All posts in Console

If you arrived here chances are you have a WPF application you want to lock down to running only once. Maybe you tried doing it by looking at Process.GetProcesses() but found it to be slow and unreliable and wanted something a bit more straight forward? Well, mutexes would be the most direct way to go. There are a few articles on the web about how to do this in .Net and they go into great detail about how mutexes work and how developers misuse them all the time. I am going to touch on the pieces you need for this solution and not waste any more of your time.

Q: What is a mutex?
A: If you took Computer Science courses this should be a no-brainer, but let’s assume you didn’t.

Mutex is short for a mutual exclusion object. This exists as a uniquely named resource that can be shared across multiple threads. Each thread would need to lock the resource to use it, so it cannot be accessed simultaneously.

Q: How does this help me?
A: Multiple applications can access the mutex allowing you to create a unique token to be reserved by a specific application instance.

Now we get to the how part.
First, let create a mutex placeholder and a unique key for our mutex:


private static Mutex _instanceMutex;
private static string MyApplicationKey = "{0036BC97-7DE3-4934-9928-43CE53CBF0AA}";

Next let’s create some key methods to set, evaluate, and terminate our mutex:


/// <summary>
/// Checks if application is already running.
/// </summary>
/// <returns></returns>
public static bool StartInstance()
{
    // Set mutex
    _instanceMutex = new Mutex(true, Constants.MyApplicationKey);

    // Check if already running
    bool isAlreadyInUse = false;
    try 
    {
        isAlreadyInUse = !_instanceMutex.WaitOne(TimeSpan.Zero, true);
    }
    catch (AbandonedMutexException)
    {
        KillInstance();
        isAlreadyInUse = false;
    }
    catch (Exception)
    {
        _instanceMutex.Close();
        isAlreadyInUse = false;
    }
    return isAlreadyInUse;
}

/// <summary>
/// Kills the instance.
/// </summary>
/// <param name="code">The code.</param>
public static void KillInstance(int code = 0)
{
    if (_instanceMutex == null) return;

    // Owning application should release mutex
    if (code == 0)
    {
        try
        {
            _instanceMutex.ReleaseMutex();
        }
        catch (Exception) { }
    }
    _instanceMutex.Close();
}

StartInstance does a few key things:

  • Claim ownership of a new mutex with our application key.
  • Evaluate the mutex by invoking a WaitHandle.
  • An AbandonedMutexException exception may occur which means the mutex exists but was not properly released by the owning process. This is likely caused by the owning process exiting unexpectedly. We kill the mutex in this case (covered later) and set this as not in use.
  • If a general exception occurs we simply close the instance and set it to not in use.
  • Otherwise, it is already in use.

 
Hold on a second!

Q: What is the difference between Releasing a mutex and Closing a mutex?
A: This is an important question.

Releasing a mutex (Mutex.ReleaseMutex()) releases a mutex from memory. This means no application can access it and it will need to be created again. Only the owning application can release the mutex unless that application is no longer in memory.

Closing a mutex (Mutex.Close()) in .Net really means closing the WaitHandle associated with the mutex. This should always be done after accessing a mutex.

 
KillInstance works as follows:

  • If a standard exit code of 0 is provided it assumes itself the owner of the mutex and attempts to release it.
  • The mutex is then closed.

 
And that’s all you need. So, let’s put it in an example.

Let’s add it to our App.xaml.cs OnStartup and OnExit as follows:


/// <summary>
/// Raises the <see cref="E:System.Windows.Application.Startup" /> event.
/// </summary>
/// <param name="e">A <see cref="T:System.Windows.StartupEventArgs" /> that contains the 
/// event data.</param>
protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);

    // Check if running
    if (!StartInstance()) return;
    
	// Apparently we are already running our app
    MessageBox.Show("Already Running!");

    // If running, peace out
    Application.Current.Shutdown(1);
}

/// <summary>
/// Raises the <see cref="E:System.Windows.Application.Exit"/> event.
/// </summary>
/// <param name="e">An <see cref="T:System.Windows.ExitEventArgs"/> that contains the event 
/// data.</param>
protected override void OnExit(ExitEventArgs e)
{
    base.OnExit(e);

    // Kill instance
    KillInstance(e.ApplicationExitCode);
}

  1. OnStartup evaluates whether the mutex is already in use. If it is, it tells the user it is already running and exits the application.
  2. OnExit passes the exit code to KillInstance and handles closing the mutex.

 
