Multiple instances of application

Administrator

VB.NET Forum Admin
Joined
Jun 3, 2004
Messages
1,462
Programming Experience
10+
I originally had my new app set to disallow multiple instances (.NET 2.0) in the application settings area. Now I decided I want to allow multiple instances, however, I want to warn that an instance is already running and present a yes/no dialog to continue the second instance or activate the running instance.

Anyone have any code to:

1) Detect if an instance of the application is running
2) Activate the running instance

Thx
 
Try this, it uses the applications Startup event that can be cancelled:
VB.NET:
Shared m As New Threading.Mutex(False, "Global\8450D92E-1779-43af-A761-647D0FFF8967")
 
Private Sub MyApplication_Startup(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
    If m.WaitOne(10, False) = False Then
        m.Close()
        If MessageBox.Show("another instance detected, continue?", "Confirmation", MessageBoxButtons.YesNo) = DialogResult.No Then
            e.Cancel = True
            Dim current As Process = Process.GetCurrentProcess
            Dim ps() As Process = Process.GetProcessesByName(My.Application.Info.AssemblyName)
            For Each p As Process In ps
                If p.Id <> current.Id Then
                    AppActivate(p.Id)
                    Exit For
                End If
            Next
        End If
    End If
End Sub
"Global\" means the Mutex goes for all sessions (logged in users) on machine, use "Local\" if single-instance for current user is preferred.
 
I thought that the "Application Framework" tickbox enabled a suite written by the VB guys that, among other things, causes the ORIGINAL app to receive an event when another instance is attempted. The command line parameters are passed and the original app can do whatever.

Essentially the first app starts a remoting server. Subsequent attempts fail to bind to the remoting port for that app because it is already in use, so the existing server is notifed of command line args etc.

I wrote an app to leverage this, here's the code:
VB.NET:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;
using System.Drawing;
using System.Runtime.InteropServices;
 
 
namespace StartBay
{
  static class Program
  {
 
    [DllImport("mpr.dll")] private static extern int WNetRestoreConnectionW(int phWnd, string psLocalDrive);
 
    static MainForm mf;
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
 
 
      WNetRestoreConnectionW(0, null);
 
      bool backgroundMode =
        (args != null && args.Length == 1 && args[0].Equals("/background")) /*|| cmdLine.Contains("background=true")*/;
 
 
      try {
        mf = new MainForm();
        FormAnimation.FormAnimator fa = 
                new FormAnimation.FormAnimator(mf, FormAnimation.FormAnimator.AnimationMethod.Blend, 250);
 
        SingleInstanceApplication.Run(mf, [B]StartupNextInstanceHandler[/B], backgroundMode);      
      } catch(Exception e) {
 
        if(!backgroundMode){
          string targMsg = "removed";
          MessageBox.Show("removed");
        }
      }
 
 
    }
 
[B]  static void StartupNextInstanceHandler(object sender, StartupNextInstanceEventArgs e)[/B]
[B]  {[/B]
[B]    e.BringToForeground = true;[/B]
[B]    if(!mf.Visible)[/B]
[B]      mf.Show();[/B]
[B]    else[/B]
[B]      mf.BringToFront();[/B]
 
[B]    mf.ShowNIDAdviceBalloon();[/B]
[B]  }[/B]
[B]}[/B]
 
  public class SingleInstanceApplication :[B]WindowsFormsApplicationBase[/B]
  {
    private SingleInstanceApplication()
    {
      base.IsSingleInstance = true;
      base.ShutdownStyle = ShutdownMode.AfterMainFormCloses;
      base.EnableVisualStyles = true;
    }
 
    public static void Run(Form f, StartupNextInstanceEventHandler startupHandler, bool startHidden)
    {
      SingleInstanceApplication app = new SingleInstanceApplication();
      [B]app.StartupNextInstance += startupHandler;[/B]
      if(startHidden)
        f.Location = new Point(-32000, -32000);
      else {
        Rectangle scrn = Screen.GetWorkingArea(f);
        f.Location = new Point((scrn.Width - f.Width) / 2, (scrn.Height - f.Height) / 2);
      }
 
 
      app.MainForm = f;
      app.Run(Environment.GetCommandLineArgs());
    }
  }
}

It's C# but the interesting parts for you are in bold. Your application (My.Application) should already be an instance of WindowsFormsApplicationBase.
This means if you add a handler to the My.Application.StartupNextInstance event then that event will fire when someone attempts to start a second instance

In my code here I handle this with the bold method static void StartupNextInstanceHandler

In your code I guess it would be something like writing a method of the same signature that my static void StartupNextInstanceHandler has, and then AddHandler-ing it to attach it to My.Application.StartupNextInstance

All I do with it are bring the existing instance to the forground and show it. Also, if the user started a second instance I popup a little ballon saying something like "It's faster to double click me in the tray, to activaste the xisting instance, than it is to start a new copy"

The StartupEventArgs object should have e.g. the command line args and remember this way it is the ORIGINAL app that experiences this event which gives you more control than the secondary app merely being able to activate..
 
That is true and should be used if you want single-instance only app and also want to handle attempts at next instances, but Neal asked here for a solution for handling multi-instance app with option to allow or not this. (which option single-instance does not have)
 
you 100% correct! :D

Looks like i coulda saved myself a whole load of touchtyping practice if i'd read the actual question

cjard.Rename("spanner")

:D
 
Back
Top