我其实是试图读取被别人隐藏的窗口上的特定像素。 我想从GDI库中使用GetPixel函数,但它似乎只适用于全局设备上下文。 我无法从特定的窗口读取像素,我不明白为什么..我发现这篇文章使用PrintWindow函数将特定的窗口内容复制到可以读取的临时设备上下文中。 但我不能重现它。
编辑
谢谢大家,我的问题解决了:)
即使窗口被隐藏,该脚本也会为您提供选定窗口上指针的RGB颜色。 请注意,此程序必须以pipe理员权限启动才能获取以pipe理员权限启动的进程的像素。
#define STRICT #define WINVER 0x0501 #define _WIN32_WINNT 0x0501 // 0x0501 for PrintWindow function // You must be at least running Windows XP // See http://msdn.microsoft.com/en-us/library/6sehtctf.aspx #include <stdio.h> #include <string.h> #include <windows.h> #define WINDOW_LIST_LIMIT 32 #define WINDOW_NAME_LIMIT 1024 void FatalError(char* error) { printf("%s", error); exit(-1); } HWND window_list[WINDOW_LIST_LIMIT]; unsigned int window_list_index = 0; BOOL EnumWindowsProc(HWND window_handle, LPARAM param) { char window_title[WINDOW_NAME_LIMIT]; if(!IsWindowVisible(window_handle)) return TRUE; RECT rectangle = {0}; GetWindowRect(window_handle, &rectangle); if (IsRectEmpty(&rectangle)) return TRUE; GetWindowText(window_handle, window_title, sizeof(window_title)); if(strlen(window_title) == 0) return TRUE; if(!strcmp(window_title, "Program Manager")) return TRUE; window_list[window_list_index] = window_handle; window_list_index++; printf("%u - %s\n", window_list_index, window_title); if(window_list_index == WINDOW_LIST_LIMIT) return FALSE; return TRUE; } int main(int argc, char** argv) { unsigned int i, input; EnumWindows((WNDENUMPROC) EnumWindowsProc, (LPARAM) NULL); printf("\nChoose a window: "); scanf("%u", &input); printf("\n"); if(input > window_list_index) FatalError("Bad choice..\n"); HDC window_dc = GetWindowDC(window_list[input - 1]), global_dc = GetDC(0), temp_dc; if(!window_dc && !global_dc) FatalError("Fatal Error - Cannot get device context.\n"); POINT cursor, previous_cursor; while(1) { temp_dc = CreateCompatibleDC(window_dc); if(!temp_dc) FatalError("Fatal Error - Cannot create compatible device context.\n"); RECT window_rectangle; GetWindowRect(window_list[input - 1], &window_rectangle); HBITMAP bitmap = CreateCompatibleBitmap(window_dc, window_rectangle.right - window_rectangle.left, window_rectangle.bottom - window_rectangle.top); if (bitmap) { SelectObject(temp_dc, bitmap); PrintWindow(window_list[input - 1], temp_dc, 0); DeleteObject(bitmap); } GetCursorPos(&cursor); if(cursor.x != previous_cursor.x && cursor.y != previous_cursor.y) { COLORREF color = GetPixel(temp_dc, cursor.x - window_rectangle.left, cursor.y - window_rectangle.top); int red = GetRValue(color); int green = GetGValue(color); int blue = GetBValue(color); printf("\rRGB %02X%02X%02X", red, green, blue); cursor = previous_cursor; } DeleteDC(temp_dc); Sleep(50); // for lags } ReleaseDC(window_list[input - 1], window_dc); return 0; }
我已经改变了一些东西,现在User32不是dynamic加载的。
它编译
gcc main.c -o main.exe -lGid32 -lUser32
祝你有美好的一天 !
您正在将进程句柄传递给GetDC
。 那是不对的。 进程没有设备上下文,窗口。 记住一个进程可以有很多窗口,甚至没有。
您需要获取窗口句柄HWND
,并将其传递给GetDC
。 我期待使用FindWindow
或EnumWindows
来查找您的目标顶级窗口。
当然,你的代码可能还有其他的问题,但那是跳到我身上的那个。
HDC process_dc = GetDC(process_handle)
那么这是各种各样的错误。 GetDC
接受一个窗口句柄,而不是一个进程句柄。
为了找到这样的错误,重新编译
#define STRICT
放在你的包括之前。
这是一个令人困惑的话题,所以让我们看看我能否澄清一些事情。
首先要做的事情是,因为David和Ben都已经回答了,所以你正在向GetDC
函数传递一个进程句柄,这是错误的。 GetDC
接受窗口 HWND
( HWND
类型),并返回与该窗口相对应的设备上下文(DC, HDC
类型)。 你需要在任何其他工作之前弄清楚这个问题。
现在,正如你读过的文章所指出的那样,windows(假设它们已被正确编程)通过将自己的图像渲染到指定的设备上下文( HDC
)中来响应WM_PRINT
或WM_PRINTCLIENT
消息。 这是捕捉窗口的“图像”的简单而有效的方式,无论是重叠窗口还是单个控件的窗口。
正如汉斯在评论中提到的那样,由于句柄对设备上下文具有进程关联性 ,这意味着你在一个单独的进程中传递给窗口的HDC
应该是自己渲染的,那另一个过程。 处理设备上下文无法通过进程边界传递。 这是你的代码失败的主要原因(或者一旦你解决了句柄类型问题,将会失败)。 GDI对象上的MSDN条目明确地表明了这一点:
处理GDI对象对于一个进程来说是私有的。 也就是说,只有创建GDI对象的进程才能使用对象句柄。
固定或者绕过这将是一场艰苦的战斗。 我所知道的唯一解决方案是将代码注入到其他应用程序的进程中,首先在内存中创建一个DC,然后将WM_PRINT
或WM_PRINTCLIENT
消息发送到该进程拥有的窗口,以便绘制到内存中的设备上下文中将结果位图传回给您自己的应用程序。 这将要求您实施某种类型的进程间通信机制。
我已经看到一些传闻证据表明,通过WM_PRINT
和WM_PRINTCLIENT
消息“工作”在进程之间传递设备上下文句柄,但是我不清楚这是否是当前实现的人为因素(因此在未来版本的Windows中可能会打破) ,或者如果这是因为Windows实际上处理进程之间的编组。 我还没有看到任何文件的方式或其他。 如果这是一个为了娱乐或有限使用而进行的一次性项目,那么您可以尝试一下并放弃它。 为了其他目的,您可能希望使用IPC进行调查,确实以正确的方式做到这一点。
不要使用GetDC将DC传递给PrintWindow。 你需要创建一个兼容的DC(虽然你可以通过NULL来获得一个普通的屏幕DC),然后创建一个兼容的位图,这个窗口的尺寸是你要捕获的窗口的大小,并将其选择到DC中。 然后将该DC处理传递给PrintWindow。
Windows不需要正确响应WM_PRINT或WM_PRINTCLIENT,所以可能会有一些小故障,即使你得到这个工作。