8

I often write .net applications that only support one instance. Formerly I used .net-remoting and now WCF to detect if already an instance of my app is running and giving the focus to this instance.

My question is, if there is with .net4 a better solution available to achieve single instance applications (or is there in general a better solution available, because loading the WCF or remoting assembly at the very start of the application has a bad performance influence)

Update

Thanks for all the post. The answer to my initial question seems to be “no, there is nothing new to achieve single instance applications within .net 4”.

Thanks to all the additional information, I will change my current projects to use a Mutex to provide the desired functionality. I accepted the answer of Bob Moore because it has the most information attached to it, but thanks to all who posted useful information.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
HCL
  • 36,053
  • 27
  • 163
  • 213
  • 1
    nothing special for .net 4. wcf and remoting sound like huge overhead for such simple task – Andrey Jul 09 '10 at 09:58
  • possible duplicate of [What is the correct way to create a single instance application?](http://stackoverflow.com/questions/19147/what-is-the-correct-way-to-create-a-single-instance-application) – ChrisF Jul 09 '10 at 10:12
  • @Andrey: Yes indeed, its overhead, but I have to say that in most of theses apps I use WCF/Remoting anyway, this justifies the usage of them. But the point in time the assembly is loaded is bad because it extends the time the application takes to be loaded/initialized. – HCL Jul 09 '10 at 10:20
  • you should use mutex, as it is described in Bob Moore's answer. It is robust and fast. – Andrey Jul 09 '10 at 11:09
  • @Andrey so I will do. Thanks. – HCL Jul 09 '10 at 11:22

4 Answers4

11

The traditional way to do this is with a mutex, e.g.

bool bNew = true; 
using (Mutex mutex = new Mutex(true, "MYAPP_0D36E4C9-399D-4b05-BDA3-EE059FB77E8D", out bNew))
{
   if (bNew)
   {
       // blah, blah,
       Application.Run(new MainForm());
   }
}

Edit:

I found this code to invoke SetForegroundWindow online, so you can find the other instance of your app and bring it forward:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);


Process me = Process.GetCurrentProcess();
foreach (Process process in Process.GetProcessesByName (me.ProcessName))
{
   if (process.Id != me.Id)
   {
      SetForegroundWindow (process.MainWindowHandle);
      break;
   }
}

Note that in modern Windows implementations you can only give the foreground away.

Bob Moore
  • 6,788
  • 3
  • 29
  • 42
  • 1
    A Mutex can be per session or machine wide. – GvS Jul 09 '10 at 10:00
  • And how to activate the existing Application (Give Focus)? PInvoke? – HCL Jul 09 '10 at 10:03
  • 3
    I believe each terminal server session has a private namespace for kernel objects. I suggest you read www.flounder.com/nomultiples.htm for a more comprehensive background. That's a native code site, but you need to understand the principles if you're venturing this far down into the innards... – Bob Moore Jul 09 '10 at 10:06
  • I see others have pointed you at the global/local flags. Of course, it depends on what you mean by "work for terminal server". You can set it up to only allow one instance on a single physical machine, or on a single terminal. – Bob Moore Jul 09 '10 at 10:23
  • btw, it's rather better to extract `[assembly: Guid]` value than hardcode someone – abatishchev Aug 23 '10 at 07:13
2

I use a Mutex, and FindWindow to do this.

Concerning your comment on another answer:
For information on Local and Global mutexes in Terminal Services, follow this link.

Terminal Services client processes can use object names with a "Global\" or "Local\" prefix to explicitly create an object in the global or session name space.

This is the code I use to activate the window:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsIconic(IntPtr hWnd);

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int SH_SHOW = 5;
private const int SH_RESTORE = 9;

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);

public void Activate(IntPtr hwnd)
{
    if (IsIconic(hwnd))
        ShowWindow(hwnd, SH_RESTORE);
    else
        ShowWindow(hwnd, SH_SHOW);

    SetForegroundWindow(hwnd);
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
GvS
  • 52,015
  • 16
  • 101
  • 139
2

There's a simpler way - with help of WindowsFormsApplicationBase class from Microsoft.VisualBasic.ApplicationServices:

using System;
using System.Collections.Generic;

public class SingleInstanceApplicationWrapper :
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase 
{
  public SingleInstanceApplicationWrapper()
  {
    IsSingleInstance = true;
  }

  private MyApp m_app;
  protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
  {
    // here we create our WPF application
    m_app = new MyApp();
    m_app.Run();
    return false;
  }

  protected override void OnStartupNextInstance(Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e)
  {
    m_app.DispatchCommandLineParams(e.CommandLine);
  }
}

public class MyApp : System.Windows.Application
{
  protected override void OnStartup(System.Windows.StartupEventArgs e)
  {
    base.OnStartup(e);
    DispatchCommandLineParams(e.Args);
  }
  public void DispatchCommandLineParams(IEnumerable<string> cmdParams)
  {
    // process command line parameters
    Console.WriteLine(this.GetHashCode() + " - dispatched");
  }
}
public class Program
{
  [STAThread]
  public static void Main(string[] args)
  {
    var wrapper = new SingleInstanceApplicationWrapper();
    wrapper.Run(args);
  }
}
Shrike
  • 9,218
  • 7
  • 68
  • 105
-2

I would suggest Singleton-Pattern. Look at this (example for VB.net!):http://vbnotebookfor.net/2007/09/13/introduction-to-the-singleton-pattern-in-vbnet/

Greetz

Husky110
  • 723
  • 2
  • 10
  • 27
  • Sorry, I dont't understand how it helps? The singleton pattern works in the applications domain but not over different processes. – HCL Jul 09 '10 at 10:07