Win32应用程序在关闭对话框时立即退出

问题描述:

[编辑添加:事实证明,答案非常无聊,与Win32,对话框等无关。我只是在我的代码中有一个白痴错误。感谢Hans Passant发现它。]Win32应用程序在关闭对话框时立即退出

(这是有点长。内容提要:我有一个简单的Win32应用程序,在通知区域创建一个图标,从不显示其主窗口,并有一个“约”框这可以通过右键单击通知区域图标来显示,因为我无法理解,当“about”框显示然后关闭时,应用程序的主消息循环会收到退出消息并退出。我做了错误的原因?)


我正在写一个小程序,在通知区域位于(“系统托盘”),并做处理各种不相关的,在此位的背景。它的UI几乎是微不足道的:您可以右键单击通知区域图标以获取菜单,并具有“退出”和“关于”选项;前者退出,后者弹出一个关于这个程序的模态对话框。

该应用程序是用C++编写的,并直接使用Win32(没有MFC或任何东西)。我被困在石器时代的道歉。

唯一的问题是:当“关于”对话框关闭时,程序退出!什么可能导致这种情况?

我不确定进一步的信息是最有用的解决这个问题。这里有几点意见。

  • 单击对话框的“确定”按钮后,应用程序生命周期结束时的Windows消息序列如下。
    • 对话框的proc获取WM_CTLCOLORBTN
    • 应用程序的(不可见的)主窗口获取WM_ENABLE(TRUE)。
    • 对话框获取WM_CTLCOLORBTN,WM_IMESETCONTEXT,WM_SETFOCUS,WM_WINDOWPOSCHANGING,WM_WINDOWPOSCHANGED,3xWM_GETICON,WM_NCACTIVATE,2xWM_GETICON,WM_ACTIVATE,WM_WINDOWPOSCHANGING。
    • 应用程序的窗口ges WM_WINDOWPOSCHANGING,WM_NCACTIVATE,消息0x93,0x93,0x91,0x92,0x92(这些是什么?),WM_ACTIVATE。
    • 对话框获取WM_KILLFOCUS,WM_IME_SETCONTEXT。
    • 应用程序窗口获取WM_IME_SETCONTEXT。
    • 对话框获取WM_IME_NOTIFY;应用程序的主窗口也是如此。
    • 应用程序窗口获取WM_SETFOCUS。
    • 对话框获取消息0x90,WM_DESTROY,WM_NCDESTROY。
  • 在对话框窗口的proc或主应用程序窗口之后没有进一步的消息。
  • 然后,GetMessage在主消息循环中返回0(消息是WM_QUIT),并且全部结束。
  • 在我的代码中对PostQuitMessage的唯一调用是在主窗口的WndProc中,它在主窗口获取WM_DESTROY时发生,并且在此场景中实际上不会调用它。

也许有一些疯狂,或者缺少什么,在我的代码。以下是一些摘录(带有一些细节,这些细节可能不相关,为简洁起见不予考虑)。

我的WinMain的大致结构如下:

WNDCLASSEX wc; 
// fill in fields of wc 
RegisterClassEx(&wc); 

HWND w = CreateWindow(...); 

NOTIFYICONDATA nid; 
memset(&nid, 0, sizeof(nid)); 
// fill in fields of nid 
Shell_NotifyIcon(NIM_ADD, &nid); 

// (start a background thread to do the real work, 
// which is of no interest here) 

MSG msg; 
while (GetMessage(&msg, NULL, 0, 0)) { 
    if (TranslateAccelerator(msg,hwnd, accel, &msg)) continue; 
    TranslateMesage(&msg); 
    DispatchMessage(&msg); 
} 

Shell_NotifyIcon(NUM_DELETE, &nid); 
return (int)msg.wParam; 

主窗口的WndProc是这样的:

switch (message) { 
    case WM_USER_SHELLICON: // my own, attached to the icon's menu 
    if (LOWORD(lParam) == WM_RBUTTONDOWN) // ... create menu and return TRUE 
    break; 
    case WM_COMMAND: 
    // menu item 
    switch (LOWORD(wParam)) { 
     case IDM_ABOUT: 
     DialogBox(the_instance, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, AboutProc); 
     break; 
     case IDM_EXIT: 
     DestroyWindow(hWnd); 
     break; 
     default: return DefWindowProc(hWnd, message, wParam, lParam); 
    } 
    case WM_DESTROY: 
    PostQuitMessage(0); 
    break; 
    default: return DefWindowProc(hWnd, message, wParam, lParam); 
} 
return 0; 

和对话框的PRoC看起来是这样的:

switch (message) { 
    case WM_INITDIALOG: 
    // fill in a version string 
    return (INT_PTR)TRUE; 
    case WM_COMMAND: 
    if (LOWORD(wParam)==IDOK || LOWORD(wParam)==IDCANCEL) { 
     EndDialog(hDlg, LOWORD(wParam)); 
     return (INT_PTR)TRUE; 
    } 
    break; 
} 
return (INT_PTR)FALSE; 

WndProc()函数存在一个错误。 WM_COMMAND案例缺少一个中断。所以,当它执行时,比如说IDM_ABOUT,它会进入WM_DESTROY的情况。再见。

我推荐PC-lint。

+0

哟,你说得对。多么可怕。谢谢! – 2012-04-18 14:40:41