How to call win32 CreateMutex from .Net

2019-01-27 08:32发布

问题:

I've been successfully creating a .net mutex like this: SingleIns = new Mutex(true, AppName); for a while. It works in XP, Vista, but apparently not in Windows7. So I need to make an interop call to a Win32 library so other Com components can identify the mutex. I found the following code, but the Win32Calls. is not found... is there an assembly or reference I need? Thanks in advance,

Found code from: http://www.pinvoke.net/default.aspx/kernel32/CreateMutex.html

using System.Runtime.InteropServices;

    [DllImport("kernel32.dll")]
    public static extern IntPtr CreateMutex(IntPtr lpMutexAttributes, bool bInitialOwner, string lpName);


       // create IntPtrs for use with CreateMutex()
        IntPtr    ipMutexAttr = new IntPtr( 0 );
        IntPtr    ipHMutex = new IntPtr( 0 );

        try
        {
            // Create the mutex and verify its status BEFORE construction
            // of the main form.

            ipHMutex = Win32Calls.CreateMutex( ipMutexAttr,
                true, "CompanyName_AppName_MUTEX" );

            if (ipHMutex != (IntPtr)0)
            {
                // check GetLastError value (MUST use this call. See MSDN)

                int iGLE = Marshal.GetLastWin32Error();

                // if we get the ERROR_ALREADY_EXISTS value, there is
                // already another instance of this application running.

                if (iGLE == Win32Calls.ERROR_ALREADY_EXISTS)
                    // So, don't allow this instance to run.
                    return;
            }
            else    
            {    // CreateMutex() failed.
                // once the app is up and running, I log the failure from
                // within the frmMain constructor.
                bool m_bMutexFailed = true;
            }

            // construct the main form object and
            //form = new frmMain();

            // run the app.
            //Application.Run( form );

        }
        catch( Exception oEx )
        {
            //...handle it...
        }
        finally
        {
            // release the mutex
            if (ipHMutex != (IntPtr)0)
                Win32Calls.ReleaseMutex( ipHMutex );

            // cleanup the main form object instance.
            if (form != null) {
                form.Dispose();
            }
        }
    }

回答1:

It doesn't work is because you CreateMutex declaration is not in the Win32Calls namespace. Your next problem is that it still won't work because you forgot to set the SetLastError property in the [DllImport] attribute. Required to make Marshal.GetLastWin32Error() return the error.

Rewinding a bit, using the Mutex class in Win7 should work without a problem. The only failure mode I can think of is not prefixing the mutex name with "Global\" so the mutex is visible in all sessions. That's a bit remote.

More to the point, you are trying to do something that is already very well supported in the .NET framework. Project + Add Reference, select Microsoft.VisualBasic. Make your Program.cs code look like this:

using System;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;

namespace WindowsFormsApplication1 {
  class Program : WindowsFormsApplicationBase {
    [STAThread]
    static void Main(string[] args) {
      var prog = new Program();
      prog.EnableVisualStyles = true;
      prog.IsSingleInstance = true;
      prog.MainForm = new Form1();
      prog.Run(args);
    }
  }
}

Bonus goodies with this approach is that it automatically sets the focus to the running instance of your program when the user starts it again. And you can override the OnStartupNextInstance method to know what command line arguments were used and respond accordingly.



回答2:

In case it might help you, the .NET Framework already provides a wrapper of the Win32 mutex object. See System.Threading.Mutex. All of the major functionality is there, including the ability to use prefixes like "Global\".



回答3:

Should be as simple as:

private static System.Threading.Mutex _mutex = null;

const string guid = "{...GUID...}";
bool createdNew;

_mutex = new Mutex(true, guid, out createdNew);

if (!createdNew) {
    // it is in use already
}

system wide mutex creation - ownership: https://stackoverflow.com/a/3111740/1644202