【发布时间】:2008-10-21 03:52:43
【问题描述】:
我有一个应用程序,它检测是否有另一个应用程序实例正在运行,如果找到则退出。这部分似乎工作可靠。我的应用程序需要一个命令行参数,我想将它传递给已经运行的实例。到目前为止,我有以下代码:
Project1.dpr
program Project1;
uses
...
AppInstanceControl in 'AppInstanceControl.pas';
if not AppInstanceControl.RestoreIfRunning(Application.Handle) then
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TFormMain, FormMain);
Application.Run;
end;
end.
AppInstanceControl.pas
{ 基于 Zarko Gajic 在http://delphi.about.com/library/code/ncaa100703a.htm} 找到的代码
unit AppInstanceControl;
interface
uses
Windows,
SysUtils;
function RestoreIfRunning(const AAppHandle: THandle; const AMaxInstances: integer = 1): boolean;
implementation
uses
Messages;
type
PInstanceInfo = ^TInstanceInfo;
TInstanceInfo = packed record
PreviousHandle: THandle;
RunCounter: integer;
end;
var
UMappingHandle: THandle;
UInstanceInfo: PInstanceInfo;
UMappingName: string;
URemoveMe: boolean = True;
function RestoreIfRunning(const AAppHandle: THandle; const AMaxInstances: integer = 1): boolean;
var
LCopyDataStruct : TCopyDataStruct;
begin
Result := True;
UMappingName := StringReplace(
ParamStr(0),
'\',
'',
[rfReplaceAll, rfIgnoreCase]);
UMappingHandle := CreateFileMapping($FFFFFFFF,
nil,
PAGE_READWRITE,
0,
SizeOf(TInstanceInfo),
PChar(UMappingName));
if UMappingHandle = 0 then
RaiseLastOSError
else
begin
if GetLastError <> ERROR_ALREADY_EXISTS then
begin
UInstanceInfo := MapViewOfFile(UMappingHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
SizeOf(TInstanceInfo));
UInstanceInfo^.PreviousHandle := AAppHandle;
UInstanceInfo^.RunCounter := 1;
Result := False;
end
else //already runing
begin
UMappingHandle := OpenFileMapping(
FILE_MAP_ALL_ACCESS,
False,
PChar(UMappingName));
if UMappingHandle <> 0 then
begin
UInstanceInfo := MapViewOfFile(UMappingHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
SizeOf(TInstanceInfo));
if UInstanceInfo^.RunCounter >= AMaxInstances then
begin
URemoveMe := False;
if IsIconic(UInstanceInfo^.PreviousHandle) then
ShowWindow(UInstanceInfo^.PreviousHandle, SW_RESTORE);
SetForegroundWindow(UInstanceInfo^.PreviousHandle);
end
else
begin
UInstanceInfo^.PreviousHandle := AAppHandle;
UInstanceInfo^.RunCounter := 1 + UInstanceInfo^.RunCounter;
Result := False;
end
end;
end;
end;
if (Result) and (CommandLineParam <> '') then
begin
LCopyDataStruct.dwData := 0; //string
LCopyDataStruct.cbData := 1 + Length(CommandLineParam);
LCopyDataStruct.lpData := PChar(CommandLineParam);
SendMessage(UInstanceInfo^.PreviousHandle, WM_COPYDATA, Integer(AAppHandle), Integer(@LCopyDataStruct));
end;
end; (*RestoreIfRunning*)
initialization
finalization
//remove this instance
if URemoveMe then
begin
UMappingHandle := OpenFileMapping(
FILE_MAP_ALL_ACCESS,
False,
PChar(UMappingName));
if UMappingHandle <> 0 then
begin
UInstanceInfo := MapViewOfFile(UMappingHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
SizeOf(TInstanceInfo));
UInstanceInfo^.RunCounter := -1 + UInstanceInfo^.RunCounter;
end
else
RaiseLastOSError;
end;
if Assigned(UInstanceInfo) then UnmapViewOfFile(UInstanceInfo);
if UMappingHandle <> 0 then CloseHandle(UMappingHandle);
end.
并在主窗体单元中:
procedure TFormMain.WMCopyData(var Msg: TWMCopyData);
var
LMsgString: string;
begin
Assert(Msg.CopyDataStruct.dwData = 0);
LMsgString := PChar(Msg.CopyDataStruct.lpData);
//do stuff with the received string
end;
我很确定问题是我试图将消息发送到正在运行的应用程序实例的句柄,但试图在主窗体上处理消息。我想我有两个选择:
A) 从应用程序的句柄以某种方式获取其主窗体的句柄并将消息发送到那里。
B) 在应用程序而不是主窗体级别处理接收消息。
我也不确定该怎么做。有更好的方法吗?
谢谢。
【问题讨论】: