应用程序主窗体未接收通过 SendMessage 发送的消息
Application main form is not receiving messages sent via SendMessage
我从这篇文章中复制了代码:
Controlling the number of application instances
但是,SendMessage 发送的消息未被主窗体 'caught'。
这是 DPR 文件中的代码,我们在其中注册消息,然后在应用程序实例已经 运行:
时广播它
var
Mutex: THandle;
begin
MyMsg := RegisterWindowMessage('Show_Main_Form');
Mutex := CreateMutex(nil, True, 'B8C24BD7-4CFB-457E-841E-1978A8ED0B16');
if (Mutex = 0) or (GetLastError = ERROR_ALREADY_EXISTS) then
begin
SendMessage(HWND_BROADCAST, MyMsg, 0, 0);
end
这是主窗体的代码:
var
fmMain: TfmMain;
MyMsg: Cardinal;
implementation
uses
uSettings;
{$R *.dfm}
procedure TfmMain.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
if (Msg.Message = MyMsg) then
begin
beep;
Application.Restore;
Application.MainForm.Visible := True;
SetForeGroundWindow(Application.MainForm.Handle);
Handled := True;
end;
end;
procedure TfmMain.FormCreate(Sender: TObject);
begin
Application.OnMessage := AppMessage;
end;
问题是 AppMessage 过程没有被调用。怎么了?
OnMessage
用于拦截排队的消息。但是,此消息被发送而不是排队。您需要覆盖表单的 window 程序才能接收它:
将此添加到表单类型声明的受保护部分:
procedure WndProc(var Message: TMessage); override;
这样实现:
procedure TfmMain.WndProc(var Message: TMessage);
begin
inherited;
if Message.Msg = MyMsg then
begin
Beep;
Application.Restore;
Application.MainForm.Visible := True;
SetForeGroundWindow(Application.MainForm.Handle);
end;
end;
由于此表单可能是应用程序主表单的单个实例,您可以将消息处理程序的主体替换为:
Application.Restore;
Visible := True;
SetForeGroundWindow(Handle);
我还要评论说,广播这样的消息对我来说似乎有点冒险。您将将该消息发送到系统中的每个顶级 window。我认为,如果您遇到一个程序在不应该对该消息做出反应时,它肯定会导致问题。
如果是我,我会确定您打算定位的 window,然后将消息直接发送给 window。我会使用 SendMessageTimeout
来稳健地应对目标应用程序没有响应的场景。在这种情况下,SendMessage
永远不会 return 并且发送应用程序也会挂起。
我从这篇文章中复制了代码: Controlling the number of application instances
但是,SendMessage 发送的消息未被主窗体 'caught'。
这是 DPR 文件中的代码,我们在其中注册消息,然后在应用程序实例已经 运行:
时广播它var
Mutex: THandle;
begin
MyMsg := RegisterWindowMessage('Show_Main_Form');
Mutex := CreateMutex(nil, True, 'B8C24BD7-4CFB-457E-841E-1978A8ED0B16');
if (Mutex = 0) or (GetLastError = ERROR_ALREADY_EXISTS) then
begin
SendMessage(HWND_BROADCAST, MyMsg, 0, 0);
end
这是主窗体的代码:
var
fmMain: TfmMain;
MyMsg: Cardinal;
implementation
uses
uSettings;
{$R *.dfm}
procedure TfmMain.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
if (Msg.Message = MyMsg) then
begin
beep;
Application.Restore;
Application.MainForm.Visible := True;
SetForeGroundWindow(Application.MainForm.Handle);
Handled := True;
end;
end;
procedure TfmMain.FormCreate(Sender: TObject);
begin
Application.OnMessage := AppMessage;
end;
问题是 AppMessage 过程没有被调用。怎么了?
OnMessage
用于拦截排队的消息。但是,此消息被发送而不是排队。您需要覆盖表单的 window 程序才能接收它:
将此添加到表单类型声明的受保护部分:
procedure WndProc(var Message: TMessage); override;
这样实现:
procedure TfmMain.WndProc(var Message: TMessage);
begin
inherited;
if Message.Msg = MyMsg then
begin
Beep;
Application.Restore;
Application.MainForm.Visible := True;
SetForeGroundWindow(Application.MainForm.Handle);
end;
end;
由于此表单可能是应用程序主表单的单个实例,您可以将消息处理程序的主体替换为:
Application.Restore;
Visible := True;
SetForeGroundWindow(Handle);
我还要评论说,广播这样的消息对我来说似乎有点冒险。您将将该消息发送到系统中的每个顶级 window。我认为,如果您遇到一个程序在不应该对该消息做出反应时,它肯定会导致问题。
如果是我,我会确定您打算定位的 window,然后将消息直接发送给 window。我会使用 SendMessageTimeout
来稳健地应对目标应用程序没有响应的场景。在这种情况下,SendMessage
永远不会 return 并且发送应用程序也会挂起。