Click here to Skip to main content
Click here to Skip to main content

Enforcing Single Instance of a Hidden-Window Application

By , 17 Nov 2006
 

Introduction

Single instance application. There may not be a topic on which there are more good quality articles, so why another? All the methods I could find rely on the main window of the first instance being visible, which won't be the case if you have an application that hides its main window, such as a system tray application. Not only does this method work in the case of a hidden window, but compares favorably for the general case too.

Background

It turns out that detecting whether your application is already running is not very hard. There are several Win32 synchronization objects that will help (this project uses events), or you can enumerate windows and search their titles (this won't work if the window is hidden though). On the other hand, it is difficult to get the first instance of the application to display its window. Especially if the window is hidden, any method using messages or manipulating the window handle won't work.

Here are some other articles you might find helpful. I'm kind of partial to this one, which also has some code for displaying an animation as the application minimizes to the sys tray area of the task bar (which, by the way, is apparently unnecessary in XP): A Single Instance Application which Minimizes to the System Tray when Closed.

Here's another recent one that has the added advantage of having no unmanaged code (unlike my example): Single Instance Application, Passing Command Line Arguments.

Using the code

The method is simple, but the implementation a little less so. This is how it's done: the application attempts to open a named event. If the event exists, then the application knows it is the second instance. In that case, it signals the event and exits. If the named event doesn't exist, then the application creates it and starts a thread which waits for the event to be signaled. If the event becomes signaled, it uses P/Invoke to call a delegate on the GUI thread. The delegate shows the window, then calls a Win32 function to bring itself to the foreground.

The code that creates and checks the event is in a class called Event. The app's Main will create an Event object and use it to check whether another instance is already running. Here's what the Main looks like:

static void Main() 
{
    // this class provides single instance feature
    evnt = new Event();
    
    // already exists means another instance is running
    if ( evnt.EventAlreadyExists() )
    {
        // signal the other instance to come to foreground
        evnt.SignalEvent();
    }
    else
    {
        // otherwise start normally
        SingleInstanceForm f = new SingleInstanceForm();
        // important: access the Handle so .net will create it
        IntPtr dummy = f.Handle;
        f.eventSignalled = 
           new EventSignalledHandler( f.evnt_EventSignalled );
        evnt.SetObject( f );

        Application.Run();
    }

}

Notice that I don't call Application.Run() with the form reference, which allows this application to start without showing a window. While this method doesn't need a visible window, P/Invoke does need a valid window handle. Accessing the form's handle forces .NET to create it for us.

Here's what the Event constructor looks like:

public Event()
{
    eventHandle = OpenEvent( EVENT_MODIFY_STATE | 
                  SYNCHRONIZE, false, EVENT_NAME );
    if ( eventHandle == IntPtr.Zero )
    {
        eventHandle = CreateEvent( IntPtr.Zero, true, 
                      false, EVENT_NAME );
        if ( eventHandle != IntPtr.Zero )
        {
            Thread thread = 
               new Thread( new ThreadStart( WaitForSignal ) );
            thread.Start();
        }
    }
    else
    {
        eventAlreadyExists = true;
    }

}

OpenEvent will return a valid handle only if another instance has created it. So, it's very important that the handle gets closed, which is why I implement the IDisposable interface. If the handle were left open, your app would run the first time, but would not be able to start again until after a reboot or logout.

Win32 Synchronization object names can be defined on a per session or a per machine basis. This project prepends "Local\" to the name, which means it is only unique for the currently logged in user.

Points of interest

I learned about implementing IDisposable from this article: Implementing IDisposable and the Dispose Pattern Properly.

One of the keys to this project is calling a method on a GUI thread from a worker thread, and in .NET, this is handled by P/Invoke. There are many good articles on CodeProject about P/Invoke, but I also want to point out a great reference site: http://www.pinvoke.net/.

I look forward to hearing comments and better or more clear ways of doing what I've shown here. One thing I don't like is that the Event class is tied to the form class definition. One way to fix that is to create a new class that inherits from Form and that defines the necessary delegate.

On Windows 2000, SetForegroundWindow() doesn't always work as expected.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

drdre2005
United States United States
Member
I live near San Diego, CA. I wouldn't recommend it unless you can handle a severe lack of cold and snow.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralProcess not being killedmemberMember 39740095 Aug '08 - 0:54 
Hi, great code you posted here, it was really helpful, but I think I found a little bug which is not allowing the process to be effectively killed. The thread you create for waiting for the event to be signaled stays active, you need to signal it for so it knows that the handle has changed and no longer exists.
 
Peace.
GeneralRe: Process not being killedmemberJ. David Reynolds30 Oct '08 - 11:44 
You're right about the thread. I added a signal in Dispose() and a "disposing" flag that is checked in the handler to see whether to exit the thread.
 
But to the original author...THANK YOU! This is the only one of the many things I've tried that actually works for restoring the app from the system tray. Nice technique.
GeneralRe: Process not being killedmemberdrdre200530 Oct '08 - 12:10 
Hey, way to go everyone and thanks dadda_mac too. These are great improvements. I haven't been ignoring you, my $%#@# isp has a spam black hole which can't be turned off. I'm really glad you got some use out of my original project, flawed as it was!
Brad Dre
GeneralMade some slight mods for re-usability [modified]memberdadda_mac21 Feb '08 - 5:27 
Your code was great!! Exactly what I needed to restore my system tray application. The changes below made it a little easier for me to reuse the code, but I'm sure someone here could abstract this even further. You did a good job with this, kudos!
 
Note: I had to edit this, made some more abstractions - hope this helps someone.
 
using System;
using System.Threading;
using System.Runtime.InteropServices;
using System.Windows.Forms;
 
namespace SingleInstanceNoMutex
{
    /// <summary>
    /// This implements single instance.  It turns out that single instance is
    /// fairly easy with either mutex or event.  The other part of the job is
    /// to get the first instance to display its window in the foreground, which
    /// is much more difficult, especially if the app window is initially hidden.
    /// this class should be created in main().  the first instance will create
    /// the event.  The second instance will open it, then signal it and exit.  The first
    /// event starts a thread which waits indefinitely for the event to signal.
    /// That thread has to call Invoke() so that the main thread can update the GUI.
    /// This class must implement IDisposable to ensure that the unmanaged Win32 handle is released
    /// 
    /// SPECIAL CREDIT:
    /// I can't take any credit for this class.  Yes, I did make some mods, but
    /// the real credit goes to drdre2005, member on CodeProject.com
    /// His original code is available on the website.  The article is entitled
    /// "Enforcing Single Instance of a Hidden-Window Application"
    /// http://www.codeproject.com/KB/threads/SingleInstance.aspx
    /// This class just abstracts the things he's done to make it reusable.
    /// </summary>
    public class SingleInstance : IDisposable
    {
        private bool disposed = false;
 
        #region "Imported DLLs, kernel32.dll functions"
        //#############################################
        [DllImport("kernel32.dll")]
        static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
        [DllImport("kernel32.dll")]
        static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
        [DllImport("kernel32.dll")]
        static extern bool SetEvent(IntPtr hEvent);
        [DllImport("kernel32.dll")]
        static extern IntPtr OpenEvent(UInt32 dwDesiredAccess, bool bInheritable, string lpName);
        [DllImport("kernel32.dll")]
        static extern bool CloseHandle(IntPtr hHandle);
        [DllImport("kernel32.dll")]
        static extern bool ResetEvent(IntPtr hEvent);
        //#############################################
        #endregion
 
        private string EVENT_NAME = string.Format("Local:{0}:{1}:{2}",
            Application.CompanyName,
            Application.ProductName,
            Application.ProductVersion);
        private const uint INFINITE = 0xFFFFFFFF;
        private const uint SYNCHRONIZE = 0x00100000;
        private const uint EVENT_MODIFY_STATE = 0x0002;
 
        private IntPtr eventHandle = IntPtr.Zero;		// unmanaged
        private Form form = null;
 
        /// <summary>
        /// Execute a form base application if another instance already running on
        /// the system activate previous one
        /// </summary>
        /// <param name="frmMain">main form</param>
        /// <returns>true if no previous instance is running</returns>
        public SingleInstance(Form mainForm)
        {
            if (InstanceAlreadyExists())
            {
                SignalInstance();
            }
            else
            {
                form = mainForm;
                Application.Run(form);
                Environment.Exit(0);
            }
        }
 
        /// <summary>
        /// Runs based on inherited form of System.Windows.Forms.ApplicationContext
        /// If another instance is already running on the system, activate the previous one
        /// </summary>
        /// <param name="appContext">ApplicationContext</param>
        /// <returns>true if no previous instance is running</returns>
        public SingleInstance(ApplicationContext appContext)
        {
            if (InstanceAlreadyExists())
            {
                SignalInstance();
            }
            else
            {
                form = appContext.MainForm;
                Application.Run(appContext);
                Environment.Exit(0);
            }
        }
 
        // Destructor
        ~SingleInstance()
        {
            Dispose(false);
        }
 
        // after creation, call this to determine if we are the first instance
        private bool InstanceAlreadyExists()
        {
            eventHandle = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, false, EVENT_NAME);
            if (eventHandle == IntPtr.Zero)
            {
                eventHandle = CreateEvent(IntPtr.Zero, true, false, EVENT_NAME);
                if (eventHandle != IntPtr.Zero)
                {
                    Thread thread = new Thread(new ThreadStart(WaitForSignal));
                    thread.Start();
                }
                return false;
            }
            else
            {
                return true;
            }
        }
 
        // an instance calls this when it detects that it is
        // the second instance.  Then it exits
        private void SignalInstance()
        {
            if (eventHandle != IntPtr.Zero)
                SetEvent(eventHandle);
        }
 
        // thread method will wait on the event, which will signal
        // if another instance tries to start
        private void WaitForSignal()
        {
            while (true)
            {
                uint result = WaitForSingleObject(eventHandle, INFINITE);
 
                if (result == 0)
                {
 
                    ResetEvent(eventHandle);
                    if (form != null) restoreInstance();
                }
                else
                {
                    // what the heck, don't risk a busy loop
                    // just let the thread die
                    break;
                }
            }
        }
 
        private delegate void restoreInstanceDel();
        private void restoreInstance()
        {
            if (form.InvokeRequired)
            {
                form.Invoke(new restoreInstanceDel(restoreInstance));
            }
            else
            {
                form.Show();
                form.WindowState = FormWindowState.Normal;
                form.Activate();
            }
        }
 
        #region IDisposable Members
        //#############################################################
        protected virtual void Dispose(bool disposeManagedResources)
        {
            if (!this.disposed)
            {
                if (disposeManagedResources)
                {
                    // dispose managed resources
                    if (form != null)
                    {
                        form.Dispose();
                        form = null;
                    }
                }
                // dispose unmanaged resources
                if (eventHandle != IntPtr.Zero)
                    CloseHandle(eventHandle);
                eventHandle = IntPtr.Zero;
 
                disposed = true;
            }
        }
 
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        //#############################################################        
        #endregion
    }
}
I import this into my project (or create a dll and reference) and use it like this:
 
