0

I have used the code from this answer to see if my app is already running. If it is running I want to be able to get the app that is running and bring it to the front so that the user can see it.

To do this I can use the Process.Name property and check on that but if another process has the same name that isn't my app or the name changes between revisions it might not work. To fix this I thought it would be possible to compare on the applications guid. I can get my apps guid by doing the following:

string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly()
                                         .GetCustomAttributes(typeof(GuidAttribute), false)
                                         .GetValue(0)).Value.ToString();

Is there a way to get the apps guid, or the executing assembly guid, of a process that is running to compare on that?

Community
  • 1
  • 1
TheLethalCoder
  • 6,668
  • 6
  • 34
  • 69
  • not all processes have that. the guid also remains fixed between versions. you will have to look at the starting location for that assembly, load it with reflection and do your bidding. – Daniel A. White Oct 24 '16 at 10:09
  • @DanielA.White That's why I want the guid, because it remains fixed, and my apps will always have a guid – TheLethalCoder Oct 24 '16 at 10:10
  • 1
    @DanielA.White He knows that *his* process has it though, so anything that doesn't have one is simply false :) – RB. Oct 24 '16 at 10:10
  • You would have to enumerate the paths of the executables of all processes currently running, attempt to load them as .NET assemblies (which most won't be as they'll be native Windows processes) and then use reflection to extract the GUID from the [GuidAttribute] that the assembly may have. – Martin Costello Oct 24 '16 at 10:11
  • 1
    If you google for `.NET Single Instance application` you should find plenty of solutions. You don't have to re-invent one yourself. – Damien_The_Unbeliever Oct 24 '16 at 10:17
  • You can use Mutex to prevent loading another instance of your app. BringToFront on the form control (hope it is win forms) will bring the form to visible area. So, if you combine both you can get what you want. I am sorry i don't have a code sample. This [link](http://stackoverflow.com/questions/646480/is-using-a-mutex-to-prevent-multiple-instances-of-the-same-program-from-running) may help you – Thangadurai Oct 24 '16 at 10:33

1 Answers1

3

Turns out it was pretty simple just need to use Assembly.LoadFrom on the process. This can throw some errors to do with access so beware of those. I have created the following class to check if an app is running and if it is bring the process to the front.

Note that the below code just swallows exceptions on loading an assembly which isn't what you want. For the moment it is like that whilst I find the right exceptions to catch.

using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Threading;

namespace Helpers
{
    public static class SingleInstance
    {
        [DllImport("User32.dll")]
        private static extern bool SetForegroundWindow(IntPtr handle);

        [DllImport("User32.dll")]
        private static extern bool ShowWindow(IntPtr handle, int nCmdShow);

        [DllImport("User32.dll")]
        private static extern bool IsIconic(IntPtr handle);

        private const int SW_RESTORE = 9;

        private static string _appGuid;

        private static Mutex _mutex;

        static SingleInstance()
        {
            _appGuid = GetAssemblyGuid(Assembly.GetExecutingAssembly());
        }

        public static bool IsAlreadyRunning(bool useGlobal)
        {
            //This code was taken from http://stackoverflow.com/a/229567/4631427

            string mutexId;
            if (useGlobal)
            {
                mutexId = String.Format("Global\\{{{0}}}", _appGuid);
            }
            else
            {
                mutexId = String.Format("{{{0}}}", _appGuid);
            }

            MutexAccessRule allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
            MutexSecurity securitySettings = new MutexSecurity();
            securitySettings.AddAccessRule(allowEveryoneRule);

            bool createdNew;
            _mutex = new Mutex(false, mutexId, out createdNew, securitySettings);

            bool hasHandle = false;
            try
            {
                hasHandle = _mutex.WaitOne(0, false);
                if (!hasHandle)
                {
                    return true;
                }
            }
            catch (AbandonedMutexException)
            {
                hasHandle = true;
            }

            return false;
        }

        public static void ShowRunningApp()
        {
            Process current = Process.GetCurrentProcess();
            foreach (Process process in Process.GetProcesses())
            {
                if (process.Id == current.Id)
                {
                    continue;
                }

                try
                {
                    Assembly assembly = Assembly.LoadFrom(process.MainModule.FileName);

                    string processGuid = GetAssemblyGuid(assembly);
                    if (_appGuid.Equals(processGuid))
                    {
                        BringProcessToFront(process);
                        return;
                    }
                } catch { }
            }
        }

        private static string GetAssemblyGuid(Assembly assembly)
        {
            object[] customAttribs = assembly.GetCustomAttributes(typeof(GuidAttribute), false);
            if (customAttribs.Length < 1)
            {
                return null;
            }

            return ((GuidAttribute)(customAttribs.GetValue(0))).Value.ToString();
        }

        private static void BringProcessToFront(Process process)
        {
            IntPtr handle = process.MainWindowHandle;
            if (IsIconic(handle))
            {
                ShowWindow(handle, SW_RESTORE);
            }

            SetForegroundWindow(handle);
        }
    }
}
TheLethalCoder
  • 6,668
  • 6
  • 34
  • 69