- //
- // SingleInstance.cs
- //
- // Author: Shams Madhani {sdotmadhaniatgmxdotcom}
- //
- // Licensed under BSD or compatible license.
- // Redistribution and use in source and binary forms, with or without modification,
- // are permitted provided that the conditions set forth by BSD license are met.
- //
- // References: To be added..
- //
- using System;
- using System.IO;
- //using System.IO.Pipes;
- using System.Threading;
- using System.Collections.Generic;
- using System.Security.Permissions;
- namespace singleinstance
- {
- public class ArgumentsReceivedEventArgs : EventArgs
- {
- public String[] Args { get; set; }
- }
- public class SingleInstance : IDisposable
- {
- public static string argfilepath = Environment.CurrentDirectory;
- public static string argfile = "newargs.txt";
- public Mutex mutex = null;
- private Boolean ownsMutex = false;
- public Guid identifier = Guid.Empty;
- FileSystemWatcher watcher = new FileSystemWatcher();
- DateTime lastRead = DateTime.MinValue;
- /// <summary>
- /// Enforces single instance for an application.
- /// </summary>
- /// <param name="identifier">An identifier unique to this application.</param>
- public SingleInstance(Guid identifier)
- {
- this.identifier = identifier;
- mutex = new Mutex(true, identifier.ToString(), out ownsMutex);
- }
- /// <summary>
- /// Indicates whether this is the first instance of this application.
- /// </summary>
- public Boolean IsFirstInstance
- { get { return ownsMutex; } }
- /// <summary>
- /// Passes the given arguments to the first running instance of the application.
- /// </summary>
- /// <param name="arguments">The arguments to pass.</param>
- /// <returns>Return true if the operation succeded, false otherwise.</returns>
- public Boolean PassArgumentsToFirstInstance(String[] arguments)
- {
- if (IsFirstInstance)
- throw new InvalidOperationException("This is the first instance.");
- if (!File.Exists(argfile))
- File.Create(argfile);
- File.WriteAllText(argfile, "");
- foreach (string argument in arguments)
- {
- File.AppendAllText(argfile, argument+Environment.NewLine);
- }
- return false;
- }
- /// <summary>
- /// Listens for arguments being passed from successive instances of the applicaiton.
- /// </summary>
- public void ListenForArgumentsFromSuccessiveInstances()
- {
- if (!IsFirstInstance)
- throw new InvalidOperationException("This is not the first instance.");
- ThreadPool.QueueUserWorkItem(new WaitCallback(ListenForArguments));
- GC.KeepAlive(mutex);
- Thread.Sleep(1000);
- }
- /// <summary>
- /// Listens for arguments on a named pipe.
- /// </summary>
- /// <param name="state">State object required by WaitCallback delegate.</param>
- private void ListenForArguments(Object state)
- {
- if (!File.Exists(argfile))
- File.Create(argfile);
- watcher.Path = argfilepath;
- watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
- watcher.Filter = argfile;
- watcher.Changed += new FileSystemEventHandler(OnChanged);
- watcher.IncludeSubdirectories = false;
- watcher.EnableRaisingEvents = true;
- }
- private void OnChanged(Object state, FileSystemEventArgs e)
- {
- DateTime lastWriteTime = File.GetLastWriteTime(argfile);
- if (lastWriteTime != lastRead)
- {
- try
- {
- watcher.EnableRaisingEvents = false;
- Console.WriteLine("This is the first instance.");
- Thread.Sleep(1000);
- try
- {
- String line;
- List<String> arguments = new List<String>();
- using (StreamReader sr = new StreamReader(argfile))
- {
- while (sr.Peek() >= 0)
- {
- line = sr.ReadLine();
- arguments.Add(line);
- }
- sr.Dispose();
- }
- ThreadPool.QueueUserWorkItem(new WaitCallback(CallOnArgumentsReceived), arguments.ToArray());
- Thread.Sleep(1000);
- }
- catch (Exception exp1)
- {
- // Let the user know what went wrong.
- Console.WriteLine("The file could not be read:");
- Console.WriteLine(exp1.Message);
- }
- }
- finally
- {
- //Thread.Sleep(1000);
- watcher.EnableRaisingEvents = true;
- }
- lastRead = lastWriteTime;
- }
- }
- /// <summary>
- /// Calls the OnArgumentsReceived method casting the state Object to String[].
- /// </summary>
- /// <param name="state">The arguments to pass.</param>
- private void CallOnArgumentsReceived(Object state)
- {
- OnArgumentsReceived((String[])state);
- }
- /// <summary>
- /// Event raised when arguments are received from successive instances.
- /// </summary>
- public event EventHandler<ArgumentsReceivedEventArgs> ArgumentsReceived;
- /// <summary>
- /// Fires the ArgumentsReceived event.
- /// </summary>
- /// <param name="arguments">The arguments to pass with the ArgumentsReceivedEventArgs.</param>
- private void OnArgumentsReceived(String[] arguments)
- {
- if (ArgumentsReceived != null)
- ArgumentsReceived(this, new ArgumentsReceivedEventArgs() { Args = arguments });
- }
- #region IDisposable
- private Boolean disposed = false;
- protected virtual void Dispose(bool disposing)
- {
- if (!disposed)
- {
- if (mutex != null && ownsMutex)
- {
- mutex.ReleaseMutex();
- mutex = null;
- }
- disposed = true;
- }
- }
- ~SingleInstance()
- {
- Dispose(false);
- }
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- #endregion
- }
- }
Single instance command line application in C# using Mono