using System;
using System.Collections.Generic;
using System.Windows.Forms;
 
namespace MyWindowsApp
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new frumSearch());
            using (new SingleInstanceNoMutex.SingleInstance(new frmSearch())) { }
        }
    }
}

 
modified on Tuesday, March 4, 2008 4:21 PM

Generalpassing command line argumentsmemberMarioMARTIN31 Oct '07 - 1:52 
Hi all!
 
I wrote another verion that is able to pass command line arguments using named native Windows pipes.
 
A version that uses WCF and 'NetNamedPipeBinding' would also be possible.
 

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Win32.SafeHandles;
using System.IO;
using System.ComponentModel;
 
namespace Common
{
  /// <summary>
  /// Class that is used to check whether the current running application is
  /// unique (the first instance) or whether there is already another instance
  /// running.
  /// 
  /// If there is already another instance running the new instance passes its
  /// commandline arguments to the priviously started application instance.
  /// </summary>
  public class SingleInstanceManager : IDisposable
  {
    #region delegates
    /// <summary>
    /// Gets called when this is the first instance and another instance tries
    /// to start
    /// </summary>
    /// <param name="args">Command line arguments of the second instance</param>
    public delegate void ShowApplicationCallback( String args );
    private ShowApplicationCallback m_ShowAppCallback;
 

