Don't worry, the Exif series is not closed yet... preparing Part 4 just
requires more work...
This new post series is dedicated to - as title say - the
creation of a single instance application. That is, application that can only
run once simultaneously. That's a frequently encountered issue, particularly
when your program makes use of resources that cannot be shared (overlay video
surfaces, network listen ports, etc.)
My solution to the single instance application problem is to create a class
called ProcessLock that can be locked, unlocked, and indicate whether
the application is running.
The ProcessLock implements the IDisposable interface, so that the
process lock can be locked and unlocked through a using statement. The
implementation uses a named mutex (with is global to the user session).
The ProcessLock tries to create the underlying mutex in the constructor.
A failure means that the mutex does already exist : the application is running.
#region
References
using System;
using System.Diagnostics;
using System.Threading;
#endregion
namespace SingleInstance {
///
<summary>
/// Provides a lock object to
prevent a program from being launched multiple times.
/// </summary>
public class ProcessLock
: IDisposable {
#region Fields
private string applicationName;
private Mutex mutex;
private bool created;
private bool disposed;
#endregion
#region Instance Management
/// <summary>
/// Initializes a new instance
of the <see cref="ProcessLock"/>
class.
/// </summary>
/// <param
name="applicationName">Name of the
process lock</param>
public ProcessLock(
string
applicationName) {
this.applicationName
= applicationName;
TryLock();
}
/// <summary>
/// Disposes the process lock
resources.
/// </summary>
public void Dispose()
{
if (mutex!=
null){
if
(created)
Unlock();
else {
mutex.Close();
mutex = null;
}
}
disposed =
true;
}
#endregion
#region Properties
/// <summary>
/// Indicates whether a process
for the given name does already exist.
/// </summary>
public bool AlreadyExists
{
}
/// <summary>
/// Indicates whether the
process lock is disposed.
/// </summary>
public bool Disposed
{
}
#endregion
#region Methods
/// <summary>
/// Try to get the process lock
again.
/// </summary>
public bool TryLock(){
if
(disposed)
throw
new ObjectDisposedException("ProcessLock");
if (created)
throw
new InvalidOperationException();
if (mutex!=
null)
mutex.Close();
mutex =
new Mutex(
true,
applicationName,
out created);
return created;
}
/// <summary>
/// Releases the process lock.
/// </summary>
public void Unlock()
{
if (disposed)
throw
new ObjectDisposedException(
"ProcessLock");
if (!created)
throw
new InvalidOperationException();
Debug.Assert(mutex!=
null);
mutex.ReleaseMutex();
mutex =
null;
created =
false;
}
#endregion
}
}
. . .
Using a ProcessLock is quite straight-forward. A sample Console
application follows (you will note the use of System.Reflection.Assembly
for retrieving the application name) :
using
System;
using System.Reflection;
namespace SingleInstance
{
public
sealed class SingleInstance
{
private SingleInstance(){}
private static
readonly string assemblyName =
Assembly.GetExecutingAssembly().GetName().Name;
/// <summary>
/// Application entry point.
/// </summary>
[STAThread]
static void Main() {
using(ProcessLock
processLock =
new ProcessLock(assemblyName)) {
if
(processLock.AlreadyExists)
return;
// The program operation must run inside the 'using' block.
Run();
}
}
private static
void Run() {
Console.WriteLine("{0}
running. Press 'Enter' to exit.", assemblyName);
Console.ReadLine();
}
}
}
. . .
In the next post, I will explain how to bring a window to the foreground, even if it is currently invisible...