Есть ли способ использовать PrintWindow с элементом управления? (используя AutoIt)

У меня есть небольшой фрагмент скрипта, но когда я использую PrintWindow, он возвращает только черный снимок:

PrintWindow () работает нормально с дескриптором окна, но не с дескрипторами управления.

(Или есть способ захватить только нижнюю часть окна или что-то посередине без необходимости захватывать полное окно и вырезать его?)

Скрипт AutoIt:

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 ответа

Решение

У меня есть небольшой фрагмент скрипта, но когда я использую PrintWindow, он возвращает только черный снимок:

Прежде всего, я не знаю язык, который вы используете, но ваш код и вопрос достаточно ясны, чтобы я мог предложить решение.

Сразу же, мне кажется, что ваш второй параметр PrintWindow это неправильно (это HWND все же это должно быть HDC).

Во-вторых, в вашем коде есть утечки GDI, но я исправил это -> см. Мой комментарий в коде. Короче говоря, каждый раз, когда вы SelectObject что-то в контексте устройства, вы "выталкиваете" исходный объект, который "стоял там" перед этим выбором. Этот оригинальный объект должен быть сохранен и "помещен обратно". Если нет, то ваша память со временем будет исчерпана и ваше приложение будет зависать. Просто Google для "утечки GDI", и вы найдете подробное объяснение того, что я описал.

В-третьих, конечно, вы получаете черный захват, потому что ваш начальный HDC пуст -> вам нужно передать содержимое вашего memDC в hDC, Для этого вам нужно использовать функцию BitBlt. Как я уже сказал, я не знаю, на каком языке вы работаете, но я попытался дать вам псевдокод на иллюстрации ниже, чтобы вы могли понять, что делать.

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 )

Я надеюсь, что это поможет, оставьте комментарий, если у вас есть дополнительные вопросы, и я постараюсь помочь.

(Или есть способ захватить только нижнюю часть окна или что-то посередине?)

Да, но сначала мне нужно знать, работает ли вышеуказанный метод для вас. Затем оставьте комментарий, если вам все еще нужна эта вторая часть и постарается вам помочь.

С наилучшими пожеланиями и удачи!

Самый простой - сделать снимок всего окна, а затем вырезать нужную часть (например, элемент управления) изображения. Одной из причин черного изображения элемента управления через PrintWindow является CS_PARENTDC элемента управления.

Другие вопросы по тегам