1

Тема: AHK: Возможно ли получить цвет пикселя неактивного окна

Окно не просто неактивное, оно или свёрнуто, или перекрыто другим окном. В нём происходит какая-то активность. Надо узнать цвет пикселей в некоторой области.
Есть команды PixelSearch и GetPixelColor, но они определяют цвет на экране вообще, без привязки к окну.
Возможно ли это в принципе?

2

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Avenger пишет:

Возможно ли это в принципе?

Тут не подскажу, а вот ежели попробовать обходной путь:

1. Запомнить текущее Foreground window.
2. Сделать нужное окно Foreground.
3. GetPixelColor.
4. Сделать запомненное окно Foreground'ом.

Или нужное окно на передний план выводить никак нельзя/невозможно/нежелательно?

3

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

alexii пишет:

Или нужное окно на передний план выводить никак нельзя/невозможно/нежелательно?

Угу, совсем никак нельзя

4

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Вообще-то, PixelGetColor...

А если через WinAPI GetPixelColor попробовать?

5

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Это как? Т.е не средствами AHK? Можно примерчик?

6

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Неа. Примерчик GetPixelColor смотри в MSDN. Из AHK вызывать через DllCall. Реально ли это сделать - я не подскажу, нужны более опытные товарищи, желательно С-шники; они проконсультируют.

7

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Не претендую на роль опытного товарища, но думаю, что это не сработает. Вот что пишет MS про GetPixel:

If the pixel is outside of the current clipping region, the return value is CLR_INVALID.

"Clipping region" - всегда в видимой части окна. Его координаты сообщаются приложению, чтобы оно могло уменьшить себе работу, ограничив вывод в окно только этой областью. Если оно этим не воспользуется, обрезку сделает Windows. Т.е. по-любому цвет в невидимой части не вычисляется и взять его негде.

Разве что вообразить себе какой-то сильно хитрый способ узнать "что тут было бы, если бы", т.е. что нарисовала бы здесь программа, если бы это место было видимым. Но это уже в саму программу влазить надо, я так понимаю.

8

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

YMP пишет:

Не претендую на роль опытного товарища

А я тем более , но вот здесь

YMP пишет:

по-любому цвет в невидимой части не вычисляется и взять его негде

по-моему неверно. Нужен DC, и от него плясать. Иначе как бы шла отрисовка в невидимых окнах? Впрочем, я только подавал идею, за реализацию не берусь. Но какой-то способ определённо существует. Другой вопрос, можно ли его привязать к AHK.

9

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

alexii пишет:

Но какой-то способ определённо существует.

Не-е, так я не играю.    Ты покажи этот способ, тогда я поверю, что он существует. Допустим, получили DC, а что дальше? Какой план действий?

10

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Знал бы - показал, а так могу только строить предположения. Не более.

11

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

2YMP: разбираясь с #2, вспомнил об этой теме. Получить цвет точки из неактивного окна, похоже, возможно (в том числе и со сдвинутым за видимые границы экрана — если потребуется как-то скрыть окно, либо перекрытым другим окном). Работа с минимизированным или скрытым окном — нет (во всяком случае, у меня с минимизированным окном срабатывало ~ 1/10 случаев, если не реже, так что я склонен считать это случайностью). На примере Paint'а и точки 300, 300; работать будет только под XP и выше; за качество кода не ручаюсь, тяжело мне AHK даётся — потратил вчетверо больше времени на перевод на AHK, нежели на написание первоначального варианта на AutoIt :

X := 300
Y := 300

SetFormat, Integer, Hex

WinGet, hWnd, ID, ahk_class MSPaintApp

hDC     := DllCall("GetDC", Int, hWnd)
hMemDC  := DllCall("CreateCompatibleDC", UInt, hDC)
WinGetPos,,, Width, Height, ahk_id %hWnd%
hBitmap := DllCall("CreateCompatibleBitmap", UInt, hDC, Int, Width, Int, Height)
DllCall("SelectObject", UInt, hMemDC, UInt, hBitmap)
DllCall("PrintWindow", UInt, hWnd, UInt, hMemDC, UInt, 0)
Color   := DllCall("GetPixel", UInt, hMemDC, UInt, X, UIint, Y)

DllCall("DeleteObject", UInt, hBitmap)
DllCall("DeleteDC", UInt, hMemDC)
DllCall("ReleaseDC", UInt, ahk_id %hWnd%, UInt, hDC)

Transform, Red,   BitAnd, Color, 0x0000FF

