views:

388

answers:

2

Hello, 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();
            }
        }
    }
A: 

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.

Hans Passant
A: 

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\".

binarycoder
The problem is the .Net Mutex that works for XP and Vista, is not being detected by an unmanaged program (c++) for Windows 7. On Windows 7, GetLastError() always returns ERROR_SUCCESS whether the mutex exists or not. So, I am attempting to change the way I call the mutex to accomodate the native c++ code. NOTE: the .net mutex to .net works fine on Windows 7. The .Net mutex to interop c++ mutex is what is failing... could be on the c++ side.
mytwocents
I think the problem is not that the mutex not being created in a globally recognized way in Windows 7 since a service is creating it. I've appended "Global\" to the mutex name since some posts indicated that worked for them. However, that doesn't work for me either. (The mutex created by the service doesn't show up in the ProcessExplorer find handle, but I know it's there because if I run the same program, the mutex wanrns its already created.) Microsoft, what's going on with services and mutextes?
mytwocents