Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MessageBox with timeout OR Closing a MessageBox from another thread

If my application crashes, I use an ExceptionFilter to catch the crash, perform some final actions, then show a message box to the user that the application has crashed.

Because the application already crashed, there's not much I can (or I dare) to do, because if I do too much, the executed code might access corrupted memory and crash again. Some of the things I currently can't do (or I don't dare to do) is to close network connections, Oracle database sessions, ...

Problem is that if an application crashes, and the user is out to lunch while the MessageBox is open, other users might be blocked, because of the open database session. Therefore I want:

  • Either a MessageBox with a time-out. Problem is that you can't do this with the standard MessageBox Win32 API function, and I don't want to make a specific dialog for it (because I want to minimize the executed logic after the crash)
  • Or the possibility to close the MessageBox from another thread (the other thread can provide the time-out logic).

Did I overlook something in the Win32 API and is there a possibility to have a MessageBox with a time-out?

Or what is the correct way to close an open MessageBox from another thread (how to get the MessageBox handle, how to close it, ...)?

like image 211
Patrick Avatar asked Jun 22 '10 08:06

Patrick


7 Answers

While I agree that spawning a new process to display a fire-and-forget dialog is probably best, FWIW there is actually a timeoutable messagebox function exported from user32 on XP & above; MessageBoxTimeout (as used by things like WShell.Popup())

like image 159
Alex K. Avatar answered Oct 05 '22 12:10

Alex K.


You should ask yourself, why you want a messagebox in the first place. When it is OK that the message box is not seen when noone is sitting in front of the computer, why isn't it OK that the user doesn't see a message when his program disappears?

If you really want it, I think the simplest solution is to spawn a new process displaying the message. It can run as long as it wants and does not interfer with your crashing program.

like image 40
Timbo Avatar answered Oct 05 '22 12:10

Timbo


Quick copy/paste solution:

int DU_MessageBoxTimeout(HWND hWnd, const WCHAR* sText, const WCHAR* sCaption, UINT uType, DWORD dwMilliseconds)
{
    // Displays a message box, and dismisses it after the specified timeout.
    typedef int(__stdcall *MSGBOXWAPI)(IN HWND hWnd, IN LPCWSTR lpText, IN LPCWSTR lpCaption, IN UINT uType, IN WORD wLanguageId, IN DWORD dwMilliseconds);

    int iResult;

    HMODULE hUser32 = LoadLibraryA("user32.dll");
    if (hUser32)
    {
        auto MessageBoxTimeoutW = (MSGBOXWAPI)GetProcAddress(hUser32, "MessageBoxTimeoutW");

        iResult = MessageBoxTimeoutW(hWnd, sText, sCaption, uType, 0, dwMilliseconds);

        FreeLibrary(hUser32);
    }
    else
        iResult = MessageBox(hWnd, sText, sCaption, uType);         // oups, fallback to the standard function!

    return iResult;
}
like image 43
Simon Avatar answered Oct 05 '22 12:10

Simon


I noticed that if the main thread simply exits the application while the other thread still has the ::MessageBox open, that the MessageBox is being adopted by a process called CSRSS. This solves my problem, since this only requires a time-out on the Event in the main thread (WaitForSingleObject with timeout).

However, this raised another question: https://stackoverflow.com/questions/3091915/explanation-why-messagebox-of-exited-application-is-adopted-by-winsrv.

like image 44
Patrick Avatar answered Oct 05 '22 13:10

Patrick


This does not justify a thread.

The best solution would be to use a modal dialog box that registers a timer for auto-close.

like image 27
Pavel Radzivilovsky Avatar answered Oct 05 '22 12:10

Pavel Radzivilovsky


What about just logging the event to a local file (and record memory dumps or whatever information you might need for later debugging)?

You could close your application, close network connections and do your housekeeping stuff.

As soon as the application is started again, you can inform your user (based on local file information) that the application has crashed during last execution.

like image 40
glutorange Avatar answered Oct 05 '22 13:10

glutorange


A Win32 MessageBox really is a dialog, with a dialog message pump. You can therefore rely on standard Win32 timer messages (WM_TIMER). Send one to your own window, and when you do get it, dismiss the MessageBox by sending a WM_COMMAND/BN_CLICKED message to the ID_OK button.

The messagebox, since it's a dialog, will be class "#32770". Since it's the only dialog box you will have open, it's easy to find amongst your child windows.

like image 42
MSalters Avatar answered Oct 05 '22 11:10

MSalters