捕获窗口的屏幕截图,不包括某些HWND的样式(WS_SYSMENU)

时间:2018-05-16 22:02:42

标签: c++ winapi gdi+

我正在尝试每隔几秒钟定期比较同一窗口的快照。即使技术上窗口没有改变,图片仍然是相同的,我仍然得到通知,图片中的某些内容已经改变,我正在使用良好的旧BitBlt功能来捕获特定的窗口。和Zlib's CRC32比较结果。

以下是2张相同图片的示例,唯一的区别是windows的标题(untitled paint)颜色。只要窗口有焦点,它就是黑色,否则是灰色。由于我不是HWND的所有者,有没有更好的方法来拍照而不计算窗口的实际大小减去GetSystemMetrices(SM_CYSIZEFRAME / SM_CXSIZE)而不是改变样式。

我的代码:

WINDOWPLACEMENT rect;
    ::GetWindowPlacement(windowDesc.hWnd, &rect);
    if (SW_SHOWMINIMIZED == rect.showCmd)
    {
        return;
    }

    CImage img;
    img.Create(
        rect.rcNormalPosition.right - rect.rcNormalPosition.left,
        rect.rcNormalPosition.bottom - rect.rcNormalPosition.top, 
        32);

    HWND hWnd = windowDesc.hWnd;
    std::shared_ptr<HDC__> spSrcHdc(::GetDC(hWnd), [hWnd](HDC hdc) {::ReleaseDC(hWnd, hdc); });
    //::BitBlt(img.GetDC(), 0, 0, img.GetWidth(), img.GetHeight(), spSrcHdc.get(), 0, 0, SRCCOPY);
    ::PrintWindow(hWnd, img.GetDC(), 0x2);
    BITMAP bmp = { 0 };
    if (!::GetObject((HBITMAP)img, sizeof(BITMAP), &bmp))
    {
        throw std::exception("Failed to retrieve raw bmp buffer");
    }

    unsigned long ulbmpCRC = crc32(0, 
        (BYTE*)bmp.bmBits, bmp.bmWidthBytes * bmp.bmHeight);

    if (0 != ulbmpCRC && ulbmpCRC == windowDesc.crc)
    {
    }

enter image description here enter image description here

我无法解决的另一个问题是文本框存在的时候。事实上,我有光标闪烁,它生成不同的CRC32值。再一次,我可以使用BitBlt忽略这种现象的能力吗?

1 个答案:

答案 0 :(得分:1)

要确定目标窗口的客户端区域,您可以向其发送WM_NCCALCSIZE消息。这使您可以为大多数应用程序可靠地确定标题栏的大小,如:

RECT r;
GetWindowRect (hTargetWnd, &r);
SendMessage (hTargetWnd, WM_NCCALCSIZE, FALSE, (LPARAM) &r);

对于闪烁的插入符问题,您可以尝试记住您看到的最后两个不同屏幕的校验和。那么当窗口实际上在两个状态之间来回切换时,你有机会解决问题。

那,以及更复杂的比较逻辑(例如遍历子窗口列表以查找编辑控件以查看是否有任何更改仅限于此类控件的内容),应该可以实现您想要的大部分内容