    /// <summary>
    /// Gets called when this is NOT the first instance
    /// </summary>
    public delegate void TerminateApplicationCallback();
    private TerminateApplicationCallback m_TerminateAppCallback;
    #endregion
 

    #region contained definitions
    /// <summary>
    /// Wrapper for native Windows functions, flags and constants
    /// </summary>
    private class NativeMethods
    {
      #region flags and enums
      [Flags]
      internal enum CreateNamedPipeFlags : uint
      {
        PIPE_TYPE_BYTE = 0,
        PIPE_TYPE_MESSAGE = 0x00000004,
 
        PIPE_READMODE_BYTE = 0,
        PIPE_READMODE_MESSAGE = 0x00000002,
 
        PIPE_WAIT = 0,
 
        PIPE_ACCESS_INBOUND = 0x00000001,
        PIPE_ACCESS_OUTBOUND = 0x00000002,
        PIPE_ACCESS_DUPLEX = 0x00000003,
      }
 
      internal enum CreateNamedPipeConstants : uint
      {
        NUMBER_OF_PIPE_INST = 1,
        OUT_BUFFER_SIZE = 256,
        IN_BUFFER_SIZE = 256,
      }
 
      [Flags]
      internal enum CreateFileFlags : uint
      {
        GENERIC_READ = 0x80000000,
        GENERIC_WRITE = 0x40000000,
      }
 
