Sometimes you want to only allow for a single instance of your application and that can be accomplished by using a Mutex class. On top of that, if it’s used on a Terminal Server / Citrix, you also want to check the session id, to ensure you’re not interfering with other user’s instances or even the same user on a different connection.
EDIT: On a second read, the SID might not be needed in the mutex name, as by default the mutex is local, unless told otherwise, see note below:
http://msdn.microsoft.com/en-us/library/system.threading.mutex.aspx
* * *
   [DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); 
 
[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool SetForegroundWindow(IntPtr hWnd);
 
// Constants 
const int SW_RESTORE = 9;
 
/// <summary> 
/// The main entry point for the application. 
/// </summary> 
[STAThread] 
static void Main() 
{ 
  // 
  // Use a Mutex to allow only one instance per session...  
  // 
  bool   newInstance = true; 
  String mutexId     = String.Format("APP={0}; SID={1}",
                                     Assembly.GetExecutingAssembly().GetName().Name, 
                                     System.Diagnostics.Process.GetCurrentProcess().SessionId); 
 
  Mutex mutex = new System.Threading.Mutex(true, mutexId, out newInstance);  
  if (!newInstance) {
    MessageBox.Show("Application Already Running!" + mutexId);
 
    // Find the instance holding the mutex and restore...  
    Process currentProcess = Process.GetCurrentProcess();  
    foreach (Process process in Process.GetProcessesByName(currentProcess.ProcessName))  
    {  
      if (process.Id        != currentProcess.Id &&  
          process.SessionId == currentProcess.SessionId)  
      { 
        // Restore window (if minimized)... 
        ShowWindow(process.MainWindowHandle, SW_RESTORE); 
 
        // Set foreground window... 
        SetForegroundWindow(process.MainWindowHandle);
 
        break;  
      }  
    }  
    return;  
  }
 
  //  
  // Run normal...  
  //  
  Application.EnableVisualStyles();  
  Application.SetCompatibleTextRenderingDefault(false);  
  Application.Run(new MainForm()); 
 
  //
  // Hold the mutex from being garbage collected... 
  //
  GC.KeepAlive(mutex);
}
Resources:

thank you so much, this code help me to create a very good solution
ReplyDeleteYou might want to cut the lines:
ReplyDelete// Hold the mutex from being garbage collected...
GC.KeepAlive(mutex);
And paste them at the bottom of this method - KeepAlive() only promises to keep the object alive *until* this particular call and not after it.
Reference:
http://msdn.microsoft.com/en-us/library/system.gc.keepalive.aspx
Thanks for that, I've changed the code, although I've seen it work fine before, it makes sense though to change it.
ReplyDeleteWorks great but how do I restore a window from the system tray?
ReplyDeleteIf your window was hidden, you might want to call ShowWindow(hwnd, SW_SHOW) instead or prior to SW_RESTORE.
ReplyDeleteSee if the comments at ShowWindow page help:
http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx
It helped me. great work
ReplyDeleteNavan M