And that’s it! I recommend you read up more on mutexes to make absolutely sure you are comfortable with this approach. But for now, this should get you what you need to get back to work.

Happy coding!

Getting the Windows Key

Categories: .Net, C#, Console, WPF
Comments: No

In my last post I went over how to retrieve the Windows Product Activation information from Windows Vista / 7.0 / 2008. Today, we are going to do something on the same thread but very much more desirable. And that is retrieving the Windows Key information.

For as long as Windows has had a key, admins have been looking to be able to retrieve the Windows key information on the fly: especially when they need to do a re-install and lost their original media casing.

So, let’s get right to it with a console application.


static void Main(string[] args)
{
    string computername = Environment.MachineName;
    const RegistryHive registryRoot = RegistryHive.LocalMachine;
    const string sSubKeyName = @"SOFTWAREMicrosoftWindows NTCurrentVersion";
    const string sValueName = "DigitalProductId";
    string windowsKey = "";

    // Get product Id
    RegistryKey regoutput = RegistryKey.OpenRemoteBaseKey(
        registryRoot, computername, RegistryView.Default).
        OpenSubKey(sSubKeyName);

    // Convert to byte array
    byte[] digitalProductId;
    if (regoutput != null)
    {
        digitalProductId = regoutput.GetValue(sValueName) as byte[];

        // Get Windows Product Key
        windowsKey = (digitalProductId != null)
            ? DecodeProductKey(digitalProductId)
            : "The product key was not accessible";
    }

    else
    {
        windowsKey = "The product key was not accessible";
    }

    // Output 
    Console.WriteLine(windowsKey);
    Console.Read();
}

In this example, I am choosing my local machine as the target. The location of the value we want is located in the registry here:
HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionDigitalProductId.

We then get the byte array representing the key and decode it with the below method.


/// <summary>
/// Decodes a Microsoft product key based on the provided digital product id.
/// </summary>
/// <param name="digitalProductId">The digital product id.</param>
/// <returns></returns>
private static string DecodeProductKey(byte[] digitalProductId)
{
    // Offset of first byte of encoded product key in 
    //  'DigitalProductIdxxx" REG_BINARY value. Offset = 34H.
    const int keyStartIndex = 52;

    // Offset of last byte of encoded product key in 
    //  'DigitalProductIdxxx" REG_BINARY value. Offset = 43H.
    const int keyEndIndex = keyStartIndex + 15;

    // Possible alpha-numeric characters in product key.
    var digits = new[]
            {
                'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R',
                'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9'
            };

    // Length of decoded product key
    const int decodeLength = 29;

    // Length of decoded product key in byte-form.
    // Each byte represents 2 chars.
    const int decodeStringLength = 15;

    // Array of containing the decoded product key.
    var decodedChars = new char[decodeLength];

    // Extract byte 52 to 67 inclusive.
    var hexPid = new ArrayList();
    for (int i = keyStartIndex; i <= keyEndIndex; i++)
    {
        hexPid.Add(digitalProductId[i]);
    }
    for (int i = decodeLength - 1; i >= 0; i--)
    {
        // Every sixth char is a separator.
        if ((i + 1) % 6 == 0)
        {
            decodedChars[i] = '-';
        }
        else
        {
            // Do the actual decoding.
            int digitMapIndex = 0;
            for (int j = decodeStringLength - 1; j >= 0; j--)
            {
                int byteValue = (digitMapIndex << 8) | (byte)hexPid[j];
                hexPid[j] = (byte)(byteValue / 24);
                digitMapIndex = byteValue % 24;
                decodedChars[i] = digits[digitMapIndex];
            }
        }
    }
    return new string(decodedChars);
}

Now, if you are running 64-bit Windows (and most of us are), you may be running into problems getting your byte array. Why is that? Well, the short answer is that it has to do with your Configuration Manager settings. The default platform target is x86: which does not have access to several 64-bit spaces including certain registry values.

You can change that by doing the following in Visual Studio:

  1. Open your Project Properties.
  2. Go to the Build tab.
  3. For each Configuration set the Platorm target to Any CPU.
  4. For Visual Studio 2012, make sure to uncheck Prefer 32-bit.

That’s all there is to it.

Until next time.