      internal enum CreateFileConstants : uint
      {
        OPEN_EXISTING = 3,
      }
      #endregion
 
      #region native Windows functions
      [DllImport( "Kernel32.dll" )]
      public static extern SafeFileHandle CreateNamedPipe( string lpName,
                                       [MarshalAs( UnmanagedType.I4 )]
                                       CreateNamedPipeFlags dwOpenMode,
                                       [MarshalAs( UnmanagedType.I4 )]
                                       CreateNamedPipeFlags dwPipeMode,
                                       [MarshalAs( UnmanagedType.I4 )]
                                       CreateNamedPipeConstants nMaxInstances,
                                       [MarshalAs( UnmanagedType.I4 )]
                                       CreateNamedPipeConstants nOutBufferSize,
                                       [MarshalAs( UnmanagedType.I4 )]
                                       CreateNamedPipeConstants nInBufferSize,
                                       [MarshalAs( UnmanagedType.I4 )]
                                       CreateNamedPipeConstants nDefaultTimeOut,
                                       IntPtr lpSecurityAttributes );
 
      [DllImport( "Kernel32.dll", SetLastError = true )]
      [return: MarshalAs( UnmanagedType.I4 )]
      public extern static Int32 ConnectNamedPipe( SafeFileHandle namedPipe,
                                                   IntPtr overlapped );
 
      [DllImport( "Kernel32.dll", SetLastError = true )]
      public extern static SafeFileHandle CreateFile( string name,
                                       [MarshalAs( UnmanagedType.I4 )]
                                       CreateFileFlags desiredAccess,
                                       [MarshalAs( UnmanagedType.I4 )]
                                       CreateFileFlags shareMode,
                                       IntPtr securityAttributes,
                                       [MarshalAs( UnmanagedType.I4 )]
                                       CreateFileConstants creationDisposition,
                                       [MarshalAs( UnmanagedType.I4 )]
                                       UInt32 flagsAndAttributes,
                                       IntPtr templateFile );
 
      [DllImport( "Kernel32.dll" )]
      [return: MarshalAs( UnmanagedType.Bool )]
      public static extern bool DisconnectNamedPipe( SafeFileHandle hNamedPipe );
      #endregion
    }
    #endregion
 

    #region constructors
    /// <summary>
    /// Constructor that initializes the SingleInstanceManager
    /// </summary>
    /// <param name="applicationName">Unique string that identifies your 
    /// application</param>
    /// <param name="showCallback">Callback that gets executed when another 
    /// instance of your application tries to start</param>
    /// <param name="terminateCallback">Callback that gets executed when another 
    /// instance of your application already got started</param>
    public SingleInstanceManager( String applicationName,
                                  ShowApplicationCallback showCallback,
                                  TerminateApplicationCallback terminateCallback )
    {
      m_ShowAppCallback = showCallback;
      m_TerminateAppCallback = terminateCallback;
      m_MutexName = applicationName;
      m_Arguments = Environment.CommandLine; //ToDo: Remove Process name
    }
 

    /// <summary>
    /// Hidden default constructor
    /// </summary>
    private SingleInstanceManager()
    { }
    #endregion
 

    #region public member functions
    /// <summary>
    /// Call this function after you instantiated the SingleInstanceManager
    /// to check whether this is the first instance or not.
    /// 
    /// Throws: SingleInstanceManagerException
    /// </summary>
    public void CheckUniqueness()
    {
      bool isMutexNew = false;
 
      try
      {
        //Try to create our Mutex
        m_Mutex = new Mutex( true, m_MutexName, out isMutexNew );
 
        if ( isMutexNew == true )
        {
          ClaimUniqueness();
        }
        else
        {
          NotifyUniqueInstance();
        }
      }
      catch ( Exception e )
      {
        throw new SingleInstanceManagerException( 
                     "SingleInstanceManager could not CheckUniqueness. " +
                     "Details :" + e.Message );
      }
    }
    #endregion
 

