[編輯添加:事實證明,答案非常無聊,與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;
喲,你說得對。多麼可怕。謝謝! – 2012-04-18 14:40:41