Page 1 of 2

Very simple single instance test

Posted: Thu Jul 03, 2008 8:02 pm
by Blue
I was looking for a short and sweet way to test if my application was already running.
After reading blueznl's inspired and clear explanation of mutex, i came up with the following which works real fine.

If you remove the macros, comments and messages, you'll see how ridiculously simple it really is:

Code: Select all

Macro eol
   Chr(13) + Chr(10)
EndMacro
Macro MsgBox(msg = "J'attends...", titre = "information")
    MessageRequester(titre, msg, 0)
EndMacro

EnableExplicit

Define.L error, hMutex
Define.S msg, mutex_name

; we attempt to open a named mutex
mutex_name = "Single_Instance_Test"
hMutex = OpenMutex_(#MUTEX_ALL_ACCESS,0,@mutex_name)

If hMutex <> 0
  msg = " We were able to open the mutex object: " + Str(hMutex)
  msg + eol + " We therefore know that it exists, and our application too."
  msg + eol + " So, we simply leave quietly..." + eol 
  MsgBox(msg, "Discovering our mutex "+Str(hMutex))

else
  msg = " Opening the mutex failed."
  msg + eol + " Therefore, neither it nor our appplication exist."
 
  ; we'll remedy that right now . First the mutex:
  hMutex = CreateMutex_(0,0,@mutex_name)
  
 ; then the application :
  If OpenWindow(0,100,150,450,200,"Testing mutex " + Str(hMutex), #PB_Window_SystemMenu) 
    msg + eol + " We create it ("+Str(hMutex)+") as we launch our application..." + eol
    MsgBox(msg,"Creating mutex "+Str(hMutex))
 
    Define.L event
    Repeat 
      event=WaitWindowEvent() 
    Until event=#PB_Event_CloseWindow 
  EndIf

EndIf

If hMutex <> 0		; which should be always
  CloseHandle_(hMutex) 
EndIf
End

Any similiraty to blueznl's and Berikco's code is intentional !
Their code pointed me in the right direction...
(Berikco code is here, down the middle of the page)

The drawback to the above is that the running instance of the application does not jump to the front, whereas Berikco's method ensured that happened.

Anybody know a good, simple way to force an application to the front ? (if i'm going to understand, it HAS to be simple!) :lol:

Posted: Thu Jul 03, 2008 8:47 pm
by akj
Here's the method I have used successfully for ages:

Code: Select all

Procedure AlreadyRunning() ; AKJ  30-Jan-07
; Ensure the current program is not already running
; Terminate this process if it is
; Uses #Program$
Protected app, msg$
app=CreateSemaphore_(0,0,1,"AKJ "+#Program$)
If app<>0 And GetLastError_()=#ERROR_ALREADY_EXISTS
  CloseHandle_(app) ; This line can be omitted
  msg$="The "+#Program$+" program is already running."+#CRLF$+#CRLF$
  msg$+"This process will terminate."
  MessageRequester(#Program$+" Error", msg$, #MB_ICONERROR)
  End
EndIf 
EndProcedure
It requires the constant #Program$ to be assigned a value, which it is in every program I write.

Posted: Thu Jul 03, 2008 8:59 pm
by Kaeru Gaman
If you remove the macros, comments and messages, you'll see how ridiculously simple it really is:
ermn... sorry...
but why don't you remove the unneccessary things yourself to show us how simple it is?

I don't need a Macro to replace #CRLF$...

Posted: Thu Jul 03, 2008 10:13 pm
by Blue
akj wrote:Here's the method I have used successfully for ages:

Code: Select all

Procedure AlreadyRunning()
[...]
Yesssssss... Amazingly simple and efficient.
Thanks for sharing a good idea, akj.
I really like your solution.

It's intimidating how many useful API routines exist that I know nothing about... thanks for making me discover yet another very useful one.

Now, any equivalent smart procedure in your bag of goodies for forcibly shifting the focus on the running applications's window ?
You give me that and I can go on holidays, leaving the programming entirely to you ! :lol:

Thanks for sharing an excellent idea.

Posted: Thu Jul 03, 2008 10:29 pm
by Blue
Kaeru Gaman wrote:[...]
ermn... sorry...
but why don't you remove the unneccessary things yourself to show us how simple it is?
I don't need a Macro to replace #CRLF$...
ermn... sorry... :shock: :oops:
The thing is, however, that I DO.

But, yeah, [removed impatient and idiotic answer] :oops: ... you raise a valid point.

I sometimes forget to KISS ! *


* keep it simple, stupid !

Re: Very simple single instance test

Posted: Thu Jul 03, 2008 10:31 pm
by PB
This is all I use at the start of my source:

Code: Select all

If CreateMutex_(0,1,"MyAppName")=0 Or GetLastError_()<>0 : End : EndIf
Can't get much simpler than that. :)

> Anybody know a good, simple way to force an application to the front ?

http://www.purebasic.fr/english/viewtopic.php?t=7105

Re: Very simple single instance test

Posted: Thu Jul 03, 2008 10:34 pm
by Blue
PB wrote:This is all I use at the start of my source:

Code: Select all

If CreateMutex_(0,1,"MyAppName")=0 Or GetLastError_()<>0 : End : EndIf
Can't get much simpler than that. :)
Agreed. Can't be beaten for simplicity AND brevity.
Thanks PB.
But don't you HAVE to clean up after creating a mutex ?
Won't you be creating a leak or something ?
Anyhow, I admire the compactnes of your code.

PS: And thanks for the link as well. It's Right On ! I never thought of searching for "re-activate window" :oops:

Posted: Thu Jul 03, 2008 11:41 pm
by Kaeru Gaman
you got me completely wrong.

...is there a contest out there? the one who gets Kaeru most wrong wins a barrel gasoline?

I'm interested in your solution and in your code...
but if you want to show other how short and simple it is,
why don't you post it short and simple?
most of us like to read a code and understand what it does,
and it helps if it's kept simple and additional things left out.

you want to present something?
well, you need to catch your audiences interest,
and you don't do that by hiding the more interesting parts
of your idea between macros and messages as you said yourself.

and why do you bother writing a macro "eol",
when you just can use the implemented constant #CRLF$?

Posted: Fri Jul 04, 2008 12:50 am
by pdwyer
Kaeru Gaman wrote:you got me completely wrong.

...is there a contest out there? the one who gets Kaeru most wrong wins a barrel gasoline?
You win then for getting the Kanji in your name wrong :twisted:


(you did come across a little harsh)

Posted: Fri Jul 04, 2008 1:50 am
by Inf0Byt3
I do this to prevent the app running twice. If you launch the app a second time, your program's window will just restore on the screen like on 'professional' apps. Compile the code as an exe, then run it, minimize the window and run it again.

Code: Select all

Procedure.l FindPartWin(Part.s)
 ;
 ;by SFSxOI???
 ;http://www.purebasic.fr/english/viewtopic.php?t=25489
 ;
 Window = GetWindow_(GetDesktopWindow_(),#GW_CHILD)
 ;
 Repeat
  WindowName.s = Space(999) 
  GetWindowText_(Window,WindowName,999)
  If FindString(WindowName,Part,0) <> 0 And IsWindowVisible_(Window)=#True
   Win = Window
  Else
   Window = GetWindow_(Window,#GW_HWNDNEXT)
  EndIf
 Until Window = 0 Or Win <> 0
 ;
 ProcedureReturn Win
 ;
EndProcedure 

;Some globals here :P
Global IB_MutexName.s = "My Cool PureBasic Program",IB_hMutex

;The mutex right before opening the window
IB_hMutex = CreateMutex_(0, 0, @IB_MutexName)
If GetLastError_() = #ERROR_ALREADY_EXISTS
 IBHwnd = FindPartWin("My Cool PureBasic Window")
 If IBHwnd <> 0
  SendMessage_(IBHwnd,#SW_SHOWNORMAL,0,0) 
  ShowWindow_(IBHwnd,#SW_RESTORE)
  ShowWindow_(IBHwnd,#SW_SHOW)
  SetForegroundWindow_(IBHwnd)
  End
 EndIf
EndIf

;DEMO :)
If OpenWindow(0, 100, 200, 195, 260, "My Cool PureBasic Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)

  Repeat
    EventID = WaitWindowEvent()

    If EventID = #PB_Event_CloseWindow
      Quit = 1
    EndIf

  Until Quit = 1
  
EndIf

End
I hope it'll be useful :).

Posted: Fri Jul 04, 2008 3:17 am
by Blue
Inf0Byt3 wrote:[...] ...your program's window will just restore on the screen [...]
I hope it'll be useful :).
It will be, no doubt... if only for the abundance of API calls it demonstrates.
Ah !!! That elusive GetWindowText_(). I knew it existed, but couldn't remember its proper name.
The idiotic search function of the Windows SDK never got me even close to the correct name.

So, Thank you, Inf0Byt3.

Plus, as you suggest, your fancy solution is indeed very nicely behaved.
A full notch above what I could hope to achieve by myself !

Posted: Fri Jul 04, 2008 4:06 am
by Blue
Kaeru Gaman wrote:you got me completely wrong.

...is there a contest out there? the one who gets Kaeru most wrong wins a barrel gasoline?
[...]
and why do you bother writing a macro "eol",
when you just can use the implemented constant #CRLF$?
Sorry, Kaeru Gaman, for having joined the hordes of Kaeru Gaman bashers out there.
But where exactly do you say I can claim my barrel of black gold?
I do admit that I did get a little hot around the collar when I read your contribution, and, for that, I apologize.

Why eol rather the implemented constant #CRLF$? :shock:
Obviously for many important reasons, among which...
(1)
i did not know about the constant having been implemented (Thanks for the tip.)
(2) typing 3 common lower case letters on a FR-CA keyboard is a lot faster than typing #CRLF$
(3) i use the custom keyword feature of the PB IDE to color eol and make it stand out. I can't do that with constants because of their prefixed pound character.
(4) I'm over 50 + 10, and therefore very set in deep-rooted programming habits accumulated since 1978. I now find it unfortunately very hard to learn new tricks, believe me. That's also why I usually write constants before variables in comparisons (as in if 3 = number rather than if number = 3 , for instance)
(5) when I copy my code on the forum, i just can't be bothered to replace my silly macros with more serious non-silly and approved ways of writing out classy code.
(6) because i find eol more pretty than #CRLF$
(7) and, finally, the most compelling of them all: because !

That's all I could think of right now, but I hope I have you convinced of the imperative necessity to amend your ways and convert to MY time-proven code-writing fashion.

Should something more come to mind during the night, i'll make sure to add it in at the bottom, later.

And, again, I apologize to you and swear on Fred's compiler to never ever bash you again, Kaeru Gaman. Promise. :lol:

Posted: Fri Jul 04, 2008 6:54 am
by blueznl
(7) and, finally, the most compelling of them all: because !
My favourite reason! :-)

Re: Very simple single instance test

Posted: Fri Jul 04, 2008 10:30 am
by PB
> don't you HAVE to clean up after creating a mutex ?

Not really. From the MSDN docs for CreateMutex:

The system closes the handle automatically when the process terminates.

So, I just let the OS do the cleaning for me. ;) Been working fine for me for
many years with no leaks, so I'd say it's pretty much stable, as documented.

Posted: Fri Jul 04, 2008 11:24 am
by Hroudtwolf
Hi,

Here is my little suggestion for "single instances".

Code: Select all

; Single instances
; 2008 Hroudtwolf
; PureBasic-Lounge.com
; PureBasic 4.x
; Windows (2000+)

Procedure CheckForSingleInstance ( sAppname.s )
   Protected lFileID.l  
   
   sAppname = "\\.\mailslot\ms_" + sAppname
   
   lFileID = ReadFile (#PB_Any , sAppname )
   If lFileID
      CloseFile (lFileID)
      ProcedureReturn #False
   EndIf
   
   CreateMailslot_( @ sAppname , #Null , #Null , #Null )
   
   ProcedureReturn #True
EndProcedure

Procedure FreeSingleInstance ( sAppname.s )
   ProcedureReturn DeleteFile ( "\\.\mailslot\ms_" + sAppname )
EndProcedure

;--- Test

OpenConsole ()
If CheckForSingleInstance ( "myapp" )
   PrintN ( "Programm started." )
Else
   PrintN ( "Sorry. There is already an instance of this application." )
EndIf
Input ()
FreeSingleInstance ( "myapp" )
CloseConsole ()
Best regards

Wolf