Перехват модальных окон в приложениях Delphi может быть необходим для различных целей, например, для отладки, автоматизации тестирования или для изменения поведения окон во время выполнения программы. В данной статье мы рассмотрим методы и примеры использования перехвата модальных окон на примере функции ShowMessage.
Проблема и цель
Пользователь ищет способ перехватить момент, когда модальное окно появляется на экране, и получить ссылку на форму, которая это окно показало. В частности, рассматривается использование функции ShowMessage, которая в стандартной реализации не предоставляет возможности для перехвата.
Решение
В современных версиях Delphi и Windows, вызов ShowMessage приводит к появлению окна диалога. Для перехвата активации этого окна можно использовать механизм WH_CBT (Callback Tracing) хука. Ниже приведен пример кода, который устанавливает такой хук:
function CBTProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
wnd: HWND;
ClassName: string;
begin
if nCode = HCBT_ACTIVATE then
begin
wnd := wParam;
SetLength(ClassName, 256);
GetClassName(wnd, PChar(ClassName), Length(ClassName));
if (ClassName = '#32770') or (ClassName = 'TMessageForm') then
// Действия с окном, например, вывод сообщения
Beep;
end;
Result := CallNextHookEx(0, nCode, wParam, lParam);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Hook: HHOOK;
begin
Hook := SetWindowsHookEx(WH_CBT, CBTProc, HInstance, GetCurrentThreadId);
if Hook = 0 then
RaiseLastOSError;
try
ShowMessage('Hello');
finally
if not UnhookWindowsHookEx(Hook) then
RaiseLastOSError;
end;
end;
Обратите внимание, что имя класса окна может отличаться в зависимости от операционной системы. Например, на XP класс будет TMessageForm, так как окно является формой Delphi, в то время как на Vista и более новых системах окно будет стандартным диалоговым окном сообщения с классом #32770.
Альтернативный подход
Также можно использовать альтернативный подход, установив глобальный хук в основном окне приложения. Это позволяет перехватить все модальные окна, показываемые в приложении:
procedure TMainForm.FormCreate(Sender: TObject);
begin
Application.HookMainWindow(ApplicationHook);
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
Application.UnhookMainWindow(ApplicationHook);
end;
function TMainForm.ApplicationHook(var Message: TMessage): Boolean;
var
I: Integer;
begin
Result := False;
// Проверка сообщений и действия с окнами
if (Message.Msg = WM_ENABLE) and not TWMEnable(Message).Enabled then
begin
for I := 0 to Screen.FormCount - 1 do
begin
with Screen.Forms[I] do
if (Enabled and (ClassNameIs('TMessageForm') or ClassNameIs('TForm') or ClassNameIs('TMyLoginDialog'))) then
begin
// Действия с формой
Result := True;
Break;
end;
end;
end;
end;
Важные замечания
Получить экземпляр VCL формы для модального диалога не получится, так как это будет не VCL форма, а окно Windows.
Для работы с окном потребуется использовать API Windows.
Заключение
Перехват модальных окон в Delphi может быть полезен для различных задач, но требует тщательного планирования и понимания того, как работает система окон Windows. Использование хуков позволяет гибко реагировать на появление новых окон, но также вносит определенные риски, такие как бесконечные циклы и непредвиденное поведение программы.
Перехват модальных окон в приложениях Delphi может быть необходим для отладки, автоматизации тестирования или изменения поведения окон во время выполнения программы.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS