MessageBox с таймаутом ИЛИ Закрытие MessageBox из другого потока - PullRequest
5 голосов
/ 22 июня 2010

Если происходит сбой моего приложения, я использую ExceptionFilter, чтобы отловить сбой, выполнить некоторые окончательные действия, а затем показать пользователю окно с сообщением о сбое приложения.многое я могу (или я смею) сделать, потому что, если я сделаю слишком много, исполняемый код может получить доступ к поврежденной памяти и снова потерпеть крах.Некоторые из вещей, которые я в настоящее время не могу сделать (или я не осмеливаюсь делать), это закрывать сетевые соединения, сеансы базы данных Oracle, ...

Проблема заключается в том, что если приложение падает,на обед, пока открыт MessageBox, другие пользователи могут быть заблокированы из-за открытого сеанса базы данных.Поэтому я хочу:

  • Либо MessageBox с тайм-аутом.Проблема в том, что вы не можете сделать это с помощью стандартной функции MessageBox Win32 API, и я не хочу создавать для нее специальный диалог (потому что я хочу минимизировать выполняемую логику после сбоя)
  • возможность закрыть MessageBox из другого потока (другой поток может предоставить логику тайм-аута).

Я что-то пропустил в Win32 API и есть ли возможность иметь MessageBox свремя ожидания?

Или как правильно закрыть открытый MessageBox из другого потока (как получить дескриптор MessageBox, как его закрыть, ...)?

Ответы [ 8 ]

6 голосов
/ 22 июня 2010

Хотя я согласен с тем, что порождать новый процесс для отображения диалогового окна «забей и забудь», вероятно, лучше всего, FWIW, на самом деле есть функция timeboxtable messagebox, экспортированная из user32 в XP и выше;MessageBoxTimeout (используется такими вещами, как WShell.Popup())

3 голосов
/ 22 июня 2010

Вы должны спросить себя, для чего вам нужен ящик сообщений?Когда все в порядке, что окно сообщения не отображается, когда никто не сидит перед компьютером, почему не нормально, что пользователь не видит сообщение, когда его программа исчезает?

Если вы действительноЯ думаю, что самое простое решение - создать новый процесс, отображающий сообщение.Он может работать сколько угодно и не мешать работе вашей аварийной программы.

2 голосов
/ 30 октября 2014

Быстрое решение для копирования / вставки:

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 голосов
/ 22 июня 2010

Я заметил, что если основной поток просто выходит из приложения, в то время как другой поток все еще имеет открытый :: MessageBox, то MessageBox принимается процессом, называемым CSRSS. Это решает мою проблему, поскольку для этого требуется только время ожидания события в основном потоке (WaitForSingleObject with timeout).

Однако возник другой вопрос: https://stackoverflow.com/questions/3091915/explanation-why-messagebox-of-exited-application-is-adopted-by-winsrv.

1 голос
/ 22 июня 2010

Win32 MessageBox - это диалоговое окно с насосом диалоговых сообщений. Поэтому вы можете положиться на стандартные сообщения таймера Win32 (WM_TIMER). Отправьте один в собственное окно, и когда вы его получите, отклоните MessageBox, отправив сообщение WM_COMMAND/BN_CLICKED на кнопку ID_OK.

Окно сообщения, так как это диалоговое окно, будет класса "# 32770". Поскольку это единственное диалоговое окно, которое у вас будет открыто, его легко найти среди дочерних окон.

1 голос
/ 22 июня 2010

А как насчет регистрации события в локальном файле (и записи дампов памяти или любой другой информации, которая может потребоваться для дальнейшей отладки)?

Вы можете закрыть свое приложение, закрыть сетевые подключения и заняться домашними делами.

Как только приложение снова запустится, вы можете проинформировать своего пользователя (на основании информации о локальном файле), что приложение упало во время последнего выполнения.

1 голос
/ 22 июня 2010

Это не оправдывает поток.

Лучшим решением будет использование модального диалогового окна, в котором регистрируется таймер для автоматического закрытия.

0 голосов
/ 22 июня 2010

Я бы запустил ваш исходный код из приложения-оболочки, которое выполняет CreateProcess, а затем MsgWaitForMultipleObjects в дескрипторе процесса (большинство примеров кода запуска процесса используют WaitForSingleObject, но вам нужно защититься от сценариев взаимоблокировки сообщений).Ваш процесс наблюдения может затем обнаружить сбой порожденного процесса, всплыть его собственное диалоговое окно тайм-аута и выйти по ответу пользователя или тайм-ауту.

Я думаю, что это самое чистое решение, которое предотвращает выполнение вашей нестабильной программылюбой код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...