2013-06-30 4 views
1

Я создаю модуль скриншотов, используя только чистый python (ctypes), не большой lib, такой как win32, wx, QT, ... Он должен управлять несколькими экранами (что PIL и Pillow не могут).Скриншот [ctypes.windll CreateDCFromHandle]

Где я блокируюсь при вызове CreateDCFromHandle, ctypes.windll.gdi32 не знает эту функцию. Я посмотрел на исходный код win32, чтобы быть вдохновленным, но бесполезным. Как сказано в комментарии, эта функция не существует в MSDN, поэтому какие изменения следует применять, чтобы принимать во внимание другие экраны?

Это код, который работает для основного монитора, но не для других: source code. Он блокируется на линии 35. Я пробовал много комбинаций, ища ответы здесь и на других сайтах. Но ничего функционального для меня ... Это всего лишь скриншот!

У вас есть ключи?

Заранее спасибо :)


Edit, я нашел mystake! Это код, который работает:

srcdc = ctypes.windll.user32.GetWindowDC(0) 
memdc = ctypes.windll.gdi32.CreateCompatibleDC(srcdc) 
bmp = ctypes.windll.gdi32.CreateCompatibleBitmap(srcdc, width, height) 
ctypes.windll.gdi32.SelectObject(memdc, bmp) 
ctypes.windll.gdi32.BitBlt(memdc, 0, 0, width, height, srcdc, left, top, SRCCOPY)   
bmp_header = pack('LHHHH', calcsize('LHHHH'), width, height, 1, 24) 
c_bmp_header = c_buffer(bmp_header) 
c_bits = c_buffer(' ' * (height * ((width * 3 + 3) & -4))) 
got_bits = ctypes.windll.gdi32.GetDIBits(memdc, bmp, 0, height, 
         c_bits, c_bmp_header, DIB_RGB_COLORS) 
# Here, got_bits should be equal to height to tell you all goes well. 

французская статья с полными объяснениями: Windows : capture d'écran

+0

MSDN, похоже, не знает этой функции. – icktoofay

+0

Правильно, после всех выполненных запросов эта функция всегда присутствует в источнике кода, но не в MSDN. Где я могу применить изменения, чтобы принимать во внимание другие экраны? –

+0

Хм нет, я не использую argtypes. Этот код работает с 64-битной версией Windows 7. Должен ли я использовать argtypes, если я не объявляю функции? –

ответ

0

Редактировать, я нашел мой мистик! Это код, который работает:

srcdc = ctypes.windll.user32.GetWindowDC(0) 
memdc = ctypes.windll.gdi32.CreateCompatibleDC(srcdc) 
bmp = ctypes.windll.gdi32.CreateCompatibleBitmap(srcdc, width, height) 
ctypes.windll.gdi32.SelectObject(memdc, bmp) 
ctypes.windll.gdi32.BitBlt(memdc, 0, 0, width, height, srcdc, left, top, SRCCOPY)   
bmp_header = pack('LHHHH', calcsize('LHHHH'), width, height, 1, 24) 
c_bmp_header = c_buffer(bmp_header) 
c_bits = c_buffer(' ' * (height * ((width * 3 + 3) & -4))) 
got_bits = ctypes.windll.gdi32.GetDIBits(
    memdc, bmp, 0, height, c_bits, c_bmp_header, DIB_RGB_COLORS) 
# Here, got_bits should be equal to height to tell you all goes well. 
1

Глядя на the source для pywin32, CreateDCFromHandle является выдумкой. Он не существует в Windows API; это просто мост, преобразующий предмет Windows API в вещь pywin32.

Поскольку вы используете ctypes вместо pywin32, конверсия не требуется; если вы можете пропустить этот шаг:

hwin = user.GetDesktopWindow() 
hwindc = user.GetWindowDC(monitor['hmon']) 
memdc = gdi.CreateCompatibleDC(hwindc) 

Когда вы пытаетесь сделать некоторую нативную-Windows API вещи с ctypes в Python, я считаю, это более полезно взглянуть на существующем код C, который уже использует Windows API, вместо использования кода Python, который использует обертку вокруг него.

+0

Да, я посещаю MSDN с 5 дней, но повторная передача не так хороша, как хотелось бы. Я видел, что эта функция распознается, дайте мне DC для всех мониторов: gdi32.CreateDCW ('DISPLAY', 0, 0, 0) Но результат тот же: захвачен только первичный монитор. Я продолжу расследование. –

+0

@eryksun: Правильно, но это, вероятно, не делает ничего полезного в Windows API. Он просто переносит дескриптор API Windows в другой объект. – icktoofay

+0

@eryksun: Да, я уже прочитал эту часть кода и увидел это. Я ссылался на него, но не включил его в свой ответ, потому что я не думал, что это имеет значение. Я добавлю ссылку на источник, хотя это может быть полезно для всех, кого это интересует. – icktoofay

1

Это не функция Windows API. Вам понадобится комбинация EnumDisplayDevices и CreateDC. Имейте в виду, что вы должны добавлять «A» или «W» к именам функций в зависимости от того, хотите ли вы использовать строки ANSI или строки Unicode (широкоформатные).

+0

Да, EnumDisplayDevices() возвращает координаты, ручки окон и ручки DC. Но эти значения (ручки) не работают, возможно, я неправильно понимаю, как это работает. CreateDCW ('DISPLAY', 0, 0, 0) должен создать DC для всех мониторов (как указано в MSDN), но получение пикселей со второго монитора не работает. –

+0

@ Tiger-222 Затем вы должны попытаться получить пиксели для каждого монитора отдельно –

+0

Это то, что я хочу :) Он работает для основного монитора, но не для второго. Кажется, что все работает до GetDIBits(), который не возвращает требуемое значение. Черное изображение. –

Смежные вопросы