Reputation: 735
Why does calling SetForegroundWindow()
in multiple background threads act as if they are all foreground threads at the same time?
In my understanding, calling SetForegroundWindow()
after creating a window in a background thread will set the calling thread as the foreground thread. However, whenever another thread calls SetForegroundWindow()
, then that thread becomes the foreground thread, and the previous foreground thread returns to the background.
I've tested 3 cases by clicking the title bar of a window and dragging it.
SetForegroundWindow()
after creating each windowThe results of each cases were:
The reason why I express "as if they are all foreground threads" in my question is that case 3 should act the same as case 2 unless the clicked window is already in the foreground.
References I looked at are as follows:
[EDIT]
Here's the sample code that reproduces Case 2. If SetForegroundWindow is called for each windows in each thread, Case 3 is reproduced. Case 1 can be reproduced if SINGLETHREAD is defined.
#include <Windows.h>
HINSTANCE g_hInstance = nullptr;
HANDLE g_hEvent0 = nullptr;
HANDLE g_hEvent1 = nullptr;
//#define SINGLETHREAD
LRESULT WINAPI WndProc(HWND _hWnd, UINT _unMessage, WPARAM _wParam, LPARAM _lParam)
{
switch (_unMessage)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
default:
break;
}
return DefWindowProc(_hWnd, _unMessage, _wParam, _lParam);
}
DWORD WINAPI Thread0(LPVOID _lpParam)
{
WNDCLASSEXW stWndClassExW0
{
sizeof(WNDCLASSEXW),
CS_VREDRAW | CS_HREDRAW,
&WndProc,
0,
0,
g_hInstance,
nullptr,
static_cast<HICON__*>(LoadImageW(nullptr, static_cast<const wchar_t*>(IDC_ARROW), static_cast<unsigned int>(IMAGE_CURSOR), 0, 0, static_cast<unsigned int>(LR_SHARED))),
static_cast<HBRUSH__*>(GetStockObject(WHITE_BRUSH)),
L"MenuName",
L"ClassName0",
nullptr
};
ATOM usWindowClass0 = RegisterClassExW(&stWndClassExW0);
HWND hWnd0 = CreateWindowExW(0,
reinterpret_cast<const wchar_t*>(usWindowClass0),
L"0",
WS_OVERLAPPEDWINDOW,
0,
0,
1200,
800,
nullptr,
nullptr,
g_hInstance,
nullptr);
ShowWindow(hWnd0, SW_SHOW);
//SetForegroundWindow(hWnd0);
MSG msg{};
while (true)
{
if (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE) != 0)
{
if (msg.message == WM_QUIT)
{
break;
}
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
SetEvent(g_hEvent0);
return 0ul;
}
DWORD WINAPI Thread1(LPVOID _lpParam)
{
WNDCLASSEXW stWndClassExW1
{
sizeof(WNDCLASSEXW),
CS_VREDRAW | CS_HREDRAW,
&WndProc,
0,
0,
g_hInstance,
nullptr,
static_cast<HICON__*>(LoadImageW(nullptr, static_cast<const wchar_t*>(IDC_ARROW), static_cast<unsigned int>(IMAGE_CURSOR), 0, 0, static_cast<unsigned int>(LR_SHARED))),
static_cast<HBRUSH__*>(GetStockObject(WHITE_BRUSH)),
L"MenuName",
L"ClassName1",
nullptr
};
ATOM usWindowClass1 = RegisterClassExW(&stWndClassExW1);
HWND hWnd1 = CreateWindowExW(0,
reinterpret_cast<const wchar_t*>(usWindowClass1),
L"1",
WS_OVERLAPPEDWINDOW,
200,
200,
1200,
800,
nullptr,
nullptr,
g_hInstance,
nullptr);
ShowWindow(hWnd1, SW_SHOW);
//SetForegroundWindow(hWnd1);
MSG msg{};
while (true)
{
if (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE) != 0)
{
if (msg.message == WM_QUIT)
{
break;
}
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
SetEvent(g_hEvent1);
return 0ul;
}
int WINAPI wWinMain(_In_ HINSTANCE _hInstance,
_In_opt_ HINSTANCE _hPrevInstance,
_In_ LPWSTR _lpCmdLine,
_In_ int _nCmdShow)
{
g_hInstance = _hInstance;
#ifdef SINGLETHREAD
WNDCLASSEXW stWndClassExW0
{
sizeof(WNDCLASSEXW),
CS_VREDRAW | CS_HREDRAW,
&WndProc,
0,
0,
g_hInstance,
nullptr,
static_cast<HICON__*>(LoadImageW(nullptr, static_cast<const wchar_t*>(IDC_ARROW), static_cast<unsigned int>(IMAGE_CURSOR), 0, 0, static_cast<unsigned int>(LR_SHARED))),
static_cast<HBRUSH__*>(GetStockObject(WHITE_BRUSH)),
L"MenuName",
L"ClassName0",
nullptr
};
ATOM usWindowClass0 = RegisterClassExW(&stWndClassExW0);
HWND hWnd0 = CreateWindowExW(0,
reinterpret_cast<const wchar_t*>(usWindowClass0),
L"0",
WS_OVERLAPPEDWINDOW,
0,
0,
1200,
800,
nullptr,
nullptr,
g_hInstance,
nullptr);
ShowWindow(hWnd0, SW_SHOW);
WNDCLASSEXW stWndClassExW1
{
sizeof(WNDCLASSEXW),
CS_VREDRAW | CS_HREDRAW,
&WndProc,
0,
0,
g_hInstance,
nullptr,
static_cast<HICON__*>(LoadImageW(nullptr, static_cast<const wchar_t*>(IDC_ARROW), static_cast<unsigned int>(IMAGE_CURSOR), 0, 0, static_cast<unsigned int>(LR_SHARED))),
static_cast<HBRUSH__*>(GetStockObject(WHITE_BRUSH)),
L"MenuName",
L"ClassName1",
nullptr
};
ATOM usWindowClass1 = RegisterClassExW(&stWndClassExW1);
HWND hWnd1 = CreateWindowExW(0,
reinterpret_cast<const wchar_t*>(usWindowClass1),
L"1",
WS_OVERLAPPEDWINDOW,
200,
200,
1200,
800,
nullptr,
nullptr,
g_hInstance,
nullptr);
ShowWindow(hWnd1, SW_SHOW);
tagMSG stMSG{};
while (true)
{
if (PeekMessageW(&stMSG, nullptr, 0, 0, static_cast<unsigned int>(PM_REMOVE)) != 0)
{
if (stMSG.message == static_cast<unsigned int>(WM_QUIT))
{
break;
}
TranslateMessage(&stMSG);
DispatchMessageW(&stMSG);
}
}
#else
g_hEvent0 = CreateEvent(nullptr, 0, 0, nullptr);
g_hEvent1 = CreateEvent(nullptr, 0, 0, nullptr);
DWORD dwThreadID0 = 0ul;
DWORD dwThreadID1 = 0ul;
HANDLE hThread0 = CreateThread(nullptr, 0, &Thread0, nullptr, 0, &dwThreadID0);
HANDLE hThread1 = CreateThread(nullptr, 0, &Thread1, nullptr, 0, &dwThreadID1);
WaitForSingleObject(g_hEvent0, INFINITE);
WaitForSingleObject(g_hEvent1, INFINITE);
#endif // SINGLETHREAD
return 0;
}
Upvotes: 0
Views: 159