我实际上是在尝试读取其他人隐藏的窗口上的特定像素。我想使用GDI库中的GetPixel函数,但它似乎只适用于全局设备上下文。我无法从特定窗口读取像素,我不明白为什么.. 我发现this article使用PrintWindow函数将特定窗口内容复制到可以读取的临时设备上下文。但我无法重现它。
修改
谢谢你我所有的问题都解决了:) 即使窗口被隐藏,此脚本也会为您选择的窗口提供指针的RGB颜色。提醒必须使用管理员权限启动此程序,以获取使用管理员权限启动的进程像素。
#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没有动态加载 它用
编译gcc main.c -o main.exe -lGid32 -lUser32
祝你有美好的一天!
答案 0 :(得分:4)
您正在将处理句柄传递给GetDC
。那是不对的。进程没有设备上下文,Windows也没有。记住一个进程可以有很多窗口,甚至根本没有窗口。
您需要抓住相关窗口的窗口句柄HWND
,然后将其传递给GetDC
。我希望使用FindWindow
或EnumWindows
来找到您的目标顶级窗口。
当然,您的代码可能还有其他问题,但那是跳出来的问题。
答案 1 :(得分:4)
HDC process_dc = GetDC(process_handle)
那是各种各样的错误。 GetDC
接受窗口句柄,而不是进程句柄。
要查找此类错误,请使用
重新编译#define STRICT
放在您的包含之前。
答案 2 :(得分:2)
这是一个令人困惑的主题,所以让我们看看我是否可以澄清一些事情。
首先要做的事情是:正如大卫和本已经回答的那样,你正在向GetDC
函数传递一个进程句柄,这是错误的。 GetDC
接受窗口(HWND
类型)的句柄,并返回与该窗口对应的设备上下文(DC,HDC
类型)。你需要在其他任何工作之前解决问题。
现在,正如您所阅读的文章所指出的那样,Windows(假设它们已被正确编程)通过将自己的图像渲染到指定的设备上下文来响应WM_PRINT
或WM_PRINTCLIENT
消息(HDC
)。这是一种捕获窗口“图像”的简单有效方法,无论是重叠窗口还是单个控件的窗口。
正如Hans在评论中提到的那样,因为设备上下文的句柄具有进程关联性,这意味着您在单独的进程中传递给窗口的HDC
,应该将其自身呈现的内容将不会从其他进程中生效。设备上下文的句柄不能跨进程边界传递。这是您的代码失败的主要原因(或者一旦您修复了句柄类型问题就会失败)。 MSDN entry on GDI Objects明确说明了这一点:
GDI对象的句柄对进程是私有的。也就是说,只有创建GDI对象的进程才能使用对象句柄。
修复或绕过这将是一场艰苦的战斗。我所知道的唯一解决方案是将代码注入到其他应用程序的进程中,该进程首先在内存中创建DC,然后将WM_PRINT
或WM_PRINTCLIENT
消息发送到该进程拥有的窗口以绘制到该进程中内存设备上下文,然后将生成的位图传输回您自己的应用程序。这将要求您实现某种类型的进程间通信机制。
我已经看到一些轶事证据表明通过WM_PRINT
和WM_PRINTCLIENT
消息“工作”在进程之间传递设备上下文句柄,但我不清楚这是否是当前实现的工件(因此在Windows的未来版本中会受到破坏),或者这是因为Windows实际上正在处理进程之间的编组。我没有看到任何文件的方式或方式。如果这是一个一次性的项目,你是为了娱乐或有限的使用,你可以尝试它并逃脱它。出于其他目的,您可能希望使用IPC进行调查,以正确的方式执行此操作。
答案 3 :(得分:1)
不要使用GetDC将DC传递给PrintWindow。您需要创建兼容的DC(尽管您可以将其传递给NULL以获得通用屏幕DC),然后创建与您尝试捕获的窗口大小相同的兼容位图并将其选择到DC中。然后将该DC句柄传递给PrintWindow。
Windows不需要对WM_PRINT或WM_PRINTCLIENT做出正确响应,因此即使让它工作也可能会出现一些故障。