Search code examples
pythonctypespython-mss

Screenshot [ctypes.windll CreateDCFromHandle]


I am creating a screenshot module using only pure python (ctypes), no big lib like win32, wx, QT, ... It has to manage multi-screens (what PIL and Pillow cannot).

Where I am blocking is when calling CreateDCFromHandle, ctypes.windll.gdi32 does not know this function. I looked at win32 source code to being inspired, but useless. As said in comment, this function does not exist in the MSDN, so what changes should I apply to take in consideration other screens?

This is the code which works for the primary monitor, but not for others: source code. It is blocking at the line 35. I tried a lot of combinations, looking for answers here and on others websites. But nothing functional for me ... It is just a screenshot!

Do you have clues?

Thanks in advance :)


Edit, I found my mystake! This is the code that works:

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.

French article with full explanations : Windows : capture d'écran


Solution

  • Edit, I found my mystake! This is the code that works:

    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.