11

I'm working an application of which only one instance must exist at any given time. There are several possibilities to accomplish this:

  • Check running processes for one matching our EXE's name (unreliable)
  • Find the main window (unreliable, and I don't always have a main window)
  • Create a mutex with a unique name (GUID)

The mutex option seems to me the most reliable and elegant.

However, before my second instance terminates, I want to post a message to the already running instance. For this, I need a handle to the thread (or the process) that owns the mutex.

However, there seems to be no API function to get the creator/owner of a given mutex. Am I just overlooking it? Is there another way to get to this thread/process? Is there another way to go about this?

Update: This guy simply broadcast a message to all running processes. I guess that's possible, but I don't really like it...

Thomas
  • 174,939
  • 50
  • 355
  • 478
  • Duplicate? http://stackoverflow.com/questions/19147/what-is-the-correct-way-to-create-a-single-instance-application – Dead account Dec 22 '09 at 16:13
  • Not really. None of the answers tells me how to get the process handle. – Thomas Dec 22 '09 at 16:14
  • Here's a duplicate, although it was never answered: http://stackoverflow.com/questions/541477/c-how-can-i-get-owners-name-for-a-mutex – Eric Petroelje Dec 22 '09 at 16:18
  • Well, it was answered, but probably not in the way the questioner hoped it would be :) – Eric Petroelje Dec 22 '09 at 16:20
  • I wouldn't call that an exact duplicate either; although it answers my primary question, it does not provide an alternative solution -- something I explicitly asked for. – Thomas Dec 22 '09 at 16:22
  • Not putting this as an answer (since it is not an answer), but it may be of interest: http://msdn.microsoft.com/en-us/library/aa446629%28VS.85%29.aspx shows how to get the owner (in the sense of the user) of a file lock, and you could apply the same to a mutex. Still doesn't give you a PID though. – Logan Capaldo Dec 22 '09 at 16:37

6 Answers6

12

This should get you started on the original request to get a process that owns a mutex.

It's in C#, but the Win32 calls are the same.

class HandleInfo
{
    [DllImport("ntdll.dll", CharSet = CharSet.Auto)]
    public static extern uint NtQuerySystemInformation(int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, out int ReturnLength);

    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern IntPtr VirtualAlloc(IntPtr address, uint numBytes, uint commitOrReserve, uint pageProtectionMode);

    [DllImport("kernel32.dll", SetLastError=true)]
    internal static extern bool VirtualFree(IntPtr address, uint numBytes, uint pageFreeMode);

    [StructLayout(LayoutKind.Sequential)]
    public struct SYSTEM_HANDLE_INFORMATION
    {
        public int ProcessId;
        public byte ObjectTypeNumber;
        public byte Flags; // 1 = PROTECT_FROM_CLOSE, 2 = INHERIT
        public short Handle;
        public int Object;
        public int GrantedAccess;
    }

    static uint MEM_COMMIT = 0x1000;
    static uint PAGE_READWRITE = 0x04;
    static uint MEM_DECOMMIT = 0x4000;
    static int SystemHandleInformation = 16;
    static uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;

    public HandleInfo()
    {
        IntPtr memptr = VirtualAlloc(IntPtr.Zero, 100, MEM_COMMIT, PAGE_READWRITE);

        int returnLength = 0;
        bool success = false;

        uint result = NtQuerySystemInformation(SystemHandleInformation, memptr, 100, out returnLength);
        if (result == STATUS_INFO_LENGTH_MISMATCH)
        {
            success = VirtualFree(memptr, 0, MEM_DECOMMIT);
            memptr = VirtualAlloc(IntPtr.Zero, (uint)(returnLength + 256), MEM_COMMIT, PAGE_READWRITE);
            result = NtQuerySystemInformation(SystemHandleInformation, memptr, returnLength, out returnLength);
        }

        int handleCount = Marshal.ReadInt32(memptr);
        SYSTEM_HANDLE_INFORMATION[]  returnHandles = new SYSTEM_HANDLE_INFORMATION[handleCount];

        using (StreamWriter sw = new StreamWriter(@"C:\NtQueryDbg.txt"))
        {
            sw.WriteLine("@ Offset\tProcess Id\tHandle Id\tHandleType");
            for (int i = 0; i < handleCount; i++)
            {
                SYSTEM_HANDLE_INFORMATION thisHandle = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(
                    new IntPtr(memptr.ToInt32() + 4 + i * Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION))),
                    typeof(SYSTEM_HANDLE_INFORMATION));
                sw.WriteLine("{0}\t{1}\t{2}\t{3}", i.ToString(), thisHandle.ProcessId.ToString(), thisHandle.Handle.ToString(), thisHandle.ObjectTypeNumber.ToString());
            }
        }

        success = VirtualFree(memptr, 0, MEM_DECOMMIT);
    }
}
GalacticJello
  • 11,235
  • 2
  • 25
  • 35
  • 1
    "NtQuerySystemInformation may be altered or unavailable in future versions of Windows. Applications should use the alternate functions listed in this topic." And SystemHandleInformation is entirely undocumented. Yikes! – Thomas Dec 22 '09 at 22:51
  • 10
    Actually, I was just trying to help you out. I had to dig up some of my esoteric C++ code from way back, but instead of trudging back into VC6, I decided to port it to C# for you and others (to make it a bit more current). I guess I didn't know you couldn't use undocumented stuff, you just asked if it was possible... – GalacticJello Jan 12 '10 at 05:04
  • From this code you would then go and call `NtQueryMutant` to get the owner status and the PID/ThreadID of the owner. – josh poley Aug 23 '13 at 20:01
