我的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并随后在MainWndProc中从未到达WM_DESTROY时,就好像它被卡在GetMessage或DispatchMessage或我的消息中循环,我没有在该程序中做任何花哨的事情,所以我一无所知。当我设法在调试器中完成此操作时,它最终仍在运行,但是我无法暂停它,而是一步一步查看执行的位置。
奇怪的是,虽然我已经观察不到,但是当我以控制台方式关闭它时,该窗口将消失,但是该过程将继续在后台运行,直到启动该程序的cmd窗口收到键盘输入或关闭为止。相反,在Windows模式下会发生相同的情况,但是没有cmd窗口,而是必须从任务管理器中结束它。
我对只需要一个窗口的简单Windows GUI应用程序从未遇到任何麻烦。只有在我遇到更多问题时,它才会完全关闭并且不知道如何正常退出。
您从未将condition
设置为TRUE
,不会杀死计时器。
并添加错误检查以确保窗口类注册成功并创建窗口。
下面是可以检查的工作代码:
#include <iostream>
#include <windows.h>
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";
ATOM mainAtom = RegisterClassA(&wc);
if (!mainAtom)
{
printf("error: %d\n", GetLastError());
return;
}
wc.lpfnWndProc = OwnedWndProc;
wc.lpszClassName = "OWNEDWIN";
ATOM ownAtom = RegisterClassA(&wc);
if (!ownAtom)
{
printf("error: %d\n", GetLastError());
return;
}
mainHwnd = CreateWindowExA(WS_EX_TOPMOST, "MAINWIN", "MAINWIN", WS_POPUP | WS_BORDER, 10, 10, 100, 100, 0, 0, thisMod, NULL);
if (mainHwnd == NULL)
{
printf("error: %d\n", GetLastError());
return;
}
ShowWindow(mainHwnd, SW_SHOWNORMAL);
ownedHwnd = CreateWindowExA(WS_EX_LAYERED | WS_EX_TOPMOST, "OWNEDWIN", "OWNEDWIN", WS_POPUP | WS_BORDER, 10, 130, 200, 200, mainHwnd, 0, thisMod, NULL);
if (ownedHwnd == NULL)
{
printf("error: %d\n", GetLastError());
return;
}
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) {
}
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:
condition = TRUE;
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);
}