I have create an application with Delphi XE3. My application have a trayicon (I use TCoolTrayIcon for this) so when the user minimize it there is not a icon on taskbar but only on trayicon.
To avoid more that one istance of my application I use this code:
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;
In this way when the user start application 2 times he get an error message and the second instance is terminate.
Now I'd like not show the error message but open the main form of first instance of application and terminate the second instance.
Is it possible?
You need to send a message to the other application to request that it shows itself.
First of all you need to find the other application's main window. There are many ways to do that. For instance you can use FindWindow
. Or you can enumerate the top-level windows with EnumWindows
. Typically you'd then check for matching window text and/or class name.
Once you've found the main window of the other instance, you need to give it the ability to set itself to be the foreground window. You need to call AllowSetForegroundWindow
.
var
pid: DWORD;
....
GetWindowThreadProcessId(hwndOtherInstance, pid);
AllowSetForegroundWindow(pid);
Then send the window a user-defined message. For instance:
const
WM_RESTOREWINDOW = WM_APP;
....
SendMessage(hwndOtherInstance, WM_RESTOREWINDOW, 0, 0);
Finally, your other instance's main form needs to listen for this message.
type
TMainForm = class(TForm)
....
protected
procedure WMRestoreWindow(var Message: TMessage); message WM_RESTOREWINDOW;
....
end;
When it encounters the message it must do this:
procedure TMainForm.WMRestoreWindow(var Message: TMessage);
begin
inherited;
Visible := True;
Application.Restore;
Application.BringToFront;
end;
I'm a little sceptical of your mutex handling code. I don't understand the need for security attributes since you are creating it in the local namespace. But then I see a second call to CreateMutex
that ignores the return value, but creates an object in the global namespace.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With