1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
public delegate void NewInstanceMessageEventHandler(object sender, object message);
public class SingleInstanceApplication
{
//win32 translation of APIs, message constants and structures
private class NativeMethods
{
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
public const short WM_COPYDATA = 74;
public struct COPYDATASTRUCT
{
public int dwData;
public int cbData;
public IntPtr lpData;
}
}
//a utility window to communicate between application instances
private class SIANativeWindow : NativeWindow
{
public SIANativeWindow()
{
CreateParams cp = new CreateParams();
cp.Caption = _theInstance._id; //The window title is the same as the Id
CreateHandle(cp);
}
//The window procedure that handles notifications from new application instances
protected override void WndProc(ref Message m)
{
if (m.Msg == NativeMethods.WM_COPYDATA)
{
//convert the message LParam to the WM_COPYDATA structure
NativeMethods.COPYDATASTRUCT data = (NativeMethods.COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.COPYDATASTRUCT));
object obj = null;
if (data.cbData > 0 && data.lpData != IntPtr.Zero)
{
//copy the native byte array to a .net byte array
byte[] buffer = new byte[data.cbData];
Marshal.Copy(data.lpData, buffer, 0, buffer.Length);
//deserialize the buffer to a new object
obj = Deserialize(buffer);
}
_theInstance.OnNewInstanceMessage(obj);
}
else
base.WndProc(ref m);
}
}
//Singleton
static SingleInstanceApplication _theInstance = new SingleInstanceApplication();
//this is a uniqe id used to identify the application
string _id;
//The is a named mutex used to determine if another application instance already exists
Mutex _instanceCounter;
//Is this the first instance?
bool _firstInstance;
//Utility window for communication between apps
SIANativeWindow _notifcationWindow;
private void Dispose()
{
//release the mutex handle
_instanceCounter.Close();
//and destroy the window
if (_notifcationWindow != null)
_notifcationWindow.DestroyHandle();
}
private void Init()
{
_notifcationWindow = new SIANativeWindow();
}
//returns a uniqe Id representing the application. This is basically the name of the .exe
private static string GetAppId()
{
#warning SingleInstance Handler Customisé avec un Guid
return "{107746EE-AD4B-4e7b-B209-CF7F1A93F631}";
}
//notify event handler
private void OnNewInstanceMessage(object message)
{
if (NewInstanceMessage != null)
NewInstanceMessage(this, message);
}
private SingleInstanceApplication()
{
//AUDREY
//_id = "SIA_" + GetAppId();
_id = "SIA_" + GetAppId();
_instanceCounter = new Mutex(false, _id, out _firstInstance);
}
private bool Exists
{
get
{
return !_firstInstance;
}
}
//send a notification to the already existing instance that a new instance was started
private bool NotifyPreviousInstance(object message)
{
//First, find the window of the previous instance
IntPtr handle = NativeMethods.FindWindow(null, _id);
if (handle != IntPtr.Zero)
{
//create a GCHandle to hold the serialized object.
GCHandle bufferHandle = new GCHandle();
try
{
byte[] buffer;
NativeMethods.COPYDATASTRUCT data = new NativeMethods.COPYDATASTRUCT();
if (message != null)
{
//serialize the object into a byte array
buffer = Serialize(message);
//pin the byte array in memory
bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
data.dwData = 0;
data.cbData = buffer.Length;
//get the address of the pinned buffer
data.lpData = bufferHandle.AddrOfPinnedObject();
}
GCHandle dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
NativeMethods.SendMessage(handle, NativeMethods.WM_COPYDATA, IntPtr.Zero, dataHandle.AddrOfPinnedObject());
return true;
}
finally
{
dataHandle.Free();
}
}
finally
{
if (bufferHandle.IsAllocated)
bufferHandle.Free();
}
}
return false;
}
//2 utility methods for object serialization\deserialization
private static object Deserialize(byte[] buffer)
{
using (MemoryStream stream = new MemoryStream(buffer))
{
return new BinaryFormatter().Deserialize(stream);
}
}
private static byte[] Serialize(Object obj)
{
using (MemoryStream stream = new MemoryStream())
{
new BinaryFormatter().Serialize(stream, obj);
return stream.ToArray();
}
}
public static bool AlreadyExists
{
get
{
return _theInstance.Exists;
}
}
public static bool NotifyExistingInstance(object message)
{
if (_theInstance.Exists)
{
return _theInstance.NotifyPreviousInstance(message);
}
return false;
}
public static bool NotifyExistingInstance()
{
return NotifyExistingInstance(null);
}
public static void Initialize()
{
_theInstance.Init();
}
public static void Close()
{
_theInstance.Dispose();
}
public static event NewInstanceMessageEventHandler NewInstanceMessage;
} |
Partager