我用Delphi XE3创建了一个应用程序。 我的应用程序有一个trayicon(我使用TCoolTrayIcon),所以当用户最小化它时,任务栏上没有图标,只有在trayicon上。
为了避免使用我的应用程序,我使用此代码:
procedure CreateMutexes(const MutexName: String);
const
SECURITY_DESCRIPTOR_REVISION = 1;
var
SecurityDesc: TSecurityDescriptor;
SecurityAttr: TSecurityAttributes;
MutexHandle: THandle;
begin
InitializeSecurityDescriptor(@SecurityDesc, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(@SecurityDesc, True, nil, False);
SecurityAttr.nLength := SizeOf(SecurityAttr);
SecurityAttr.lpSecurityDescriptor := @SecurityDesc;
SecurityAttr.bInheritHandle := False;
MutexHandle := CreateMutex(@SecurityAttr, False, PChar(MutexName));
if MutexHandle <> 0 then
begin
if GetLastError = ERROR_ALREADY_EXISTS then
begin
MessageBox(0, 'You cannot start more than one instance of ContLab.'
+ #13#10 + 'Use the instance has already started.',
'ContLab', mb_IconHand);
CloseHandle(MutexHandle);
Halt;
end
end;
CreateMutex(@SecurityAttr, False, PChar('Global\' + MutexName));
end;
这样,当用户启动应用程序2次时,他收到错误消息,第二个实例终止。
现在我不想显示错误消息,而是打开第一个应用程序实例的主要形式并终止第二个实例。
有可能吗?
答案 0 :(得分:6)
您需要向其他应用程序发送消息,请求它显示自己。
首先,您需要找到其他应用程序的主窗口。有很多方法可以做到这一点。例如,您可以使用FindWindow
。或者,您可以使用EnumWindows
枚举顶级窗口。通常,您会检查匹配的窗口文本和/或类名。
一旦找到了另一个实例的主窗口,就需要让它能够将自己设置为前景窗口。您需要致电AllowSetForegroundWindow
。
var
pid: DWORD;
....
GetWindowThreadProcessId(hwndOtherInstance, pid);
AllowSetForegroundWindow(pid);
然后向窗口发送用户定义的消息。例如:
const
WM_RESTOREWINDOW = WM_APP;
....
SendMessage(hwndOtherInstance, WM_RESTOREWINDOW, 0, 0);
最后,您的其他实例的主要表单需要侦听此消息。
type
TMainForm = class(TForm)
....
protected
procedure WMRestoreWindow(var Message: TMessage); message WM_RESTOREWINDOW;
....
end;
当遇到消息时,它必须这样做:
procedure TMainForm.WMRestoreWindow(var Message: TMessage);
begin
inherited;
Visible := True;
Application.Restore;
Application.BringToFront;
end;
我对您的互斥锁处理代码持怀疑态度。由于您是在本地命名空间中创建安全属性,因此我不了解安全属性的必要性。但后来我看到第二次调用CreateMutex
忽略了返回值,但在全局命名空间中创建了一个对象。