Detect if application is already open

Is there a way to test if the application is already open so as to prevent a second instance from being opened?

I have two ideas, but I want to see if there is a proven method.
Idea 1:
Have a simple table in the database with a single field that is updated when the application is opened. And that when the application opens the first query is to see if the table.field is set.

Idea 2:
When the application opens it creates a file. This file is searched for during the open phase and if it exists then a second instance will not open. If it doesn’t then the application will open.

I am thinking there is a method to look at memory maybe?

http://documentation.xojo.com/api/language/mutex.html

1 Like

As I understand it, this is only an issue on Windows as MacOS will handle this for you. In the Windows version of my app, I use the Mutex features in MBS to listen for and switch to an already running instance of my app.

macOS kind of handles this for you. A user can launch multiple instances of your app with open -n MyApp.app and you’ll get more than one. So if you really need to enforce one instance only, you’ll still want to use the Mutex.

1 Like

And if the app crashes or the user kills the process, the field will not be restored nor the file deleted. Great way to prevent your app to work again.

As Andrew said, the best option is with the mutex

Hi John,

  1. In the App add the property
    mMutex As Mutex

  2. in the event handler App.Open add the following code:
    mMutex = New Mutex(App.ExecutableFile.Name)
    If Not mMutex.TryEnter Then
    MessageBox(“Application already running”)
    Quit
    End If

  3. in the event handler App.Close add the following code to release the mutex
    If mMutex <> Nil Then
    mMutex.Leave
    End If

// ------------------

Best regards

3 Likes

Or, instead of a dialog, bring the running app to the front.

How?

Send a message via IPCSocket and call Show on the window in the main app.

If needed, we can help with WindowsPipeMBS class or the ActivateWindowMBS function in MBS Xojo Plugins.

Hey, I’m just the idea guy. :slight_smile:

I don’t have code for this, sorry.

2 Likes

//Bringing already running application to the front
dim w as new WindowsListMBS
dim i,c as integer
c=w.WindowCount-1
for i=0 to c
if w.WindowText(i) = “Name of the window title of your application” then
w.ActivateWindow(i)
end if
next
//-----------------------------------

1 Like

Thank you for the shout out for mutex… I’ll try that in a bit. Just FYI… I don’t write for or use Microsoft Windows or Apple Macintosh… I am and have been a Linux guy only since 1999.

The above code (Bringing already running application to the front) works for Microsoft Windows only.

The IPCSocket solution works cross platform and is a great idea!

This code is a bit better, it brings all windows of your already running application to the front:

//-----------------------------------
dim w as new WindowsListMBS
dim i,c as integer
c=w.WindowCount-1
for i=0 to c
  if w.WindowImageFileName(i).IndexOf(App.ExecutableFile.Name)>-1 AND w.WindowText(i).Length>0 AND w.WindowClassName(i)="RBWindow" then
    w.ActivateWindow(i)
  end if
next
//-----------------------------------

This is the code I use in App.Open, from https://github.com/thommcgrath/Beacon/blob/master/Project/App.xojo_code

		  Var Lock As New Mutex("com.thezaz.beacon" + If(DebugBuild, ".debug", ""))
		  If Not Lock.TryEnter Then
		    #If TargetWin32
		      Var StartTime As Double = System.Microseconds
		      Var PushSocket As New IPCSocket
		      PushSocket.Path = Self.ApplicationSupport.Child("ipc").NativePath
		      PushSocket.Connect
		      Do Until PushSocket.IsConnected Or System.Microseconds - StartTime > 5000000
		        PushSocket.Poll
		      Loop
		      If PushSocket.IsConnected Then
		        PushSocket.Write(System.CommandLine + Encodings.UTF8.Chr(0))
		        Do Until PushSocket.BytesLeftToSend = 0 Or System.Microseconds - StartTime > 5000000
		          PushSocket.Poll
		        Loop
		        PushSocket.Close
		      End If
		    #EndIf
		    
		    Quit
		    Return
		  Else
		    Self.mMutex = Lock
		    #If TargetWin32
		      Self.mHandoffSocket = New IPCSocket
		      Self.mHandoffSocket.Path = Self.ApplicationSupport.Child("ipc").NativePath
		      AddHandler Self.mHandoffSocket.DataAvailable, WeakAddressOf Self.mHandoffSocket_DataReceived
		      AddHandler Self.mHandoffSocket.Error, WeakAddressOf Self.mHandoffSocket_Error
		      Self.mHandoffSocket.Listen
		    #EndIf
		  End If

So basically, if it gets the mutex, listen for an IPC connection. If it doesn’t, pass the command line parameters to the running instance.

why is there a section for targetwin32 but nothing for targetmac??

Not really necessary on Mac.

1 Like

on mac, the default behavior for a variety of actions (double-clicking the app icon, dragging a file onto the app icon in the finder, double-clicking a file, and probably a few others I’m forgetting) is to use the already-running app.

On windows, many of these cases launch a second copy of the app, which is generally not what the user wanted.