Is there a way to use PrintWindow with a control? (using AutoIt)

990 views Asked by At

I have this little piece of script but when I use PrintWindow it's only returning a black capture:

PrintWindow() is working fine with a window handle but it's not with control handles.

(Or is there a way to capture only the bottom part of the window or something in the middle without the need to capture the full window and cutting it?)

AutoIt script:

Local $hWnd = ControlGetHandle("[CLASS:Notepad]","","Edit1")
Local $pos = ControlGetPos($hWnd,"","")
;MsgBox($MB_OK, "OK", $pos[0])
Local $Width = $pos[2]
Local $Height = $pos[3]

Local $hDC = _WinAPI_GetDC($hWnd)
Local $memDC = _WinAPI_CreateCompatibleDC($hDC)
Local $memBmp = _WinAPI_CreateCompatibleBitmap($hDC, $Width, $Height)
_WinAPI_SelectObject ($memDC, $memBmp)
;DllCall("User32.dll","int","PrintWindow","hwnd",$hWnd,"hwnd",$memDC,"int",0)
;_WinAPI_BitBlt($hDC, 0, 0, $Width, $Height, $memDC, 0,0, $SRCCOPY)
_WinAPI_BitBlt($memDC, 0, 0, $Width, $Height, $hDC, 0,0, $SRCCOPY) ;this is working now!

_GDIPlus_Startup()
Local $hBMP=_GDIPlus_BitmapCreateFromHBITMAP($memBmp)
Local $hHBITMAP=_GDIPlus_BitmapCreateHBITMAPFromBitmap($hBMP)

_WinAPI_DeleteObject($hDC)
_WinAPI_ReleaseDC($hWnd, $hDC)
_WinAPI_DeleteDC($memDC)
_WinAPI_DeleteObject ($memBmp)
_WinAPI_DeleteDC($hDC)

$sPath = @ScriptDir & '\capture.bmp'
_WinAPI_SaveHBITMAPToFile($sPath, $hHBITMAP)
2

There are 2 answers

10
AlwaysLearningNewStuff On BEST ANSWER

I have this little piece of script but when I use PrintWindow it's only returning a black capture:

First of all, I do not know the language you use, but your code and question is clear enough for me to try to offer the solution.

Right off the bat, it seems to me that your second parameter to PrintWindow is wrong ( it is HWND yet it should be HDC ).

Second, you have GDI leaks in your code, but I have corrected it -> see my comment in the code. Long story short, each time you SelectObject something into device context, you "push out" original object that "stood there" before that select. That original object must be saved and "placed back". If not, then your memory will be exhausted over time and your application will freeze. Just Google for "GDI leaks" and you will find a detailed explanation of what I have described.

Third, of course you get black capture because your initial HDC is empty -> you need to transfer the content of your memDC into hDC. To do that you need to use BitBlt function. As I have said, I don't know the language you work in but I have tried to give you pseudo code in the illustration below so you can have some clue of what to do.

Local $hWnd = ControlGetHandle("[CLASS:Notepad]","","Edit1")
Local $pos = ControlGetPos($hWnd,"","")
;MsgBox($MB_OK, "OK", $pos[0])
Local $Width = $pos[2]
Local $Height = $pos[3]

Local $hDC = _WinAPI_GetDC($hWnd)
Local $memDC = _WinAPI_CreateCompatibleDC($hDC)
Local $memBmp = _WinAPI_CreateCompatibleBitmap($hDC, $Width, $Height)

Local $bmpOriginal = _WinAPI_SelectObject ($memDC, $memBmp)  ;store original DC bitmap 

DllCall("User32.dll","int","PrintWindow","hwnd",$hWnd,
    "hdc",  ; I think this is an error, this parameter is of type HDC
    $memDC,"int",0)

DllCall("User32.dll","int","BitBlt", "hdc", memDC, 
    ... , ; fill in the rest of parameters
    "hdc" , hDC, 
    ... ) ; fill in the rest of parameters. Your last parameter should be SRCCOPY!

; when done with the DC, first select back the original bitmap
_WinAPI_SelectObject( $memDC, $bmpOriginal ) 
; now we can delete memory bitmap since it is no longer needed
_WinAPI_DeleteObject( $memBmp )
; delete memory DC since we performed proper cleanup
_WinAPI_DeleteDC( $memDC )
; release window's DC
_WinAPI_ReleaseDC( $hwnd, $hDC )

I hope this helps, leave a comment if you have further questions and I will try to help.

(Or is there a way to capture only the bottom part of the window or something in the middle?)

Yes, but first I need to know if the above method works for you. Then leave a comment if you still need to this second part and will try to help you.

Best regards and good luck!

2
kero On

Easiest - take a snapshot of the entire window and then cut out the desired portion (e.g. control) of the image. One of the reason for the black image of the control via PrintWindow is CS_PARENTDC of the control.