Jump to content
new_x

Prevent Multiple Instance from running at the same time

Recommended Posts

Hi all
I inserted the following call to the dpr file of the application to prevent the multiple instances. But did not succeed.

 

 

function isOneInstance(): Boolean;
Var
  Handle: THandle;
  ErrCode: DWORD;
Begin
  Result:= False;
  Handle:= 0;

  try
    Handle:= CreateMutex(nil, True, 'Global\_AFB2FB05-5FA5-4C9E-9633-2353418AFF7E-HGaytt19');
    if(Handle= 0) then exit();
    if GetLastError() = ERROR_ALREADY_EXISTS then begin
      exit();
    end;

    Result:= True;
  finally
    if(Handle<>0) then begin
      ReleaseMutex(Handle);
      CloseHandle(Handle);
    end;
    Handle:= 0;
  end;
End;


begin
  if(isOneInstance()) then begin
    Application.Initialize;
    Application.MainFormOnTaskbar := True;
    Application.CreateForm(TForm1, Form1);
    Application.Run;
  end else begin
    Application.MessageBox('Already Running', 'WARNING', MB_OK);
    Application.Terminate();
  end;
end.

 

Best Regards,

Share this post


Link to post
6 minutes ago, new_x said:

  finally
    if(Handle<>0) then begin
      ReleaseMutex(Handle);
      CloseHandle(Handle);
    end;

Your code is closing the handle, so how the next instance will get ERROR_ALREADY_EXISTS ?!

Redesign that.

  • Like 1

Share this post


Link to post

You should also set the bInitialOwner parameter to False in the CreateMutex() call.  You don't need ownership of the mutex just to create it and test for its existence.  You can then remove the call to ReleaseMutex() as well.

Share this post


Link to post

Importing an other 3rd party library seems to be a huge overkill just to use a simple mutex.

 

I have the following code in my .dpr file before any form creations:

  handle := CreateMutex(nil, True, 'MyAppName');
  Try
    If (handle = 0) Or (GetLastError = ERROR_ALREADY_EXISTS) Then
    Begin
      // TMessageDialog.ShowDialog('Only one instance can be running at a time!', dtError);
      handle := FindWindow('TMyApplicationMainForm', nil);
      If IsWindow(handle) Then
      Begin
        ShowWindow(handle, SW_RESTORE And SW_SHOW);
        SetForegroundWindow(handle);
        SetFocus(handle);
      End;

      Exit;
    End;
    
    // Form creations, initialization, run here originally from .dpr
  Finally
    CloseHandle(handle);
  End;

Works like a charm, and you only need WinApi.Windows.
 

Share this post


Link to post

I use a similar approach as aehimself for Window programs with an addition I saw in a Holger Flick video.

 

He created a very simple static TController class and replaced the .dpr code with a single line:

begin
  TAppController.Run;
end.

This way you don't have to add code to the .dpr which I have had cause trouble in the past since Delphi edits this file as well. You can add code to the Run procedure and not worry about messing things up.

TAppController = class
  public
    class procedure Run;
  private
    class function CheckSingleton: Boolean;
    class procedure SetFocusRunningInstance;
  end;

class function TAppController.CheckSingleton: Boolean;
begin
  Result := FindWindow(WINDOW_CLASS_NAME, nil) = 0;
end;

class procedure TAppController.SetFocusRunningInstance;
begin
  ShowWindow(FindWindow(WINDOW_CLASS_NAME, nil), SW_SHOWMAXIMIZED);
end;

class procedure TAppController.Run;
begin
    Application.Initialize;
    Application.MainFormOnTaskbar := True;

    if TAppController.CheckSingleton then
    begin
      //Add conditional defines,  splash screen whatever
     
      Application.Run;

    end
    else
    begin
      TAppController.SetFocusRunningInstance;
    end;
end;

Someone else (Can't remember where) also suggested setting the main form window to something unique  you need to override the CreateParams of the Main form.

procedure TfrmMain.CreateParams(var Params: TCreateParams);
begin
  inherited;
  StrCopy(Params.WinClassName, WINDOW_CLASS_NAME);
end;

 

  • Like 2

Share this post


Link to post

I like mutex approach more (with one little difference that I use events). It will work for any application while Findwindow is for GUI-only (or you have to create a dummy window just for that). For some apps I allow running from different paths so I'm retrieving folder of Application.ExeName and adding it to event name.

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×