Home > Enterprise >  BitBlt causes a glitch when called after EVENT_SYSTEM_FOREGROUND
BitBlt causes a glitch when called after EVENT_SYSTEM_FOREGROUND

Time:08-28

I need to take a screenshot of the foreground window.

To do that, I use SetWinEventHook() (listening to EVENT_SYSTEM_FOREGROUND) and BitBlt(). It's working as expected, except for newly created windows which shows up not fully rendered (transparent parts):

enter image description here

Adding a 10~50ms delay between the EVENT_SYSTEM_FOREGROUND event and BitBlt() "solves" the problem.

The issue happens randomly and only to some windows. Can someone explain what's happening and how to properly fix this?

Here's a minimal reproduceable example:

VOID CALLBACK WinEventProcCallback(HWINEVENTHOOK hWinEventHook, DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
    if (dwEvent == EVENT_SYSTEM_FOREGROUND && hwnd)
    {
        // Sleep(20); // This "solves" the issue
        HDC dcScreen = GetDC(hwnd);
        HDC dcTarget = CreateCompatibleDC(dcScreen);
        HBITMAP bmpTarget = CreateCompatibleBitmap(dcScreen, 100, 100);
        HGDIOBJ oldBmp = SelectObject(dcTarget, bmpTarget);
        BitBlt(dcTarget, 0, 0, 100, 100, dcScreen, 100, 100, SRCCOPY | CAPTUREBLT);
        SelectObject(dcTarget, oldBmp);
        DeleteDC(dcTarget);
        ReleaseDC(hwnd, dcScreen);
    }
  
}

int main()
{   
    SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, NULL, WinEventProcCallback, 0, 0, WINEVENT_OUTOFCONTEXT);

    MSG msg;
    while (GetMessageA(&msg, NULL, 0, 0)) {}

    return 0;
}

CodePudding user response:

EVENT_SYSTEM_FOREGROUND might notify from deep inside the foreground change code in the window manager and the new foreground window might still be waiting to paint by the time you BitBlt.

Call RedrawWindow(.., RDW_UPDATENOW) or UpdateWindow first to make the window paint its invalid areas.

  • Related