May 29, 2016

In this article I will explain you how to make windows application as singleton in c#. We can use Remoting or Mutex to make application as singleton. We can also use Microsoft.VisualBasic assembly  to make application as singleton. I do not want to have dependency on Microsoft.Visual basic.  I will go with mutex approach.
Mutex is used for interprocess synchronization. There are many locking constructs in .Net like Monitor and Lock. But they only work with in process. Here we need synchronization between multiple processes so we cannot use Monitor or lock. We have to use Mutex or Semaphore. Here is the code to implement singleton logic.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace SingleApplication
{
    static class Program
    {
        static Mutext cmutex = null;
        internal static readonly int WM_SHOWFIRSTINSTANCE = WinFunctions.RegisterWindowMessage("WM_SHOWFIRSTINSTANCE|{0}", "Out Custom Message");
   
        static void Main() 
        {
            cmutex = new Mutex(false, string.Format("Global\\" + GetUniqueId);  // Create global mutex, If Mutex names starts with Global then systemwide mutex is created
            bool lockAccuired;

            try
            {
                try
                {
                    lockAccuired = cmutex.WaitOne(1000);
                }
                catch(AbandonedMutexException)
                {
                    //abandoned exeption is thrown when that thread that owned the mutex does not release it. If any thread tries to accuire 
                    //abandoned mutex then this exception is thrown. However now calling thread has accuried mutex.
                    lockAccuired = true;
                } 
                catch
                {
                    lockAccuired = false;
                }

                if(lockAccuired)
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new Form1());
                }
                else
                {
                    WinFunctions.PostMessage((IntPtr)WinFunctions.HWND_BROADCAST,WM_SHOWFIRSTINSTANCE,IntPtr.Zero,IntPtr.Zero);
                }
            }
            finally
            {
                if(lockAccuired)
                {
                    cmutex.ReleaseMutex();
                }
            }

            //signals garbage collector to not garbage collect this object while the application is running.
            GC.KeepAlive(cmutex);
        }

        string GetUniqueId
        {
            get
            {
                var attributes = Assembly.GetEntryAssembly().GetCustomAttributes(typeof(GuidAttribute), false);
                if(attributes.Length == 0)
                    return string.Empty;
                return ((GuidAttribute)attributes[0])).Value;
            }
        }
    }

    static public class WinFunctions
    {
        public const int HWND_BROADCAST = 0xffff;
        public const int SW_SHOWNORMAL = 1;
        
        //This native function is used to register message.
        [DllImport("user32")]
        public static extern int RegisterWindowMessage(string message);

        public static int RegisterWindowMessage(string format, params object[] args)
        {
            string message = String.Format(format, args);
            return RegisterWindowMessage(message);
        }
        

        [DllImport("user32")]
        public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);

        [DllImportAttribute("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        [DllImportAttribute("user32.dll")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        public static void ShowToFront(IntPtr window)
        {
            //Show window and display in front   
            ShowWindow(window, SW_SHOWNORMAL);
            SetForegroundWindow(window);
        }
    }
}

Now in your main application form [Here Form1], i will override Form class method WinProc.

protected override void WndProc(ref Message message)
{
    if (message.Msg == Program.WM_SHOWFIRSTINSTANCE)
    {
        ShowWindow();
    }
    base.WndProc(ref message);
}

Also in your main form, override Form closing event, and cancel event and show form in taskbar. So actually form is not closed when user clicks on close icon.

protected override void OnFormClosing(FormClosingEventArgs e)
{
    e.Cancel = true;
    Hide();
}

I hope that you will now get basic idea how to implement logic to make application as singleton.