    #region private member functions
    /// <summary>
    /// Gets called when this instance is the first (the unique) instance and
    /// waits for commandline arguments of other instances
    /// </summary>
    private void ClaimUniqueness()
    {      
        //Open a pipe for the commandline arguments of other instances
        CreatePipe();
 
        //Wait for other instances
        m_Thread = new Thread( new ThreadStart( WaitForSignal ) );
        m_Thread.Start();
    }
 

    /// <summary>
    /// Passes the commandline arguments to the unique instance and calls
    /// ShowApplicationCallback afterwards
    /// </summary>
    private void NotifyUniqueInstance()
    { 
        m_Pipe = NativeMethods.CreateFile( @"\\.\pipe\" + m_MutexName,
                                     NativeMethods.CreateFileFlags.GENERIC_WRITE,
                                     0,
                                     IntPtr.Zero,
                                     NativeMethods.CreateFileConstants.OPEN_EXISTING,
                                     0,
                                     IntPtr.Zero );
 
        if ( m_Pipe.IsInvalid )
          throw new Win32Exception( Marshal.GetLastWin32Error() );
 
        //Pass arguments into the pipe
        using ( TextWriter textWriter =
          new StreamWriter( new FileStream( m_Pipe, FileAccess.Write ) ) )
        {
          textWriter.WriteLine( m_Arguments );
          textWriter.Flush();
        }
 
      //call the termination callback
      m_TerminateAppCallback();
    }
 

    /// <summary>
    /// Creates a pipe that is used to receive commandline arguments
    /// </summary>
    private void CreatePipe()
    {
        m_Pipe = NativeMethods.CreateNamedPipe( @"\\.\pipe\" + m_MutexName,
                                    NativeMethods.CreateNamedPipeFlags.PIPE_ACCESS_DUPLEX,
                                    NativeMethods.CreateNamedPipeFlags.PIPE_TYPE_BYTE |
                                      NativeMethods.CreateNamedPipeFlags.PIPE_READMODE_BYTE |
                                      NativeMethods.CreateNamedPipeFlags.PIPE_WAIT,
                                    NativeMethods.CreateNamedPipeConstants.NUMBER_OF_PIPE_INST,
                                    NativeMethods.CreateNamedPipeConstants.OUT_BUFFER_SIZE,
                                    NativeMethods.CreateNamedPipeConstants.IN_BUFFER_SIZE,
                                    0,
                                    IntPtr.Zero );
 
        if ( m_Pipe.IsInvalid )
          throw new Win32Exception( Marshal.GetLastWin32Error() );
 
        m_TextReader = new StreamReader( new FileStream( m_Pipe, FileAccess.Read ) );
    }
 

    /// <summary>
    /// Waits for commandline arguments
    /// 
    /// Throws: SingleInstanceManagerException
    /// </summary>
    private void WaitForSignal()
    {
      while ( true )
      {
        try
        {
          //Connect to the pipe
          NativeMethods.ConnectNamedPipe( m_Pipe, IntPtr.Zero );
 
          m_Arguments = m_TextReader.ReadLine();
 
          m_ShowAppCallback( m_Arguments );
 
          //Disconnect from pipe
          NativeMethods.DisconnectNamedPipe( m_Pipe );
 
        }
        catch ( Exception e )
        {
          throw new SingleInstanceManagerException(
                      "SingleInstanceManager encountered a problem. " +
                      "Details :" + e.Message );
        }
      }
    }
 
    #region IDisposable Members
 
    protected virtual void Dispose( bool disposeManagedResources )
    {
      if ( !this.disposed )
      {
        
        if ( m_Pipe != null )
          m_Pipe.Dispose();
 
        if ( m_TextReader != null )
          m_TextReader.Dispose();
 
        if ( m_Thread != null )
          m_Thread.Abort();
 
        disposed = true;
      }
    }
 

    public void Dispose()
    {
      Dispose( true );
      GC.SuppressFinalize( this );
    }
 

    // destructor
    ~SingleInstanceManager()
    {
      Dispose( false );
    }
    #endregion
 
    #endregion
 
    #region member variables
 
    private bool disposed = false;
 
