AutoIt PixelGetColor from background/inactive/unfo

2019-07-20 17:42发布

PixelGetColor has an optional parameter hwnd (handle of window the pixel is read from). Therefore I assume it is possible to read from unfocused windows (i.e not minimized, but behind another window); but I can't get it to work like that.

  • Is my assumption wrong? If not, how would this be done? If so;

    • why the hwnd parameter?
    • is there another method involving pixel recognition?

1条回答
走好不送
2楼-- · 2019-07-20 17:56

Abstract

You want to create a simple empty bitmap and transfer the DeviceContext content of the hidden window into it. Then you can read any value at any position.

Creating an empty bitmap

Includes

We will need to include the WinAPI definitions and constants.

#include <WinAPI.au3>
#include <WindowsConstants.au3>

And that's about it.

Initial struct

Now we have to create a new DLL struct from the $tagBITMAPINFO template. We need to fill the struct with the bitmaps parameters. To ensure compatibility across all AutoIt version, I will access the struct items by index.

1) Create compatible Device Context:

Local $hCompDC = _WinAPI_CreateCompatibleDC(0)

2) Create struct from template, fill with data:

Local $tBMI = DllStructCreate($tagBITMAPINFO)
DllStructSetData($tBMI, 1, DllStructGetSize($tBMI) - 4) ; size of struct
DllStructSetData($tBMI, 2, 400) ; width
DllStructSetData($tBMI, 3, 400) ; height
DllStructSetData($tBMI, 4, 1)
DllStructSetData($tBMI, 5, 32)  ; bits per pixel

You need to adjust the width and height parameters to match the region you want to transfer. In your case, I guess the size of the window would be a good choice, though the smaller the region, the faster.

3) Create GDI Object

Create a CreateDIBSection and save the important variables (object handle and struct pointer):

$aDIB = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
$hGDIObj = $aDIB[0]
$hPtr = $aDIB[4]

4) Activate

Select the object to use it:

_WinAPI_SelectObject($hCompDC, $hGDIObj)

5) Create a pixel-map

This is a dword-array of color values. Replace 160000 with width*height of your region:

$hPixelStruct = DllStructCreate("dword[160000]", $hPtr)

Capture window

Now we need to transfer the hidden window DeviceContext into our "virtual" context, but first the DC of the target (I'm using Paint as an example):

$hWnd = WinGetHandle("Paint")
$hWndDC = _WinAPI_GetDC($hWnd)

Let's transfer the DC into our DC, using PrintWindow:

Local $iX = 20 ; x coord of pixel in window DC (incl. title bar)
Local $iY = 20 ; y coord
DllCall("User32.dll", "int", "PrintWindow", "hwnd", $hWnd, "ptr", $hCompDC, "int", 0)

Reading single pixels

Since $hPixelStruct is a continuous stream of values, we have to do a little bit of math to point at the right pixel:

$iColor = MsgBox(0, "Color", '0x' & Hex(DllStructGetData($hPixelStruct, 1, $iY * 400 + $iX + 1), 6))

Cleaning up

Lastly, destroy the resources:

_WinAPI_ReleaseDC(0, $hCompDC)
_WinAPI_ReleaseDC($hWnd, $hWndDC)

Results

Works perfectly. Though this is only valid for hidden windows, NOT minimized, as minimized windows do not have any drawn context.

screenshot

Script

Here's a Gist containing the script: minxomat/readcolor.au3

查看更多
登录 后发表回答