如何优雅地关闭这个简单的 Windows GUI 程序?因为它不(有时)
How to gracefully close this simple Windows GUI program? Because it doesn't (sometimes)
我的 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);
}
当它确实挂起时,它似乎总是在计时器已经被禁用并且拥有的 window 已经关闭之后发生。从未。无论是在控制台模式还是 windows 模式,它总是一样的,总是在这两种情况发生之后我尝试关闭 window.
使用 printf 语句(因为我不完全确定如何调试它)我注意到当它冻结时 WM_CLOSE 并且随后 WM_DESTROY 从未在 MainWndProc 中达到,就好像它是卡在 GetMessage 或 DispatchMessage 或我的消息循环的某个深处,我没有在这个程序中做任何花哨的事情,所以我不知道。当我设法在调试器中实现这一点时,它最终仍然 运行ning 但我无法暂停它并逐步查看它正在执行的位置。
奇怪的是,尽管我不再观察到,当我在控制台模式下关闭它时,window 会消失,但进程会在后台继续 运行,直到 cmd window 我从中启动的程序接收到键盘输入或关闭。相反,在 windows 模式下会发生同样的情况,但不会有 cmd window,而是必须从任务管理器中结束它。
我从来没有遇到过只需要一个 window 的简单 Windows GUI 应用程序的问题。只有当有更多的时候,我才 运行 陷入这个永远不会完全关闭并且不知道如何优雅退出的问题。
Welp 结果是使用 WinMain
而不是 main
,并且没有将其指定为入口点(因此 C 运行-time 库被正确初始化)解决了它.就这样。我仍然无法完全理解它。
在我发现这一点之前,我注意到在调试器中,当程序脱离消息循环并退出时,仍有许多线程 运行ning。奇怪的是我从来没有创建任何线程...
不幸的是,我不知道是什么让我尝试 WinMain
,因为那时我一直在控制台和 windows 模式下疯狂地尝试不同的配置,直到我到达那个成功了。
我的 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);
}
当它确实挂起时,它似乎总是在计时器已经被禁用并且拥有的 window 已经关闭之后发生。从未。无论是在控制台模式还是 windows 模式,它总是一样的,总是在这两种情况发生之后我尝试关闭 window.
使用 printf 语句(因为我不完全确定如何调试它)我注意到当它冻结时 WM_CLOSE 并且随后 WM_DESTROY 从未在 MainWndProc 中达到,就好像它是卡在 GetMessage 或 DispatchMessage 或我的消息循环的某个深处,我没有在这个程序中做任何花哨的事情,所以我不知道。当我设法在调试器中实现这一点时,它最终仍然 运行ning 但我无法暂停它并逐步查看它正在执行的位置。
奇怪的是,尽管我不再观察到,当我在控制台模式下关闭它时,window 会消失,但进程会在后台继续 运行,直到 cmd window 我从中启动的程序接收到键盘输入或关闭。相反,在 windows 模式下会发生同样的情况,但不会有 cmd window,而是必须从任务管理器中结束它。
我从来没有遇到过只需要一个 window 的简单 Windows GUI 应用程序的问题。只有当有更多的时候,我才 运行 陷入这个永远不会完全关闭并且不知道如何优雅退出的问题。
Welp 结果是使用 WinMain
而不是 main
,并且没有将其指定为入口点(因此 C 运行-time 库被正确初始化)解决了它.就这样。我仍然无法完全理解它。
在我发现这一点之前,我注意到在调试器中,当程序脱离消息循环并退出时,仍有许多线程 运行ning。奇怪的是我从来没有创建任何线程...
不幸的是,我不知道是什么让我尝试 WinMain
,因为那时我一直在控制台和 windows 模式下疯狂地尝试不同的配置,直到我到达那个成功了。