    private Mutex m_Mutex;
    private SafeFileHandle m_Pipe;
 
    private TextReader m_TextReader;
 
    private String m_MutexName;
    private String m_Arguments;
 
    private Thread m_Thread;
 
    #endregion
  }
 
  
  [global::System.Serializable]
  public class SingleInstanceManagerException : Exception
  {
 
    public SingleInstanceManagerException() { }
    public SingleInstanceManagerException( string message ) : base( message ) { }
    public SingleInstanceManagerException( string message, Exception inner ) : base( message, inner ) { }
    protected SingleInstanceManagerException(
    System.Runtime.Serialization.SerializationInfo info,
    System.Runtime.Serialization.StreamingContext context )
      : base( info, context ) { }
  }
}
 

 

 
Cheers,
 
Mario M.
 


Dear CodeProject member: Please don't forget to show me how clever you are by rating also this message as "crap/spam/trash" instead of writing a meaningful response!


QuestionHow would you do this in WPF?memberjwhurst22 Aug '07 - 11:59 
This seems like an excellent solution to me, for Windows Forms apps. Thank you for providing it.
Would you happen to know how to structure this for a WPF (Windows Presentation Foundation) app? I'm a WPF beginner; since XAML-compiled WPF apps auto-generate their own Main() function and call it, I'm a bit fuzzy on where we'd put this code.
 
(btw, the solution on pg 200 of Adam Nathan's "Windows Presentation Foundation Unleashed", doesn't work. mutexIsNew is always true.)
 
James Hurst
"The greatness of a nation and its moral progress can be judged by the way its animals are treated."

Mahatma Gandhi

AnswerRe: How would you do this in WPF?memberdrdre200522 Aug '07 - 12:20 
Funny you should ask, until a few days ago I would have had no idea what you were talking about. But, it looks like Smurfcoder has supplied what you need.
 
As you say, there's no main(), but it looks like he constructs the Event object in the startup class constructor. Definitely cleaner than what I did in C#.
 
Brad Dre

GeneralRe: How would you do this in WPF?memberjwhurst22 Aug '07 - 17:16 
Oh geez - the solution was right there?!!! In anycase, I wouldn't say it's 'cleaner' but it does the job. Seems it took a lot of code markup to make it work. Both of you provided a terrific help!
Thank you.
 
James Hurst
"The greatness of a nation and its moral progress can be judged by the way its animals are treated."

Mahatma Gandhi