7

I don't think there is a trivial way to resolve the actual owner of a Mutex, but the process that owns it can create other secondary items whose lifetimes are tied to it. There are plenty of mechanisms that are suitable for calling back across-process without having a main window.

  1. Register an object in the COM Running Object Table. Clients that are unable to take ownership of the Mutex can lookup the owner via the ROT and call back to the owner. A File Moniker should be suitable for registration here.
  2. Create a chunk of shared memory containing location details for the owner process. From there, write into the buffer the process handle and thread handle of a thread that can receive windows messages, and then use PostThreadMessage() to send a notification. Any other competing process may open the shared memory for read-only to determine where to send a windows message.
  3. Listen in the owner process on a Socket or Named Pipe. Probably overkill and not a good match for your needs.
  4. Use a shared file with locking. I'm not fond of this because the owner will need to poll, and it won't gracefully handle N potential other processes that could be trying to contact the owner at the same time.

Here are reference links for the first two options.

  1. IRunningObjectTable @ MSDN , File Monikers @ MSDN
  2. Creating Named Shared Memory @ MSDN
takrl
  • 6,356
  • 3
  • 60
  • 69
meklarian
  • 6,595
  • 1
  • 23
  • 49
2

I have never really understood the rational behind using a Mutex which has no signaling capability. I would instead create an event (using CreateEvent) which has the same properties as creating a mutex (i.e. with a name it can return that the object already existed) but you can set the event flag in the new process, as long as the original process is waiting on the event flag it can be notified when it needs to wake itself up.

tyranid
  • 13,028
  • 1
  • 32
  • 34
  • 2
    Of course, the original process is not blocking waiting for an event; it's just running circles in its message loop. (I could check the mutex each time through the loop, but that feels evil.) – Thomas Dec 22 '09 at 16:24
  • You could always run another thread, have it sleep on the event, and post to the message loop when something happens. – Thanatos Dec 22 '09 at 16:29
  • 3
    There is also MsgWaitForMultipleObjects which allows you to wait for either a windows message to arrive or a waitable handle (say and event or mutex) to be signalled allowing you to do it in one thread. – tyranid Dec 23 '09 at 14:34
2

You could always do it the UNIX way and create a "pid" file, putting the process id of the currently running instance into that file. Then have the app delete the file when it exits.

When a new instance starts up it should verify that the process in the PID file is actually alive as well (in case the app exits abnormally and the file doesn't get deleted)

Eric Petroelje
  • 59,820
  • 9
  • 127
  • 177
  • +1. You can even use a file lock on this file instead of a separate Mutex. – Logan Capaldo Dec 22 '09 at 16:25
  • Similar to this, could you use a shared memory, and write the PID there? – Thanatos Dec 22 '09 at 16:28
  • No need to go through the filesystem, actually... a piece of shared memory (`CreateFileMapping`) will do just fine. Thanks for putting me on this track. I'll accept this unless someone comes up with a better solution. – Thomas Dec 22 '09 at 16:33
2

Create a shared memory area with the fixed name:

http://msdn.microsoft.com/en-us/library/aa366551%28VS.85%29.aspx

Then you can put any structure you like inside, including process id, HWND etc.

There's a portable option: create a socket on a port (with a fixed number) and wait (accept) on it. The second instance of the app will fail since the port is already taken. Then the second instance can connect to the socket of the primary instance and send any information desired.

I hope this helps...

  • In general, sockets are bad for this. They require some port number to be hard-coded; what if this number would already be occupied? Creating listening connection also makes an app very suspicious if its functions do not require this. I'd consider, say, notepad that accepts incoming connections a 100% malicious software. As long as end-user software is considered, socket communication is OK only for specific apps like FileZilla server and interface. Of course, enterprise software could require any option it wants. I'd recommend named pipes for this. – Fr0sT Mar 24 '14 at 13:02
0

I had similar problems. I am want a function that returns if a single instance of an app is running. Then another function to bring the app to the front. In which I must first deduce the HWND of the already running window.

FindWindow sucks big time. Window titles can change, another window could be using the same class and title, etc.

Then I thought maybe extra data could be stored with a mutex. But I dont see where user data can be stored in a mutex object or event object. But a mutex knows which thread it belongs to and thus which process it belongs to. But as you said, the api doesnt seem to exist.

Many new and complicated looking methods have been suggested here; with the exeception of simply using a file. So I want to add another method, temporary registry keys.

This method is easiest for me as I already built an hkey library. But the win32 registry api is pretty straight forward compared to the horrifying looking shared memory method.

user13947194
  • 337
  • 5
  • 7