1

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.

Nick
  • 483
  • 1
  • 6
  • 15
  • I hope I will not have to put thousand lines of my public class Program run within some class or something; but then again, I don't know.. I was hoping there could be some simple way to declare once that this program runs once - so if someone tries to run a second instance, to automatically return to the currently running console window. Thank you in advance. – Nick Feb 05 '22 at 01:06
  • you want to make sure that two instances of your program are not running at once? So the second one should terminate? Or do you want the second one to wait for the first one to finish? – pm100 Feb 05 '22 at 01:13
  • @pm100 I want to make sure that my program runs once. Meaning, if it is running and you try to run it again, it shouldn't start a second instance. – Nick Feb 05 '22 at 01:16

2 Answers2

1

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

pm100
  • 48,078
  • 23
  • 82
  • 145
  • Thank you very much; I put it immediately under static void Main(string[] args) as I see it, and my next line of code (my ex-first line of code, before addition) is DateTime utcDateTime = DateTime.UtcNow; I build, no errors, all good. I run, and seems it is closing immediately - by the way, my line DateTime etc has the green curly underline with warning "unreachable code detected.." What do I do wrong?? – Nick Feb 05 '22 at 01:35
  • Done! (I had to replace your return with my Exception). Works perfectly! THANK YOU very much ! – Nick Feb 05 '22 at 01:49
  • @Nick read the code from codeproject and workout what its doing. You will find it interesting, plus you dont want to depend on magic that you dont understand – pm100 Feb 05 '22 at 02:15
  • @pim100 You are absolutely right! Actually I downloaded a couple of projects on mutex and I am beginning to understand. Your source worked perfectly! Thank you so much! – Nick Feb 05 '22 at 10:41
0

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();