【问题标题】:MessageBox with timeout OR Closing a MessageBox from another thread超时的消息框或从另一个线程关闭消息框
【发布时间】:2010-06-22 08:04:15
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

    标签: c++ windows winapi


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      虽然我同意生成一个新进程来显示即发即弃对话框可能是最好的,但 FWIW 实际上在 XP 及更高版本上从 user32 导出了一个可超时的消息框函数; MessageBoxTimeout(被WShell.Popup()之类的东西使用)

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          【解决方案4】:

          你应该问自己,为什么你首先想要一个消息框。当没有人坐在电脑前看不到消息框是可以的,为什么当他的程序消失时用户看不到消息就不行了?

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

          【讨论】:

            【解决方案5】:

            我注意到,如果主线程简单地退出应用程序,而另一个线程仍然打开 ::MessageBox,则表明 MessageBox 正在被称为 CSRSS 的进程采用。这解决了我的问题,因为这只需要主线程中的事件超时(WaitForSingleObject 超时)。

            不过,这又引发了另一个问题:https://stackoverflow.com/questions/3091915/explanation-why-messagebox-of-exited-application-is-adopted-by-winsrv

            【讨论】:

              【解决方案6】:

              这并不能证明线程是正确的。

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

              【讨论】:

              • 我想写同样的建议:创建一个关于DialogBox的新对话框,在WM_INITDIALOG中创建一个带有SetTimer的计时器,然后关闭WM_TIMER中的对话框。
              【解决方案7】:

              仅将事件记录到本地文件(并记录内存转储或您以后调试可能需要的任何信息)怎么样?

              你可以关闭你的应用程序,关闭网络连接并做你的家务。

              应用程序再次启动后,您可以通知您的用户(根据本地文件信息)应用程序在上次执行期间崩溃了。

              【讨论】:

                【解决方案8】:

                我会从包装应用程序内部运行您的原始代码,该应用程序执行 CreateProcess,然后在进程句柄上执行 MsgWaitForMultipleObjects(大多数进程启动代码示例使用 WaitForSingleObject,但您需要防止消息传递死锁情况)。然后,您的监视进程可以检测到生成的进程的故障,弹出自己的超时对话框,并在用户响应或超时时退出。

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

                【讨论】:

                  猜你喜欢
                  • 2021-03-16
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-09-07
                  • 1970-01-01
                  • 2013-04-14
                  • 2014-07-04
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多