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):
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.