具有超时的MessageBox或从另一个线程关闭MessageBox

时间:2010-06-22 08:04:15

标签: c++ windows winapi

如果我的应用程序崩溃,我使用ExceptionFilter来捕获崩溃,执行一些最终操作,然后向用户显示应用程序崩溃的消息框。

因为应用程序已经崩溃,所以我可以(或者我不敢)做太多事情,因为如果我做得太多,执行的代码可能会访问损坏的内存并再次崩溃。 我目前无法做的一些事情(或者我不敢做)是关闭网络连接,Oracle数据库会话,......

问题是,如果应用程序崩溃,并且用户在MessageBox打开时外出吃午餐,则由于打开数据库会话,其他用户可能会被阻止。因此,我想:

  • 带有超时的MessageBox。问题是你不能用标准的MessageBox Win32 API函数做这个,我不想为它做一个特定的对话(因为我想在崩溃后最小化执行的逻辑)
  • 或者从另一个线程关闭MessageBox的可能性(另一个线程可以提供超时逻辑)。

我是否忽略了Win32 API中的某些内容,是否有可能让MessageBox超时?

或者从另一个线程关闭打开的MessageBox的正确方法是什么(如何获取MessageBox句柄,如何关闭它,...)?

8 个答案:

答案 0 :(得分:6)

虽然我同意产生一个新的过程来显示一个即发即弃的对话框可能是最好的,但是FWIW实际上有一个可以在XP和user32上从user32导出的超时消息框功能。以上; MessageBoxTimeout(用于WShell.Popup()

之类的内容

答案 1 :(得分:3)

你应该问问自己,为什么你想要一个消息框。当没有人坐在电脑前没有看到消息框时,为什么用户在程序消失时没有看到消息呢?

如果你真的想要它,我认为最简单的解决方案是生成一个显示消息的新进程。它可以根据需要运行,也不会干扰您的崩溃程序。

答案 2 :(得分:2)

我注意到如果主线程只是退出应用程序,而另一个线程仍然打开:: MessageBox,那么MessageBox正被一个名为CSRSS的进程所采用。这解决了我的问题,因为这只需要在主线程中的事件超时(具有超时的WaitForSingleObject)。

然而,这提出了另一个问题:https://stackoverflow.com/questions/3091915/explanation-why-messagebox-of-exited-application-is-adopted-by-winsrv

答案 3 :(得分:2)

快速复制/粘贴解决方案:

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;
}

答案 4 :(得分:1)

这不能证明一个主题。

最好的解决方案是使用一个模式对话框来注册一个自动关闭的计时器。

答案 5 :(得分:1)

如何将事件记录到本地文件(以及记录内存转储或稍后调试可能需要的任何信息)?

您可以关闭应用程序,关闭网络连接并执行管理工作。

一旦应用程序再次启动,您就可以通知您的用户(基于本地文件信息)应用程序在上次执行期间崩溃。

答案 6 :(得分:1)

Win32 MessageBox确实是一个对话框,带有对话框消息泵。因此,您可以依赖标准的Win32计时器消息(WM_TIMER)。将一个发送到您自己的窗口,当您获得它时,通过向ID_OK按钮发送WM_COMMAND/BN_CLICKED消息来关闭MessageBox。

消息框,因为它是一个对话框,将是“#32770”类。由于它是您打开的唯一对话框,因此很容易在您的子窗口中找到它。

答案 7 :(得分:0)

我将从包装器应用程序中运行原始代码,该应用程序执行CreateProcess,然后在进程句柄上运行MsgWaitForMultipleObjects(大多数进程启动代码示例使用WaitForSingleObject,但您需要防止消息传递死锁方案)。然后,您的观察过程可以检测生成的进程的失败,弹出自己的超时对话框,并退出用户响应或超时。

我认为这是最干净的解决方案,可以防止不稳定的程序执行任何代码。