LeopardSkinPillBoxHat
LeopardSkinPillBoxHat

Reputation: 29421

Need to prevent access to a certain feature while an upgrade is being installed

Our product allows updates to be installed via an MSI installer. An update consists of several files which need to be copied to disk, and the addition of database entries which the installer adds by running several SQL scripts.

Updates can be (and commonly are) installed while the main executable is open. Because of this, I need a way of preventing access to a certain database-intensive feature while the upgrade is in progress.

My current thoughts:

  1. Installer adds a registry key when it starts up.
  2. Update is installed.
  3. On success or failure, the registry key is deleted.

Meanwhile, the application (written in C#) queries for the presence of the registry key, displaying an error dialog if it is set.

Is this reliable? I'm concerned about what happens if the user kills the installer via task manager, then the registry key will never be deleted and the user will be permanently locked out of the feature. Also not sure about any race conditions that the above solution could lead to.

Any suggestions about whether this approach is feasible, or a better approach?

Upvotes: 0

Views: 224

Answers (3)

Christopher Painter
Christopher Painter

Reputation: 55581

Windows Installer already implements a Mutex to indicate that an installation is in progress. Just code your database intensive code to check for that mutex and no-op while it's present. Nothing additional needs to be done.

(Note: using this will stop your processing any time MSI is installing a product which is probably not a bad idea anyways. If you want a unique mutex, it's trivial to write a custom action. )

_MSIExecute Mutex


Update by @LeopardSkinPillBoxHat

The above answer did what I needed. This is the code I ended up using:

    static void Main(string[] args)
    {
        try
        {
            Mutex mutex = Mutex.OpenExisting(@"Global\_MSIExecute");
            if (!mutex.WaitOne(TimeSpan.FromSeconds(5), false))
            {
                Console.WriteLine("Installation in progress!");
                return;
            }
        }
        catch (AbandonedMutexException)
        {
            Console.WriteLine("Mutex was abandoned");
        }
        catch (WaitHandleCannotBeOpenedException)
        {
            Console.WriteLine("MSI installer not running");
        }

        // Perform operation here
    }

Upvotes: 2

HABO
HABO

Reputation: 15816

ALTER DATABASE <name> SINGLE_USER

As described here will break all other connections and allow you to proceed with the update.

Upvotes: 1

Bort
Bort

Reputation: 7618

Would using a named Mutex be reasonable here? Require that the intensive tasks and the updater first acquire the mutex before executing.

EDIT: I lied about wrapping the mutex in a using will protect you from task manager shutdowns. Makes sense, you wouldn't expect finally blocks to execute either. What you'll end up with is an AbandonedMutex, which is discussed in the msdn article I linked.

Also saw recently a useful little article about using a Mutex to prevent multiple instances of the same program from executing.

Upvotes: 2

Related Questions