Recent

Author Topic: Unique Instance Terminate Application  (Read 2950 times)

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Unique Instance Terminate Application
« Reply #15 on: December 08, 2023, 06:32:40 pm »
A windows only solution that each folder can run 1 copy of your application can look like this:
Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Windows, SysUtils, Base64,
  7.   {$IFDEF UNIX}
  8.   cthreads,
  9.   {$ENDIF}
  10.   {$IFDEF HASAMIGA}
  11.   athreads,
  12.   {$ENDIF}
  13.   Interfaces, // this includes the LCL widgetset
  14.   Forms, unit1
  15.   { you can add units after this };
  16.  
  17. {$R *.res}
  18.  
  19. function GetNamedPipeServerProcessId(hNamedPipe: THandle;
  20.   out ServerProcessId: ULONG): BOOL; stdcall;
  21.   external kernel32 name 'GetNamedPipeServerProcessId';
  22.  
  23. function EnumWindowsProcCallback(HWnd: THandle; PID: LPARAM): BOOL; stdcall;
  24. var
  25.   WinPID: DWORD;
  26. begin
  27.   GetWindowThreadProcessId(HWnd, WinPID);
  28.   Result := WinPID <> (PULONG(PID))^;
  29.   if not Result then
  30.     SetForegroundWindow(HWnd); // Note: Windows forbid to use this, you need a different approach!
  31. end;
  32.  
  33. const
  34.   FILE_FLAG_FIRST_PIPE_INSTANCE = $00080000;
  35. var
  36.   hPipeClient: THandle;
  37.   pipeName: AnsiString;
  38.   processID: ULONG;
  39. begin
  40.   pipeName := '\\.\pipe\' + Base64.EncodeStringBase64(ParamStr(0));
  41.   hPipeClient := CreateNamedPipe(PAnsiChar(pipeName),
  42.     PIPE_ACCESS_OUTBOUND or FILE_FLAG_FIRST_PIPE_INSTANCE,
  43.     PIPE_TYPE_BYTE or PIPE_READMODE_BYTE or PIPE_WAIT, 1, 4, 4, 0, nil);
  44.   if (hPipeClient <> INVALID_HANDLE_VALUE) then
  45.     begin
  46.        RequireDerivedFormResource := True;
  47.        Application.Scaled := True;
  48.        Application.Initialize;
  49.        Application.CreateForm(TForm1, Form1);
  50.        Application.Run;
  51.        CloseHandle(hPipeClient);
  52.     end
  53.   else
  54.     begin
  55.       hPipeClient := CreateFile(PAnsiChar(pipeName), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);
  56.        if hPipeClient <> INVALID_HANDLE_VALUE then
  57.        begin
  58.          if GetNamedPipeServerProcessId(hPipeClient, processID) then
  59.            EnumWindows(@EnumWindowsProcCallback, LPARAM(@processID));
  60.        end;
  61.        if (hPipeClient <> INVALID_HANDLE_VALUE) or (GetLastError <> ERROR_PIPE_BUSY) then
  62.          CloseHandle(hPipeClient);
  63.     end;
  64. end.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

d7_2_laz

  • Hero Member
  • *****
  • Posts: 552
Re: Unique Instance Terminate Application
« Reply #16 on: December 08, 2023, 08:49:48 pm »
So we've now three possible solutions to deal with this specific scenario too, wow!
Thank you for your contribution @Kodezwerg! I'd stay at the variation based on the link i pointed to (simply i've no problem with it), but this technique appears very interesting too (named pipes .. I wouldn't have thought of it here).
Lazarus 3.6  FPC 3.2.2 Win10 64bit

440bx

  • Hero Member
  • *****
  • Posts: 4760
Re: Unique Instance Terminate Application
« Reply #17 on: December 08, 2023, 09:43:44 pm »
My special use case is that my app might be placed in more than one folder, where each one is dedicated for a special working context / config / data.
Here i'd want to allow the app running concurrently when started from different folders,
but to prohibit each one to be started twice from a same folder.
When started again from the same folder, it simply would be brought to foreground.
When started from a different folder, that should be allowed.
Piece of cake. :)

The solution is to use the full image name (include path/directory) as the mutex name, note that you'll have to replace the backslash in the path since that character is not allowed in a mutex name (see Crea]"]>Blockedtex for details.)

That way, only instances that are started from the same directory will attempt to create the same mutex thus revealing there is already an instance running.   

Use GetCurrentProcess and GetProcessImageFilename to get the full name of your process which determines the name of the mutex that is (or will be) in use.

HTH.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

d7_2_laz

  • Hero Member
  • *****
  • Posts: 552
Re: Unique Instance Terminate Application
« Reply #18 on: December 08, 2023, 10:22:59 pm »
@440bx, … hm, to be understood as “this is another possibility, #4”
or:
 “take better this strategy, based on Mutexes, it’s better, because ..”?
And: would it be needed to be implemented newly, or does it, as modification, refer to an existing code pattern?

Lazarus 3.6  FPC 3.2.2 Win10 64bit

440bx

  • Hero Member
  • *****
  • Posts: 4760
Re: Unique Instance Terminate Application
« Reply #19 on: December 08, 2023, 10:30:02 pm »
The link you provided in a previous post and to which you referred to as your preferred option uses a mutex. 

Because of this, I consider what I suggested in my previous post simply a variation of that theme, one that accomplishes the additional requirements which the normal "use a mutex" does not accomplish, i.e, the normal mutex method does not allow multiple instances of the same program to run if they reside in different directories (because all instances normally use the same mutex name.)

You can consider the method I suggested option #4 if you'd like but, I see it more as option #3.1 <chuckle>
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

d7_2_laz

  • Hero Member
  • *****
  • Posts: 552
Re: Unique Instance Terminate Application
« Reply #20 on: December 08, 2023, 11:00:59 pm »
@440bx, ok, I think I understood, you mean it could be a better/extended version of the initial approach as from reply #4 (within the link mentioned) as base, rather than going to the later version as of reply #7 herein which I pointed to. I think I got your point. Thanks!
Lazarus 3.6  FPC 3.2.2 Win10 64bit

 

TinyPortal © 2005-2018