Transform, Green, BitAnd, Color, 0x00FF00
Transform, Green, BitShiftRight, Green, 8

Transform, Blue,  BitAnd, Color, 0xFF0000
Transform, Blue,  BitShiftRight, Blue, 16

SetFormat, Integer, D

MsgBox, Color %A_Tab% %Color%`n`nRed %A_Tab% %Red%`nGreen %A_Tab% %Green%`nBlue %A_Tab% %Blue%

Аналогичный код на AutoIt (собственно, на нём писал и затем переделывал на AHK):

#Include <WinAPI.au3>

#NoTrayIcon

AutoItSetOption("TrayIconDebug", 0)
AutoItSetOption("MustDeclareVars", 1)

AutoItSetOption("WinTitleMatchMode", 4)
AutoItSetOption("WinDetectHiddenText", 1)

Local $hWnd
Local $hDC
Local $hMemDC
Local $tRect
Local $dwWidth
Local $dwHeight
Local $hBitmap

Local $Color

Local $intX = 300
Local $intY = 300

$hWnd     = WinGetHandle("[CLASS:MSPaintApp]")

$hDC      = _WinAPI_GetDC($hWnd)
$hMemDC   = _WinAPI_CreateCompatibleDC($hDC)
$tRect    = _WinAPI_GetWindowRect($hWnd)

$dwWidth  = DllStructGetData($tRect, "Right") - DllStructGetData($tRect, "Left")
$dwHeight = DllStructGetData($tRect, "Bottom") - DllStructGetData($tRect, "Top")

$hBitmap  =_WinAPI_CreateCompatibleBitmap($hDC, $dwWidth, $dwHeight)
_WinAPI_SelectObject($hMemDC, $hBitmap)
DllCall("user32.dll", "int", "PrintWindow", "hwnd", $hWnd, "ptr", $hMemDC, "uint", 0)

$Color = DllCall("gdi32.dll", "dword", "GetPixel", "ptr", $hMemDC, "int", $intX, "int", $intY)

_WinAPI_DeleteObject($hBitmap)
_WinAPI_DeleteDC($hMemDC)
_WinAPI_ReleaseDC($hWnd, $hDC)

ConsoleWrite("The Color value is 0x" & Hex(BitOR( _
    BitShift(BitAND($Color[0], 0x000000FF),-16), _
    BitShift(BitAND($Color[0], 0x0000FF00),  0), _
    BitShift(BitAND($Color[0], 0x00FF0000), 16)), 6) _
    & @CRLF & @CRLF)

ConsoleWrite("The Red value is       0x" & Hex(BitShift(BitAND($Color[0], 0x000000FF),  0), 2) & @CRLF)
ConsoleWrite("The Green value is     0x" & Hex(BitShift(BitAND($Color[0], 0x0000FF00),  8), 2) & @CRLF)
ConsoleWrite("The Blue value is      0x" & Hex(BitShift(BitAND($Color[0], 0x00FF0000), 16), 2) & @CRLF)

Exit(0)

P.S. Я тут постфактум посмотрел — поиск на официальном форуме AutoHotKey по сочетанию «PrintWindow» за последние полгода даёт интересные результаты . Народ активно начал внедрять библиотеки функций.

12

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Да, работает, очень интересный способ. А откуда ограничение к ХР и выше? Вроде все функции доступны и в более ранних виндах.

Учитывая, что переменные в АНК хранятся как строки, можно и так извлечь отдельные цвета:

Red   := SubStr(Color, 7, 2)
Green := SubStr(Color, 5, 2)
Blue  := SubStr(Color, 3, 2)

13

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Кроме PrintWindow Function (Windows):

Requirements
Minimum supported client: Windows XP
Minimum supported server: Windows Server 2003
Header: Winuser.h (include Windows.h)
Library: User32.lib
DLL: User32.dll

Способ, конечно, весьма не скорострельный. Как думаете, можно ли извлечь из него какую-то практическую пользу?

Учитывая, что переменные в АНК хранятся как строки, можно и так извлечь отдельные цвета:

Спасибо, не знал.
OFF1: меня вначале удивил тот факт, что цвет возвращается в виде BGR.
OFF2: у меня любой скрипт будет похож на VBS .

14

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Да, я невнимательно читал. Но, кстати, есть там и вот что:

Remarks

This function is similar to WM_PRINT.

Т.е. если она просто посылает это сообщение, то можно послать его и через SendMessage, в более ранних виндах.

Насчёт WM_PRINT в MSDN так:

Minimum supported client Windows 2000 Professional
Minimum supported server Windows 2000 Server

