Nick
Nick

Reputation: 533

C# Mutex how to stop my console app running multiple times

I have a console program, not that complicated but at the same time's not a hello world one. I have just two projects, first one has several classes. It is not multithreaded, and is all about calling restful APIs etc. The thing is this: I am trying to make my application check if it runs twice (it is very important). I thought that it would be somehow feasible, but turns out to be extremely complicated. Unfortunately, the only example I found, doesn't shed any light on how to use this technology. Below the code, which, is quite complicated for me, and I don't know how to plug it in my Main. Hence, the question. Below the code (is not mine, I found it here: https://www.codeproject.com/Articles/3014/Single-Process-Instance-Object)

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Reflection;

namespace SpecialServices
{
    //SingleProgamInstance uses a mutex synchronization 
    //object to ensure that only one copy of process is running 
    //at a particular time.  It also allows for UI identification
    // of the intial process by bringing that window to the foreground.
public class SingleProgramInstance : IDisposable
{

    //Win32 API calls necesary to raise an unowned processs main window
    [DllImport("user32.dll")] 
    private static extern bool SetForegroundWindow(IntPtr hWnd);
    [DllImport("user32.dll")] 
    private static extern bool ShowWindowAsync(IntPtr hWnd,int nCmdShow);
    [DllImport("user32.dll")] 
    private static extern bool IsIconic(IntPtr hWnd);

    private const int SW_RESTORE = 9;

    //private members 
    private Mutex _processSync;
    private bool _owned = false;


    public SingleProgramInstance()
    {   
        //Initialize a named mutex and attempt to
        // get ownership immediately 
        _processSync = new Mutex(
            true, // desire intial ownership
            Assembly.GetExecutingAssembly().GetName().Name,
            out _owned);
    }

    public SingleProgramInstance(string identifier)
    {   
        //Initialize a named mutex and attempt to
        // get ownership immediately.
        //Use an addtional identifier to lower
        // our chances of another process creating
        // a mutex with the same name.
        _processSync = new Mutex(
            true, // desire intial ownership
            Assembly.GetExecutingAssembly().GetName().Name + identifier,
            out _owned);
    }

    ~SingleProgramInstance()
    {
        //Release mutex (if necessary) 
        //This should have been accomplished using Dispose() 
        Release();
    }

    public bool IsSingleInstance
    {
        //If we don't own the mutex than
        // we are not the first instance.
        get {return _owned;}
    }

    public void RaiseOtherProcess()
    {
        Process proc = Process.GetCurrentProcess();
        // Using Process.ProcessName does not function properly when
        // the actual name exceeds 15 characters. Using the assembly 
        // name takes care of this quirk and is more accruate than 
        // other work arounds.
        string assemblyName = 
            Assembly.GetExecutingAssembly().GetName().Name;
        foreach (Process otherProc in 
            Process.GetProcessesByName(assemblyName))
        {
            //ignore "this" process
            if (proc.Id != otherProc.Id)
            {
                // Found a "same named process".
                // Assume it is the one we want brought to the foreground.
                // Use the Win32 API to bring it to the foreground.
                IntPtr hWnd = otherProc.MainWindowHandle;
                if (IsIconic(hWnd))
                {
                    ShowWindowAsync(hWnd,SW_RESTORE);
                }
                SetForegroundWindow(hWnd);
                break;
            }
        }
    }

    private void Release()
    {
        if (_owned)
        {
            //If we own the mutex than release it so that
            // other "same" processes can now start.
            _processSync.ReleaseMutex();
            _owned = false;
        }
    }

#region Implementation of IDisposable
    public void Dispose()
    {
        //release mutex (if necessary) and notify 
        // the garbage collector to ignore the destructor
        Release();
        GC.SuppressFinalize(this);
    }
#endregion
}
}

Any help using the above would be GREATLY appreciated; thank you so much.

Upvotes: 2

Views: 623

Answers (2)

pm100
pm100

Reputation: 50190

how to use the sample code.

take the sample code (its one file) and add it to your project (as a separate .cs file)

now at the startup of your program main add

   using(var spi = new SpecialServices.SingleProgramInstance("x5k6yz"))
    {
        if (!spi.IsSingleInstance){
            Console.WriteLine("another copy is running");
            return;
        }
    }

caveat, I have not tried the code from the sample, I assume it works.

EDIT. Ok tested, it works fine

Upvotes: 1

Jonathan Barraone
Jonathan Barraone

Reputation: 133

Try this:

private void CloseDuplicateApplications()
    {
        string ProgramTitle = System.Diagnostics.Process.GetCurrentProcess().MainWindowTitle;
        System.Diagnostics.Process[] Processes = System.Diagnostics.Process.GetProcesses();

        for (int i = 0; i < Processes.Length; i++)
        {
            if (Processes[i].MainWindowTitle == ProgramTitle)
            {
                Processes[i].CloseMainWindow();
            }
        }
    }

Currently the procedure simply closes any duplicate programs, however if you need to kill the duplicate program, replace this line:

Processes[i].CloseMainWindow();

With:

Processes[i].Kill();

Upvotes: 0

Related Questions