Gareth McCaughan
Gareth McCaughan

Reputation: 19981

Win32 application exits immediately when dialog box is closed

[EDITED to add: It turns out that the answer is very boring and has nothing to do with Win32, dialog boxes, etc. I just had an idiotic bug in my code. Thanks to Hans Passant for spotting it.]

(This is kinda long. Executive summary: I have a simple Win32 application which creates an icon in the notification area, never shows its main window, and has an "about" box that can be displayed via a right-click on the notification-area icon. For no reason I can fathom, when the "about" box is shown and then closed, the application's main message loop gets a quit message and it exits. What could I have done wrong to cause this?)


I'm writing a little program that sits in the notification area ("system tray") and does various not-relevant-here bits of processing in the background. Its UI is almost trivial: you can right-click on the notification-area icon to get a menu, with options "Exit" and "About"; the former quits, the latter pops up a little about-this-program modal dialog.

The application is written in C++ and uses Win32 directly (no MFC or anything). My apologies for being stuck in the stone age.

The only problem is this: when the "About" dialog is closed, the program exits! What could be causing this?

I'm not sure what further information is most useful in figuring this out. Here are a few observations.


Perhaps there's something crazy, or something missing, in my code. Here are some extracts (with a few details, which may not be relevant, elided for brevity).

The rough structure of my WinMain is as follows:

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;

The main window's WndProc looks like this:

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;

and the dialog box's proc looks like this:

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;

Upvotes: 4

Views: 2393

Answers (1)

Hans Passant
Hans Passant

Reputation: 942257

There's a bug in your WndProc() function. The WM_COMMAND case is missing a break. So when it executes, say, IDM_ABOUT then it falls through into the WM_DESTROY case. Sayonara.

I recommend PC-lint.

Upvotes: 4

Related Questions