Снимок экрана окна, исключающий определенные стили HWND (WS_SYSMENU) - PullRequest
0 голосов
/ 17 мая 2018

Я пытаюсь периодически сравнивать снимки одного и того же окна каждые несколько секунд. Несмотря на то, что технически окно не меняется, изображения остаются прежними, я все равно получаю уведомление, что с изображением что-то изменилось, я использую старую старую функцию BitBlt для захвата определенного окна. и Zlib's CRC32 для сравнения результатов.

Вот пример 2 одинаковых картинок, единственное отличие - цвет заголовка окна (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 голосов
/ 17 мая 2018

Чтобы определить клиентскую область целевого окна, вы можете отправить ему сообщение WM_NCCALCSIZE . Это должно позволить вам надежно определить размер строки заголовка для большинства приложений, например:

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

Что касается проблемы мигания каретки, вы можете попытаться запомнить контрольные суммы для последних двух различных экранов, которые вы видели. Тогда у вас есть шанс отработать, когда окно фактически переключается между двумя состояниями.

Это и более изощренная логика сравнения (например, обход списка дочерних окон для поиска элементов управления для редактирования, чтобы увидеть, ограничены ли какие-либо изменения в содержимом таких элементов управления), должны позволять достигать большинства того, что вы хотите .

...