Есть ли способ отменить окно сообщения, отображаемое MessageBox.Show()?
Я думаю, что это возможно, отправив закрытое "сообщение" (WM_?) В родную очередь сообщений win32? Как именно?
Там есть ссылка на вопрос WPF, но решение этого не очень хорошее, он хочет, чтобы вы создали настраиваемое окно для имитации диалогового окна.
Упс, я не должен был отказываться от закрытого голосования. Прочтите код в принятом ответе. В winforms нет ничего особенного. Если, как вы говорите в своем вопросе, вы хотите знать, «как именно» вызывать FindWIndow () и SendMessage (), этот ответ скажет вам, как именно. То есть, если WPF не использует класс окна "# 32770"; вы это проверили?
Оконные системы Windows API и WPF не связаны. О чем вы спрашиваете? Однако, независимо от этого, используйте автоматизацию пользовательского интерфейса, если вам нужно автоматизировать пользовательский интерфейс.
Я не уверен, что назвал бы это автоматизацией пользовательского интерфейса. Это больше о передаче сообщения в окно, когда у вас нет его дескриптора.
Возможный дубликат Как подавить диалоговое окно, отображаемое кодом, который я не могу изменить?
@PaulSanders: Я не уверен, как бы вы назвали процесс взаимодействия с пользовательским интерфейсом через код. Этот является называется UI Automation. Вы должны настроить WinEvents, чтобы сообщать о создании интересующего окна, а затем вызывать в нем любую операцию, которую вы сочтете нужной. Очевидно, это предполагает фреймворк, основанный на нативных HWND. ОП отметила вопрос о технологиях, использующих разные оконные системы. По-видимому, они не знали, в чем их проблема, и не отвечали, когда их просили уточнить.
@IInspectable, извините за то, что не ответил раньше. Да, я полностью осознаю, что Windows API и WPF - это не одно и то же :) Я не уверен, как может работать UI Automation, не могли бы вы предоставить некоторые подробности?
@IInspectable А, ладно, из цитируемого обращения к MessageBox.Show я предположил, что это Winforms, извините. Однако Эта страница, похоже, подразумевает, что даже в WPF это старомодное доброе окно сообщений Win32 за кулисами.
@IInspectable в моем вопросе есть тег WPF, что означает, что я работаю с приложением WPF. Однако Win32 API можно использовать и в WPF.





Самым простым решением с использованием WinApi было бы:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
private const int WM_CLOSE = 0x10;
private const string MessageBoxTitle = "UniqueTitle123";
void CloseMessageBox()
{
var hwnd = FindWindow(null, MessageBoxTitle);
if (hwnd != IntPtr.Zero)
{
PostMessage(hwnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
}
Вам нужно вызвать окно сообщений с помощью MessageBoxTitle:
MessageBox.Show("This gonna close itself", MessageBoxTitle);
А потом где-то:
CloseMessageBox();
Пример использования:
Task.Run(async () =>
{
await Task.Delay(2000).ConfigureAwait(false);
CloseMessageBox();
});
MessageBox.Show("This closes in 2 seconds", MessageBoxTitle);
Имейте в виду, что если есть другое окно с тем же заголовком, что и ваше окно сообщения, то вызов CloseMessageBox () закроет это окно вместо вашего окна сообщения. Решение простое, но выберите заголовок msgbox таким образом, чтобы была очень малая вероятность столкновения имени с другими окнами в системе, например. YourAppName-51245 должен быть в порядке.
Спасибо. Довольно близко :) Правильный способ - создать подкласс WndProc и получить HWND окна сообщения
@DonBox Я не понимаю, как вы это сделаете. Вызов MessageBox.Show является модальным - для подкласса нет «формы». Я делаю это, устанавливая временный оконный крючок, а затем перехватываю WM_INITDIALOG. Вероятно, это проще сделать в машинном коде, чем в .net. Кроме того, этот ответ можно улучшить, если вы знаете имя класса окон сообщений. Вероятно, это номер 32770, сказал бы вам Spy ++.
PS: Вы также можете отправить WM_COMMAND, который позволит вам имитировать нажатие определенной кнопки.
@PaulSanders Я не думаю, что вам нужен оконный крючок. Вы можете сделать это: stackoverflow.com/questions/624367/… Моя идея состоит в том, чтобы перехватить событие, отправленное на собственный HWND окна, чтобы получить HWND диалога. Когда у нас есть HWND диалогового окна, мы можем закрыть диалоговое окно, когда это необходимо.
@DonBox Я думаю, вам нужно немного прояснить это. Я вообще этого не понимаю.
Я думал, что опубликую решение для этого, поскольку я считаю, что это лучший способ сделать это. Ответ выше хрупкий. Я предоставил код на родном C++, так как мне не хватает навыков .net для ответа на C#. Возможно, кто-нибудь, у кого есть такие навыки, будет переводить. Обратите внимание: код не является потокобезопасным. Если вы создаете окна сообщений более чем в одном потоке, вам придется быть немного умнее.
static HHOOK my_hook;
static HWND message_box_hwnd;
// Hook proc
LRESULT CALLBACK MyHookProc (int code, WPARAM wParam, LPARAM lParam)
{
if (code < 0)
return CallNextHookEx (tdata->tcpHook, code, wParam, lParam);
CWPSTRUCT *msg = (CWPSTRUCT *) lParam;
LRESULT result = CallNextHookEx (tdata->tcpHook, code, wParam, lParam);
if (msg->message == WM_INITDIALOG)
{
message_box_hwnd = msg->hwnd;
UnhookWindowsHookEx (my_hook);
my_hook = NULL;
}
return result;
}
my_hook = SetWindowsHookEx (WH_CALLWNDPROC, MyHookProc, NULL, GetCurrentThreadId ());
MessageBox (...);
И, конечно же, в вашей процедуре таймера или что-то еще:
PostMessage (message_box_hwnd, WM_CLOSE, 0, 0);
или (скажем):
PostMessage (message_box_hwnd, WM_COMMAND, IDCANCEL, 0);
Честно говоря, ничего особенного.
@EdPlunkett, это WinForms ...