Normally (i.e. without TS), You can detect if your app is already running by using something like this:
public static bool IsAppAlreadyRunning() { Process currentProcess = Process.GetCurrentProcess(); return Process.GetProcessesByName(currentProcess.ProcessName).Length > 1; }Now obviously, this will find a running instance in a different TS session too - not what we want.
Enter the Mutex:
A mutex can control access to a shared resource, even across different processes. A mutex can be constructed like so:
new Mutex(true, QualifiedMutexName, out mutexCreated);The value returned in the out parameter indicates whether this constructor actually created the mutex or not (it could have been created by another thread, even running in a different process). From here, detecting apps running in the Same TS session is a synch.
One thing to note: The name of the mutex is important:
- If the mutex-name starts with "Global\", the mutex is visible in all terminal server sessions.
- If the mutex-name starts with "Local\", the mutex is visible only in the terminal server session where it was created.
I created a simple wrapper class for the mutex as follows:
public class AppMutex : IDisposable { protected Mutex mutex; private String mutexName; private String QualifiedMutexName { get { return String.Format(@"Global\{0}", mutexName); } } public AppMutex(String _mutexName) { mutexName = _mutexName; } public bool AlreadyActive { get { bool mutexCreated; if (mutex != null) return true; mutex = new Mutex(true, QualifiedMutexName, out mutexCreated); return !mutexCreated; } } public void Dispose() { if (mutex != null) { mutex.ReleaseMutex(); } } }Now i don't really like the fact the the AlreadyActive property actually creates the mutex too, but the idea is that this is called once at application startup, so it suffices for me.
I use the TS session ID as part of the mutex name (combined with the application name), as follows:
private static string GetTSAppId() { string appId = String.Format("{0}_{1}", GetTSSessionID(), Process.GetCurrentProcess().ProcessName); return appId; } public static uint GetTSSessionID() { try { Process _currentProcess = Process.GetCurrentProcess(); uint processID = (uint)_currentProcess.Id; uint sessionID; bool result = ProcessIdToSessionId(processID, out sessionID); if (!result) { log.Error("Not able to retrieve Terminal-Services Session ID"); return 0; } return sessionID; } catch (Exception ex) { log.Error("Unable to determine session ID", ex); return 0; } }, and construct the mutex in the static constructor of a Utility class:
private static AppMutex appMutex; static Utility() { if (IsRemoteSession()) { string tsAppId = GetTSAppId(); Console.WriteLine("Creating application mutex. ID={0}", tsAppId); appMutex = new AppMutex(tsAppId); } }Then we just check if the app is already running in the current TS session like so:
public static bool IsAppAlreadyRunning() { return appMutex.AlreadyActive; }
No comments:
Post a Comment