Page 1 of 2

Conditional check if program is running

Posted: Tue May 03, 2022 8:43 pm
by doctorized
I make an app that reads and writes data to a db. I want to be able to have only one instance of my app running from the current directory.
At program startup, I want to check for other instances. If instance found from the current directory, exit. If instance found from another directory, continue. I found some codes here in this forum but I am having hard tome to make it work as I want to.
The code is:

Code: Select all

Global ProductID$ = GetCurrentDirectory() + "MyApp"
Global Mutex = CreateMutex_(0,1,@ProductID$)

If Mutex = 0 Or GetLastError_() = 183;ERROR_ALREADY_EXISTS
	MessageRequester("","Program already running!",#MB_ICONERROR)
Else
	MessageRequester("","No other instances.",#MB_ICONINFORMATION)
EndIf
Using GetCurrentDirectory() brings GetLastError_() with 183. Without it, it runs finding instances from other directories. Any ideas?

Re: Conditional check if program is running

Posted: Tue May 03, 2022 9:06 pm
by Jeromyal

Code: Select all

UseMD5Fingerprint()

ProcedureDLL.l Instance_Mutex(Lock.s)
  Protected *Mutex
  *Mutex = CreateMutex_(#Null, 1, Lock)
  If *Mutex <> 0 And GetLastError_() = #ERROR_ALREADY_EXISTS
    CloseHandle_(*Mutex)
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure

If Instance_Mutex(FileFingerprint(ProgramFilename(), #PB_Cipher_MD5)) 
  End 0
EndIf
You can place what ever you want in the procedure call instead of the md5 checksum I used. such as...

Code: Select all

if Instance_Mutex(ProgramFilename())
so that should do exactly what you desire.

Re: Conditional check if program is running

Posted: Wed May 04, 2022 1:22 am
by BarryG
Don't use GetCurrentDirectory() as part of the mutex name, because that directory can be changed at runtime. Just use a unique static name that doesn't depend on runtime data. Even Jeromyal's version can fail if an older build of the exe is run at the same time as a newer, because the MD5 checksums of both exes won't match; thus allowing two instances to be run.

Re: Conditional check if program is running

Posted: Wed May 04, 2022 5:44 am
by Jeromyal
BarryG wrote: Wed May 04, 2022 1:22 am Don't use GetCurrentDirectory() as part of the mutex name, because that directory can be changed at runtime. Just use a unique static name that doesn't depend on runtime data. Even Jeromyal's version can fail if an older build of the exe is run at the same time as a newer, because the MD5 checksums of both exes won't match; thus allowing two instances to be run.
Valid points BarryG.
But what I understand from his post, He just does not want the current running application to be able to run from the same location as multiple instances yet be able to launch another instance as long as it is executed from a different directory. Perhaps my suggestion is unwise? I can not think of another way other than passing the applications path as the mutex string to do what he describes.
I am defiantly someone who is apt to do very unconventional things because frankly I am just an unprofessional hobbyist hack.

Re: Conditional check if program is running

Posted: Wed May 04, 2022 7:12 am
by BarryG
You're right about the external vs same directory launch - I overlooked that, sorry. Your way would fine in that case.

Re: Conditional check if program is running

Posted: Wed May 04, 2022 7:47 am
by Keya
as pointed out, don't use GetCurrentDirectory() as it can change. This returns the base directory of your process file location:

Code: Select all

AppDir$ = GetPathPart(ProgramFilename())
Debug AppDir$

Re: Conditional check if program is running

Posted: Wed May 04, 2022 8:22 am
by AZJIO
I can't find a link to the original (netmaestro).

Code: Select all

Define *a = CreateSemaphore_(#Null, 0, 1, ProgramFilename())
If *a And GetLastError_() = #ERROR_ALREADY_EXISTS
	CloseHandle_(*a)
; 	MessageRequester("","The program is already running")
	End
EndIf

Re: Conditional check if program is running

Posted: Wed May 04, 2022 8:31 am
by BarryG
Jeromyal wrote: Wed May 04, 2022 5:44 amHe just does not want the current running application to be able to run from the same location
I just remembered that the user could copy and rename the copy in the same directory, so the MD5 hashes won't match and multiple instances can therefore be run from the same location.

Re: Conditional check if program is running

Posted: Wed May 04, 2022 3:25 pm
by Jeromyal
BarryG wrote: Wed May 04, 2022 8:31 am
Jeromyal wrote: Wed May 04, 2022 5:44 amHe just does not want the current running application to be able to run from the same location
I just remembered that the user could copy and rename the copy in the same directory, so the MD5 hashes won't match and multiple instances can therefore be run from the same location.
Yeah that defiantly could cause trouble. Perhaps he should also test for a change in the name for safety?

Code: Select all

If GetFilePart(ProgramFilename()) <> "MyApp.exe"
  ; I don't know who I am anymore.
  End
EndIf
The MD5 does raise too many problems than it solves. I realized that with my own program I made and switched to a static string instead for my own latest build. Thanks to you bringing it to my attention BerryG

Re: Conditional check if program is running

Posted: Wed May 04, 2022 7:07 pm
by doctorized
BarryG is right. I did not think of previous versions. I will try to help you guys by saying that what I really want is having only one app using the db. Why should a user run and use twice an app? I do not know. I want to avoid running multiple versions and instances of my app using the same db. That's why I talked about different folder in my initial post.

Re: Conditional check if program is running

Posted: Wed May 04, 2022 9:46 pm
by freak
Your original code did not work because a backslash is not allowed in the mutex name:
The name can have a "Global" or "Local" prefix to explicitly create the object in the global or session namespace. The remainder of the name can contain any character except the backslash character (\).
See https://docs.microsoft.com/en-us/window ... eatemutexa

The code by Jeromyal avoids that by using the fingerprint of the path instead. Any other method to replace the backslash would probably work as well.

Re: Conditional check if program is running

Posted: Thu May 05, 2022 1:17 am
by BarryG
doctorized wrote: Wed May 04, 2022 7:07 pmWhy should a user run and use twice an app?
Depends what it does. Think of an image viewer, or word processor, or web browser, or even PureBasic. They all need to be run more than once.

Re: Conditional check if program is running

Posted: Thu May 05, 2022 4:21 am
by AZJIO
freak wrote: Wed May 04, 2022 9:46 pmbackslash is not allowed

Code: Select all

Define *a = CreateSemaphore_(#Null, 0, 1, ReplaceString(ProgramFilename(), "\", ":"))
If *a And GetLastError_() = #ERROR_ALREADY_EXISTS
	CloseHandle_(*a)
	MessageRequester("","The program is already running")
	End
EndIf

If OpenWindow(0, 0, 0, 220, 100, "One copy...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

Re: Conditional check if program is running

Posted: Fri May 06, 2022 4:01 pm
by doctorized
AZJIO's code with GetCurrentDirectory() instead of ProgramFilename() solves my problem. I cannot use ProgramFilename() as every executable has the version number in its name, at least till now. Thank you very much for your time and answers!

Re: Conditional check if program is running

Posted: Fri May 06, 2022 4:36 pm
by Marc56us
doctorized wrote: Fri May 06, 2022 4:01 pm AZJIO's code with GetCurrentDirectory() instead of ProgramFilename() solves my problem. I cannot use ProgramFilename() as every executable has the version number in its name, at least till now. Thank you very much for your time and answers!
Numbered programs often start with the same prefix, so only one line is needed

Code: Select all

If GetFilePart( Left( ProgramFilename( ) ), 5) <> "MyApp"