调用GetPixel获取指定窗口像素返回错误RGB值如何修复
问题原因
- 未做DPI适配:如果系统开启了DPI缩放且程序未声明高DPI感知,
ScreenToClient转换得到的客户区坐标会出现偏移,导致取色位置错误 - 窗口DC取色有局限:
GetDC(hWND)获取的窗口DC仅能拿到窗口未被遮挡区域的正确颜色,对应位置被遮挡时GetPixel会返回CLR_INVALID(值为0xFFFFFFFF),得到错误的255,255,255结果 - 重复查找窗口:把
FindWindow放在死循环内部每次执行都重复查找,属于无意义性能损耗
修复方案
首先给程序添加高DPI感知声明,MSVC编译器下可以直接在代码开头加以下pragma指令:
// 声明高DPI感知,避免坐标转换偏移 #pragma comment(linker, "/DPIAWARE")
也可以在项目属性的manifest设置里手动开启高DPI感知。
如果仅需要获取窗口可见区域的颜色,推荐直接用屏幕DC取色,规避窗口DC的遮挡问题,修复后的完整代码如下:
#include <iostream> #include <Windows.h> using namespace std; #pragma comment(linker, "/DPIAWARE") int main2() { POINT screenPos; int R, G, B; LPCWSTR window_title = L"HxD"; // 窗口只查找一次,找不到就循环等待 HWND hWND = FindWindow(NULL, window_title); while (!hWND) { cout << "not found window" << endl; Sleep(1000); hWND = FindWindow(NULL, window_title); } // 全局屏幕DC只需要获取一次,不用每次循环创建释放 HDC hScreenDC = GetDC(NULL); while (1) { GetCursorPos(&screenPos); // 转换为窗口客户区坐标,同时判断鼠标是否在窗口内 POINT clientPos = screenPos; ScreenToClient(hWND, &clientPos); RECT clientRect; GetClientRect(hWND, &clientRect); if (clientPos.x < 0 || clientPos.y < 0 || clientPos.x >= clientRect.right || clientPos.y >= clientRect.bottom) { cout << "鼠标不在HxD窗口客户区内" << endl; Sleep(1000); continue; } // 直接用屏幕DC取色,和main1逻辑一致,结果准确 COLORREF color = GetPixel(hScreenDC, screenPos.x, screenPos.y); if (color == CLR_INVALID) { cout << "取色失败" << endl; Sleep(1000); continue; } R = GetRValue(color); G = GetGValue(color); B = GetBValue(color); cout << "窗口内坐标 x : " << clientPos.x << ", y : " << clientPos.y << ", R : " << R << ", G : " << G << ", B : " << B << endl; Sleep(1000); } // 正常退出前释放资源,示例代码正常运行不会走到这里 ReleaseDC(NULL, hScreenDC); return 0; }
如果需要获取窗口被遮挡区域的颜色,可以用PrintWindow把窗口内容绘制到内存DC再取色,对应替换取色部分逻辑即可:
// 被遮挡区域取色逻辑示例 HDC hWindowDC = GetDC(hWND); HDC hMemDC = CreateCompatibleDC(hWindowDC); RECT winRect; GetClientRect(hWND, &winRect); HBITMAP hBmp = CreateCompatibleBitmap(hWindowDC, winRect.right, winRect.bottom); SelectObject(hMemDC, hBmp); // 仅绘制窗口客户区内容 PrintWindow(hWND, hMemDC, PW_CLIENTONLY); COLORREF color = GetPixel(hMemDC, clientPos.x, clientPos.y); // 用完释放资源 DeleteObject(hBmp); DeleteDC(hMemDC); ReleaseDC(hWND, hWindowDC);
内容的提问来源于stack exchange,提问作者minhtungph
相关产品推荐
相关产品推荐

