Recent

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

Weitentaaal

  • Sr. Member
  • ****
  • Posts: 499
  • Weitental is a very beautiful garbage depot.
Unique Instance Terminate Application
« on: December 05, 2023, 08:41:57 am »
Hi,

i tried to use unique instance and put this in my on create of the main Form
Code: Pascal  [Select][+][-]
  1.    if UniqueInstance.PriorInstanceRunning then begin
  2.       //raise Exception.Create('Application already Running !');
  3.       ShowMessage('Application already Running !');
  4.       Close;
  5.       Exit;
  6.    end;
  7.  

i do always get Access Violations. How do i correctly Terminate Application?
Lazarus: 2.0.12 x86_64-win64-win32/win64
Compiler Version: 3.2.2

bobby100

  • Full Member
  • ***
  • Posts: 160
    • Malzilla
Re: Unique Instance Terminate Application
« Reply #1 on: December 05, 2023, 10:21:37 pm »
This works for me in FormCreate:
Code: Pascal  [Select][+][-]
  1. if UniqueInstance1.PriorInstanceRunning then
  2.   begin
  3.     Close;
  4.   end;

And I also use this to bring the previous instance to the screen:
Code: Pascal  [Select][+][-]
  1. procedure TfrmMain.UniqueInstance1OtherInstance(Sender: TObject;
  2.   ParamCount: integer; const Parameters: array of string);
  3. begin
  4.   frmMain.WindowState := wsNormal;
  5.   frmMain.Show;
  6. end;
https://gitlab.com/bobby100 - my Lazarus components and units
https://sourceforge.net/u/boban_spasic/profile/ - my open source apps

https://malzilla.org/ - remainder at my previous life as a web security expert

Weitentaaal

  • Sr. Member
  • ****
  • Posts: 499
  • Weitental is a very beautiful garbage depot.
Re: Unique Instance Terminate Application
« Reply #2 on: December 06, 2023, 08:31:44 am »
This works for me in FormCreate:
Code: Pascal  [Select][+][-]
  1. if UniqueInstance1.PriorInstanceRunning then
  2.   begin
  3.     Close;
  4.   end;

And I also use this to bring the previous instance to the screen:
Code: Pascal  [Select][+][-]
  1. procedure TfrmMain.UniqueInstance1OtherInstance(Sender: TObject;
  2.   ParamCount: integer; const Parameters: array of string);
  3. begin
  4.   frmMain.WindowState := wsNormal;
  5.   frmMain.Show;
  6. end;

Hey thanks !

works for me too but how do i avoid the Code to continue executing ? The Close wont stop my Application from still loading. i but the same Check ("UniqueInstance1.PriorInstanceRunning") in my Mainform in the OnClose and OnDestroy Events but something will still get executed.

"And I also use this to bring the previous instance to the screen"

didn't thought about this ! thanks, i will use it.
Lazarus: 2.0.12 x86_64-win64-win32/win64
Compiler Version: 3.2.2

Zvoni

  • Hero Member
  • *****
  • Posts: 2237
Re: Unique Instance Terminate Application
« Reply #3 on: December 06, 2023, 08:45:57 am »
Hi,

i tried to use unique instance and put this in my on create of the main Form
Code: Pascal  [Select][+][-]
  1.    if UniqueInstance.PriorInstanceRunning then begin
  2.       //raise Exception.Create('Application already Running !');
  3.       ShowMessage('Application already Running !');
  4.       Close;
  5.       Exit;
  6.    end;
  7.  

i do always get Access Violations. How do i correctly Terminate Application?

"Exit" exits the Function/Procedure this code is in.
You're probably looking for "Terminate"
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

AlexTP

  • Hero Member
  • *****
  • Posts: 2353
    • UVviewsoft
Re: Unique Instance Terminate Application
« Reply #4 on: December 06, 2023, 09:41:46 am »
Code: Pascal  [Select][+][-]
  1. Application.Terminate; //better
or
Code: Pascal  [Select][+][-]
  1. Halt; //not good for GUI apps
« Last Edit: December 06, 2023, 09:47:23 am by AlexTP »

Thaddy

  • Hero Member
  • *****
  • Posts: 13987
  • Probably until I exterminate Putin.
Re: Unique Instance Terminate Application
« Reply #5 on: December 06, 2023, 10:34:09 am »
In my opinion testing for a Unique instance should be in the project.lpr file and before application.initialize and application.run are called.
In that case, though, you should not use showmessage, which relies on the LCL, but a native OS messagebox or not at all.
This pattern gives you the least amount of overhead.
Bail out as early as you can....
« Last Edit: December 06, 2023, 10:37:49 am by Thaddy »
Specialize a type, not a var.

Weitentaaal

  • Sr. Member
  • ****
  • Posts: 499
  • Weitental is a very beautiful garbage depot.
Re: Unique Instance Terminate Application
« Reply #6 on: December 06, 2023, 04:17:43 pm »
In my opinion testing for a Unique instance should be in the project.lpr file and before application.initialize and application.run are called.
In that case, though, you should not use showmessage, which relies on the LCL, but a native OS messagebox or not at all.
This pattern gives you the least amount of overhead.
Bail out as early as you can....

Thanks i didn't think of that. i will try to do it here
Lazarus: 2.0.12 x86_64-win64-win32/win64
Compiler Version: 3.2.2

Weitentaaal

  • Sr. Member
  • ****
  • Posts: 499
  • Weitental is a very beautiful garbage depot.
Re: Unique Instance Terminate Application
« Reply #7 on: December 06, 2023, 04:37:14 pm »
Added this Code to my lpr:

Code: Pascal  [Select][+][-]
  1.    if InstanceRunning then begin
  2.       Application.Terminate;
  3.       Exit;
  4.    end;
  5.  