в PSDK этак:

Requirements
  Windows NT/2000/XP: Included in Windows NT 4.0 and later.
  Windows 95/98/Me: Included in Windows 95 and later.

Но есть ещё старый Win32 Programmer's Reference, который согласен с PSDK:

WM_PRINT

Windows NT Yes
Win95 Yes

Практическая польза, наверно, возможна, но пока не знаю, какая.

15

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Я к сожалению 3/4 кода на AHK от alexii не понял, а комментариев в нём нет. Поясните где там что, хоть в общих чертах, пожалуйста!

16

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Не работает... Переменая Color пустая.... МБ кто подскажет почему ?

17

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Где и как именно «не работает»?

18

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Скопирывал код как он есть, открыл пеинт, запустил скрипт, переменая Color пустая, тоесть цвет не возвращает!

19

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Какой код из двух? Какая ОС? Какая версия AHK (если код — первый)?

20

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Первый код для AHK, Windows 7 x64, AutoHotkey_L 1.1.09.0.0 x64

21

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Всё. Теперь ждите специалистов, у которых есть и второе, и третье .

22

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Порылся в сети, нашол похожий код, но проблемма все таже!


WinGet WindowID, id, Безымянный - Paint
hdc_frame := DllCall( "GetDC", UInt, WindowID )
hdc_buffer := DllCall("gdi32.dll\CreateCompatibleDC", UInt,  hdc_frame)
hbm_buffer := DllCall("gdi32.dll\CreateCompatibleBitmap", UInt,hdc_frame, Int,A_ScreenWidth, Int,A_ScreenHeight)
DllCall( "gdi32.dll\SelectObject", UInt,hdc_buffer, UInt,hbm_buffer)
DllCall( "PrintWindow", UInt , tablelist_%a_index% , UInt , hdc_buffer , UInt , 0 ) 
getlength = 200
getheight = 100
x1 = 0
y1 = 0 
DllCall("gdi32.dll\BitBlt" , UInt,hdc_frame    , Int, 0, Int, 0, Int, getlength, Int, getheight, UInt,hdc_buffer, Int, x1, Int, y1 , UInt, 0xCC0020 )      
pixel_x = 20
pixel_y = 20
pix := DllCall("GetPixel", UInt, hdc_buffer, Int, pixel_x, Int, pixel_y)
DllCall( "gdi32.dll\DeleteObject", "uint", hbm_buffer )
DllCall( "gdi32.dll\DeleteDC" , "uint", hdc_frame )
DllCall( "gdi32.dll\DeleteDC" , "uint", hdc_buffer )
MsgBox, %pix%
ExitApp

23

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Современная версия такая:

X := 940
Y := 70

WinGet, hWnd, ID, ahk_class MSPaintApp

hDC := DllCall("GetDC", Ptr, hWnd, Ptr)
hMemDC := DllCall("CreateCompatibleDC", Ptr, hDC)
WinGetPos,,, Width, Height, ahk_id %hWnd%
hBitmap := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, Width, Int, Height, Ptr)
DllCall("SelectObject", Ptr, hMemDC, Ptr, hBitmap)
DllCall("PrintWindow", Ptr, hWnd, Ptr, hMemDC, UInt, 0)
ColorBGR := DllCall("GetPixel", Ptr, hMemDC, UInt, X, UInt, Y)

DllCall("DeleteObject", Ptr, hBitmap)
DllCall("DeleteDC", Ptr, hMemDC)
DllCall("ReleaseDC", Ptr, hWnd, Ptr, hDC)

SetFormat, IntegerFast, Hex
MsgBox, % ColorRGB := RegExReplace(ColorBGR, "(..)(..)(..)(..)", "$1$4$3$2")

Но у меня работает и вариант от alexii, если ошибки исправить:
1. в строке

Color   := DllCall("GetPixel", UInt, hMemDC, UInt, X, UIint, Y)

заменить UIint на UInt
2. в строке

DllCall("ReleaseDC", UInt, ahk_id %hWnd%, UInt, hDC)

ahk_id %hWnd% на hWnd.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

24

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

Спасибо огромное! Все работает! В который раз выручаете!

25

Re: AHK: Возможно ли получить цвет пикселя неактивного окна

teadrinker пишет:

заменить UIint на UInt

Как же оно работало-то? У меня разве что одно предположение: в оригинале было «Uint, Y», скопировав код на форум, я увидел «некрасивость», решил поправить на «UInt, Y», но поправил так, что вышло «UIint, Y» .

P.S. Красота требует жертв .