delphi在application.run之前发送消息
我正在开发一个应用程序,以防止出现多个实例。我尝试使用wm_copydata向第一个应用程序实例发送消息,但它不起作用,但我可以通过wm_SYSCOMMAND发送消息delphi在application.run之前发送消息,delphi,Delphi,我正在开发一个应用程序,以防止出现多个实例。我尝试使用wm_copydata向第一个应用程序实例发送消息,但它不起作用,但我可以通过wm_SYSCOMMAND发送消息 if not checkInstance.RestoreIfRunning(Application.Handle,oldHandle, 1) then begin Application.Initialize; Application.MainFormOnTaskbar := True; Application.Cre
if not checkInstance.RestoreIfRunning(Application.Handle,oldHandle, 1) then
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(Tfrm_main, frm_main);
Application.Run;
end
else
begin
stringToSend := 'My Message';
aCopyData.dwData := 0; //use it to identify the message contents
aCopyData.cbData := 1 + Length(stringToSend) ;
aCopyData.lpData := PChar(stringToSend) ;
SendMessage(oldHandle,WM_COPYDATA,longint(oldHandle),longint(@aCopyData));
end;
....
mainform:
private
procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA;
.
.
.
procedure mainForm.WMCopyData(var Msg: TWMCopyData);
begin
ShowMessage('received!');
end;
看起来您将消息发送到了错误的窗口。或者从另一个角度来看,您试图在错误的窗口中处理消息 你有:
if not checkInstance.RestoreIfRunning(Application.Handle, oldHandle, 1) then
当然,我们看不到checkInstance.RestoreIfRunning
后面的代码,但我的蜘蛛感知告诉我,oldHandle
中返回的句柄是应用程序句柄,而不是主窗口句柄。让我产生这种怀疑的是:
Application.Handle
传递给RestoreIfRunning
,因此当第二个应用程序尝试运行时,可能会看到该句柄WM_SYSCOMMAND
响应,可能是为了恢复应用程序的第一个实例,但这是一条由应用程序窗口过程处理的消息Application.HookMainWindow
来实现这一点。这里有一个解决方案
Unit1.pas
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
type
TForm1 = class(TForm)
private
{ Private declarations }
public
procedure WMApp(var msg: TMessage); message WM_APP;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TForm1 }
procedure TForm1.WMApp(var msg: TMessage);
begin
Application.Restore;
end;
end.
执行:项目-查看源代码
项目1.dpr
program Project1;
uses
Vcl.Forms,
Windows,
Messages,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
var
Hwnd: THandle;
begin
Hwnd := FindWindow('TForm1', nil);
if Hwnd = 0 then
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end else
begin
if not IsWindowVisible(Hwnd) then
PostMessage(Hwnd, WM_APP, 0, 0);
SetForegroundWindow(Hwnd);
end;
end.
仅此而已检查
oldHandle
是否包含mainForm
窗口的有效句柄。此外,您还可以(应该)将True
返回到接收方的Msg.Result
属性,并检查发送方的SendMessage
的返回值。此外,SendMessage
函数的参数类型是WParam
和LParam
,而不是longint
,正如在Internet上的一些完全代码片段中所写的那样。oldhandle是有效的句柄。另外,我已经为Msg.Result输入了返回值,但没有工作。我使用了这个参数类型,它工作fwiw,你的类型转换是错误的。转换为WPARAM
和LPARAM
。这样,您的代码可以在64位中工作。我已更改sendMessage,但不再工作:sendMessage(oldHandle、WM_COPYDATA、WPARAM(oldHandle)、LPARAM(@aCopyData))
很好,因此,oldHandle
没有包含有效的mainForm
窗口句柄,因为我要求您检查。oldHandle和application.handle是不同的。另外,oldHandle是application.handle(不是表单句柄)。另外,oldHandle是application.handle(不是表单句柄)。这正是我上面的假设。解决方案正是我所描述的。消息传递给应用程序,而不是表单。所以您需要在应用程序窗口过程中处理它。谢谢@David,我只在那里放了一行代码来查找表单句柄:oldHandle:=FindWindow('mainForm',nil)代码>一切正常@好吧,我不会那样做的。如果另一个应用程序的主窗体名称相同怎么办。你应该使用HookMainWindow
。我认为询问者是想让他们的解决方案(基于互斥)发挥作用,而不是使用你不同的、稍微脆弱的解决方案。您的解决方案不可靠。