У меня проблема с моим Windows приложением, когда при закрытии его с панели задач или с помощью горячей клавиши оно иногда зависает. Мне интересно, как изящно выйти из следующей программы:
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK OwnedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static HWND mainHwnd;
static HWND ownedHwnd;
void create_windows()
{
HMODULE thisMod = GetModuleHandleA(NULL);
WNDCLASSA wc;
wc.style = CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = thisMod;
wc.hIcon = 0;
wc.hCursor = 0;
wc.hbrBackground = 0;
wc.lpszMenuName = NULL;
wc.lpszClassName = "MAINWIN";
RegisterClassA(&wc);
wc.lpfnWndProc = OwnedWndProc;
wc.lpszClassName = "OWNEDWIN";
RegisterClassA(&wc);
mainHwnd = CreateWindowExA(WS_EX_TOPMOST, "MAINWIN", "MAINWIN", WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), 0, 0, thisMod, NULL);
ShowWindow(mainHwnd, SW_SHOWNORMAL);
ownedHwnd = CreateWindowExA(WS_EX_LAYERED | WS_EX_TOPMOST, "OWNEDWIN", "OWNEDWIN", WS_POPUP, 0, 0, 200, 200, mainHwnd, 0, thisMod, NULL);
ShowWindow(ownedHwnd, SW_SHOWNORMAL);
}
int main(int argc, char **argv)
{
if (!RegisterHotKey(NULL, 1, MOD_NOREPEAT, VK_ESCAPE)) {
return 0;
}
create_windows();
BOOL bRet;
MSG msg;
while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1) {
/* I'm never reached */
} else if (msg.message == WM_HOTKEY) {
UnregisterHotKey(NULL, 1);
PostMessageA(mainHwnd, WM_CLOSE, 0, 0);
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
/* Do a bit of cleanup */
return 0;
}
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static BOOL condition = FALSE;
switch (uMsg) {
case WM_CREATE:
SetTimer(hwnd, 1, 20, NULL);
return 0;
case WM_TIMER:
if (condition) {
KillTimer(hwnd, 1);
PostMessageA(ownedHwnd, WM_CLOSE, 0, 0);
} else {
/* Do processing here on both windows. The condition variable is
updated in here after the program does its thing. */
}
return 0;
case WM_CLOSE:
DestroyWindow(hwnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProcA(hwnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK OwnedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
/* Letting DefWindowProcA handle everything since I don't need this window to
do anything but close afterwards. */
return DefWindowProcA(hwnd, uMsg, wParam, lParam);
}
Когда он действительно зависает, это всегда происходит после того, как таймер уже отключен и закрытое окно закрыто. Никогда раньше. В режиме консоли или в режиме windows всегда одно и то же, всегда после того, как эти две вещи происходят, и я пытаюсь закрыть окно.
С операторами printf (потому что я не совсем уверен, как это отладить) Я заметил, что когда он замораживает WM_CLOSE и впоследствии WM_DESTROY никогда не достигается в MainWndPro c, как будто он застрял где-то глубоко в GetMessage или DispatchMessage, или мое сообщение l oop, я не делаю ничего фантастического в этой программе поэтому я понятия не имею. Когда мне удается сделать это в отладчике, он все равно работает, но я не могу приостановить его и посмотреть, где он выполняется.
Странно, хотя я больше не наблюдал, когда я закрывал его в консольном режиме, окно исчезало, но процесс продолжал выполняться в фоновом режиме, пока окно cmd, из которого я запускал программу, не получило ввод с клавиатуры или не закрылось. И наоборот, в режиме windows происходит то же самое, но окна cmd не будет, вместо этого придется завершать его из диспетчера задач.
У меня никогда не было проблем с простым Windows GUI приложения, где требуется только одно окно. Только когда я сталкиваюсь с этой проблемой, я больше никогда не закрываюсь и не знаю, как изящно выйти.