i thought after "Application.Terminate" was executed, all the Code after it would be ignored. It did not so thats why i was using the Exit in the first place.
Lazarus: 2.0.12 x86_64-win64-win32/win64
Compiler Version: 3.2.2

Zvoni

  • Hero Member
  • *****
  • Posts: 2237
Re: Unique Instance Terminate Application
« Reply #8 on: December 06, 2023, 05:38:34 pm »
Added this Code to my lpr:

Code: Pascal  [Select][+][-]
  1.    if InstanceRunning then begin
  2.       Application.Terminate;
  3.       Exit;
  4.    end;
  5.  

i thought after "Application.Terminate" was executed, all the Code after it would be ignored. It did not so thats why i was using the Exit in the first place.
I‘d say that’s normal since it runs in its own thread and might have to do cleanup

Or just change your if clause to an if then else

If instance running then
  Terminate
Else
   Regular startup code
« Last Edit: December 06, 2023, 05:40:48 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

KodeZwerg

  • Hero Member
  • *****
  • Posts: 1998
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Unique Instance Terminate Application
« Reply #9 on: December 06, 2023, 09:03:58 pm »
I guess in .lpr file I would do like
Code: Pascal  [Select][+][-]
  1.   if not InstanceRunning then begin
followed by the basic code to initialize forms etc...
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

Weitentaaal

  • Sr. Member
  • ****
  • Posts: 499
  • Weitental is a very beautiful garbage depot.
Re: Unique Instance Terminate Application
« Reply #10 on: December 07, 2023, 07:38:49 am »
is it still possible to bring the already existing Application to screen when using the RAW version of it. Didn't find anything in the Unit itself.
Lazarus: 2.0.12 x86_64-win64-win32/win64
Compiler Version: 3.2.2

kwyan

  • New Member
  • *
  • Posts: 23
Re: Unique Instance Terminate Application
« Reply #11 on: December 07, 2023, 02:06:32 pm »
Because I want to bring the already existing Application to screen, I don't use I use EnumWindowsProc search for the existing Application and SetForegroundWindow API to set to Foreground.

Code: Pascal  [Select][+][-]
  1. program MySample;
  2.  
  3. var
  4.    HasUniqueProcess : boolean;
  5.    
  6. function EnumWindowsProc(wHandle: HWND; lParam: LPARAM): BOOL; export; stdcall;
  7. type
  8.    TWindowName = array[0..max_path] of WChar;
  9. var
  10.    cTitle : TWindowName;
  11.    sTitle : string;
  12. begin
  13.    Result := true;
  14.    cTitle := default(TWindowName);
  15.    GetWindowTextW(wHandle, cTitle, MAX_PATH);
  16.    sTitle := cTitle;
  17.    if sTitle='My Sample' then
  18.       begin
  19.          SetForegroundWindow(wHandle);
  20.          HasUniqueProcess := true;
  21.          Result := false;
  22.       end;
  23. end;
  24.  
  25. function UniqueInstance : boolean;
  26. begin
  27.    HasUniqueProcess := false;
  28.    EnumWindows(@EnumWindowsProc, 0);
  29.    Result := HasUniqueProcess;
  30. end;
  31.  
  32. begin
  33.    if not UniqueInstance then
  34.       exit;
  35.  
  36.    Application.Scaled := True;
  37.    Application.Initialize;
  38.    Application.CreateForm(TFrmMain, FrmMain); // FrmMain will set Main Form Caption to 'My Sample'
  39.    Application.Run;
  40. end.
  41.  

Any one have better solution?
« Last Edit: December 07, 2023, 02:08:39 pm by kwyan »

d7_2_laz

  • Sr. Member
  • ****
  • Posts: 466
Re: Unique Instance Terminate Application
« Reply #12 on: December 07, 2023, 03:45:21 pm »
Not easier, but interesting though (but i guess it's Windows only):
I'm using the proposal as from reply #7 in:
https://forum.lazarus.freepascal.org/index.php/topic,27927.msg173384.html#msg173384

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.

Lazarus 3.0 Win10 x64 FPC 3.2.2

kwyan

  • New Member
  • *
  • Posts: 23
Re: Unique Instance Terminate Application
« Reply #13 on: December 07, 2023, 04:15:20 pm »
So the magic is on folder name. I propose you change the Main Form Caption with folder name, e.g. : "My Sample (Folder1) " by using the following logic:

Code: Pascal  [Select][+][-]
  1. function GenCaptionWithFolder : string;
  2. var
  3.    StartupPath : string;
  4.    Index : integer;
  5. begin
  6.    StartupPath := ExtractFilePath(ParamStr(0));
  7.    if (Length(StartupPath)>0) and (StartupPath[Length(StartupPath)]='\') then
  8.       Delete(StartupPath, Length(StartupPath), 1);
  9.    Index := RPos('\', StartupPath);
  10.    if Index>0 then
  11.       Delete(StartupPath, 1, Index);
  12.    Result := 'My Sample (' + StartupPath + ')';
  13. end;
  14.  

Then you call this in Main Form activation:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormActivate(Sender: TObject);
  2. begin
  3.    Caption := GenCaptionWithFolder;
  4. end;  
  5.  

You also call this in EnumWindowsProc when you compare the process's title with this value.


d7_2_laz

  • Sr. Member
  • ****
  • Posts: 466
Re: Unique Instance Terminate Application
« Reply #14 on: December 07, 2023, 04:26:01 pm »
Previously I had temporarily considered this approach (via Caption), but didn't pursue it,
because i didn't want to be dependent on a form's caption for this. But that's surely a matter of taste of course. Fortunately multiple ways do exist ...
Lazarus 3.0 Win10 x64 FPC 3.2.2

 

TinyPortal © 2005-2018