AnswerRe: How would you do this in WPF?membernorm .net27 Sep '07 - 23:30 
It seems WPF framework doesn't support single instance Confused | :confused: why dunno. There's couple if single instance solutions, one uses WCF (seems overkill), and one uses Microsoft.VisualBasic.ApplicationServices WTF | :WTF: . The later is prone to be buggy (doesn't surprise me being VB;P).
 
Smurfcoders solution works, I've tried in an app used by 100+ users. The only change I'd recommend being
 
http://www.codeproject.com/cs/threads/SingleInstance.asp?msg=2248357#xx2248357xx[^]
 

Chuck Norris counted to infinity - twice.

GeneralGreat!memberSmurfcoder13 Aug '07 - 4:10 
Hi,
 
Thanks a million!
 
I'm new to Windows programming and spent two days looking for a solution until I found yours!
 
I only made some minor changes in the constructor to make the handling a bit easier:
 
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
 
namespace WindowHide
{
 
 
  public class SingleInstanceManager : IDisposable
  {
    private bool disposed = false;
 
    [DllImport( "kernel32.dll" )]
    static extern uint WaitForSingleObject( IntPtr hHandle, uint dwMilliseconds );
    [DllImport( "kernel32.dll" )]
    static extern IntPtr CreateEvent( IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName );
    [DllImport( "kernel32.dll" )]
    static extern bool SetEvent( IntPtr hEvent );
    [DllImport( "kernel32.dll" )]
    static extern IntPtr OpenEvent( UInt32 dwDesiredAccess, bool bInheritable, string lpName );
    [DllImport( "kernel32.dll" )]
    static extern bool CloseHandle( IntPtr hHandle );
    [DllImport( "kernel32.dll" )]
    static extern bool ResetEvent( IntPtr hEvent );
 
    private const uint INFINITE = 0xFFFFFFFF;
    private const string EVENT_NAME = "UM_USER_SHOW_WINDOW";
    private const uint SYNCHRONIZE = 0x00100000;
    private const uint EVENT_MODIFY_STATE = 0x0002;
 
    private IntPtr m_EventHandle = IntPtr.Zero;		// unmanaged

    private Window m_Instance;
 
    public delegate void ShowApplicationCallback();
    private ShowApplicationCallback m_callback;
   
    // constructor
    public SingleInstanceManager( Window instance, ShowApplicationCallback callback )
    {
      m_Instance = instance;
      m_callback = callback;
 
      //try to our event
      m_EventHandle = OpenEvent( EVENT_MODIFY_STATE | SYNCHRONIZE, false, EVENT_NAME );
      if ( m_EventHandle == IntPtr.Zero ) //if it doesn't exist
      {
        //create our event
        m_EventHandle = CreateEvent( IntPtr.Zero, true, false, EVENT_NAME );
        if ( m_EventHandle != IntPtr.Zero ) //if successfull
        {
          Thread thread = new Thread( new ThreadStart( WaitForSignal ) );
          thread.Start();
        }
      }
      else
      {
        SetEvent( m_EventHandle );
        Environment.Exit( 0 );
      }
    }
 
    // destructor
    ~SingleInstanceManager()
    {
      Dispose( false );
    }
 
    // an instance calls this when it detects that it is
    // the second instance.  Then it exits
    public void SignalEvent()
    {
      if ( m_EventHandle != IntPtr.Zero )
        SetEvent( m_EventHandle );
    }
 

    // thread method will wait on the event, which will signal
    // if another instance tries to start
    private void WaitForSignal()
    {
      while ( true )
      {
        uint result = WaitForSingleObject( m_EventHandle, INFINITE );
 
        if ( result == 0 )
        {
          m_Instance.Dispatcher.Invoke( System.Windows.Threading.DispatcherPriority.Normal, m_callback );
        }
        else
        {
          return;
        }
      }
    }
 
    #region IDisposable Members
 
    protected virtual void Dispose( bool disposeManagedResources )
    {
      if ( !this.disposed )
      {
        // dispose unmanaged resources
        if ( m_EventHandle != IntPtr.Zero )
          CloseHandle( m_EventHandle );
        m_EventHandle = IntPtr.Zero;
 
        disposed = true;
      }
    }
 

    public void Dispose()
    {
      Dispose( true );
      GC.SuppressFinalize( this );
    }
 
    #endregion
  }
}
 
And the window code (WPF) looks like this:
 
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Runtime.InteropServices;
 
namespace WindowHide
{
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>
 
  public partial class Window1 : System.Windows.Window
  {
    SingleInstanceManager m_Event;
   
    public Window1()
    {
      this.Visibility = Visibility.Hidden;
 
      Application.Current.Exit += new ExitEventHandler( Current_Exit );
      
      m_Event = new SingleInstanceManager(this, ShowApplication);
 
      InitializeComponent();
    }
 
    public void ShowApplication()
    {
      if ( this.Visibility == Visibility.Hidden )
      {
        this.Visibility = Visibility.Visible;
      }
    }
 
    void Current_Exit( object sender, ExitEventArgs e )
    {
      Environment.Exit( 0 );
    }
  }
}

GeneralRe: Great!memberdrdre200519 Aug '07 - 5:34 

Hey, this is great! And, I'm pleased my article helped you. It looks like you've solved the problem of the Event class being dependent on a specific Form (with Window). Also, you've simplified how the worker thread calls into the gui thread.
 
But, the code doesn't look familiar -- I wasn't able to compile it in the 1.1 framework. I'm thinking I'm behind the times...
 
Thanks again!
Brad Dre

GeneralRe: Great! - Hidden?memberjwhurst22 Aug '07 - 17:06 
Good tip - I compiled it and it does work fine except that it makes the window hidden initially. Or was that just to show an example of making it show itself?
I wonder now (being the greedy sort that I am) how can we change the ShowApplication method to also bring the window to the foreground (ie, to have focus)?
 
James Hurst
"The greatness of a nation and its moral progress can be judged by the way its animals are treated."

Mahatma Gandhi

GeneralRe: Great! - Hidden?memberMarioMARTIN22 Aug '07 - 19:55 
Hi all!
 
It's me, Smurfcoder (I changed my name to a more serious one Wink | ;) )
 
I'm not only new to Windows Programming, I'm also new to C#, but I think this might work:
 

    public void ShowApplication()
    {
      if ( !this.IsActive )
      {
        this.Activate();
      }
    }
 
Cheers,
 
Mario M.
GeneralRe: Great! - Hidden?membernorm .net27 Sep '07 - 23:21 
You almost got a create WPF single instance app. My only change would be
 
m_EventHandle = CreateEvent(IntPtr.Zero, true, false, EVENT_NAME);
 
to
 
m_EventHandle = CreateEvent(IntPtr.Zero, false, false, EVENT_NAME);
 

Chuck Norris counted to infinity - twice.

GeneralSome Wpf alternativesmemberFocusedWolf3 Apr '09 - 5:46 
smurfcoder sounds like such a cool code name :P
 

Anyways here's some implementations for simple single instance that is not secure:
 
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
using System.Threading;
using System.Diagnostics;
 
namespace YourApp
{
///
/// Interaction logic for App.xaml
///
public partial class App : Application
{
//a unique method using Events? can be found here: http://dev.liferus.ru/2008/12/wpf-application-single-instance-in-one.html
 
//Single instance developed from this site:
//http://www.ai.uga.edu/~mc/SingleInstance.html
 
Mutex m;
 
protected override void OnStartup(StartupEventArgs e)
{
//http://pietschsoft.com/category/WPF.aspx
/* Another way. Slower.
 
// Get Reference to the current Process
Process thisProc = Process.GetCurrentProcess();
 
// Check how many total processes have the same name as the current one
if (Process.GetProcessesByName(thisProc.ProcessName).Length > 1)
Application.Current.Shutdown()
else
base.OnStartup(e);
*/
 
//the fast way everyone likes :P . This one seems ideal for just about any small project :P
 
bool singleInstanceRunning;
m = new System.Threading.Mutex(true, "{CF9F1919-8202-4b0b-AB74-6F29490BACBC}", out singleInstanceRunning);
 
if (!singleInstanceRunning)
Application.Current.Shutdown();
else
base.OnStartup(e);
 
GC.KeepAlive(m);
}
}
}
 
modified on Friday, April 3, 2009 12:13 PM

GeneralSimpler solution using a MutexmemberJoe McRay18 Nov '06 - 8:39 
Hello, you had a good idea and you found a nice solution.
 
Nevertheless this task can be done in a much simpler way using a Mutex:
 
public static void Main()
{
  bool createdNew;
  using(Mutex mtx = new Mutex(true /*initially owned*/, "MyUniqueMutexName_{B8EE61C8-0F08-4a8e-88F0-E5426309DD96}", out createdNew))
  {
    if (createdNew)
    {
      Console.WriteLine("Created new - first instance (or mutex was released)");
      // do the work here
    }
    else
    {
      Console.WriteLine("Not created - not first instance");
      
      // call Dispose() to free the mutex now in case
      // this process should do some work but another
      // instance should be allowed in case the first releases the mutex
      //((IDisposable)mtx).Dispose();
    }
 
    // make sure to keep the Mutex alive as long as you want to block more instances
    Console.ReadLine();
  } // mutex released by Dispose() here
}

I'm not sure if the "local"-prefix must be prepended or if it is prepended implicitly.
 
Keep on coding...
GeneralRe: Simpler solution using a MutexmemberSteve Hansen20 Nov '06 - 1:32 
But then you cant call the currently running application to do something (like coming to foreground as in the article)
GeneralRe: Simpler solution using a Mutexmemberdrdre200520 Nov '06 - 4:45 
Yes, as Steve H. said -- using a Mutex on its own doesn't supply a way for the second instance to signal the first instance, which is, as I said, the hard part. Any global OS object that can be created (even a file) can be used to detect the second instance.
 
Your code is interesting, I'm new to C# and have not seen anything like that. Does the compiler complain if the object casted to IDisposable does not implement the IDisposable interface? I'm guessing yes. But, why would you explicitly call dispose on a .NET managed object? The other puzzling thing to me is why it is Disposed() in the else, but not actually released until after the end of using?
 
Thanks for your comment!
Brad Dre
drdre2005

GeneralRe: Simpler solution using a MutexmemberSuperDave00729 Nov '06 - 4:55 
You want to dispose of your handle to the object as soon as you've decided your process is a duplicate. Until it disposes of it, it would be part owner of the object. If the original process exits, and another process attempted to take its place, it would see the object in use and assume that the work was already being done, when in fact no process was doing it.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 17 Nov 2006
Article Copyright 2006 by drdre2005
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid