// internal const int PacketFixedSize = 29; public static SubsequentProcessPacket FromStream(Stream stream) { SubsequentProcessPacket result = new SubsequentProcessPacket(); var buffer = result.BuildPacket(); if (stream.Read(buffer, 0, buffer.Length) == buffer.Length) { int sizeofInt = sizeof(int), sizeofBool = sizeof(bool), sizeofLong = sizeof(long); byte[] guiddata = new byte[buffer.Length - sizeofInt - sizeofBool - sizeofLong]; Buffer.BlockCopy(buffer, sizeofInt + sizeofBool, guiddata, 0, guiddata.Length); result.ArgumentCount = BitConverter.ToInt32(buffer, 0); result.IsMemorySharing = BitConverter.ToBoolean(buffer, sizeofInt); result.SharedID = new Guid(guiddata); result.DataLength = BitConverter.ToInt64(buffer, sizeofInt + sizeofBool + guiddata.Length); return(result); } else { return(null); } }
private void CreateSingleInstanceModel(string[] args) { SubsequentProcessPacket packetHolder = new SubsequentProcessPacket(); byte[] dummypacket = packetHolder.BuildPacket(); using (Mutex mutex = new Mutex(true, Path.Combine("Global", this._instanceID), out var isNewInstanceJustForMeHuh)) using (EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, this._instanceID)) { RegisteredWaitHandle waiter = null; try { if (isNewInstanceJustForMeHuh) { using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew(this._instanceID + "-args", dummypacket.Length, MemoryMappedFileAccess.ReadWrite)) { waiter = ThreadPool.RegisterWaitForSingleObject(waitHandle, new WaitOrTimerCallback((sender, signal) => { using (var stream = mmf.CreateViewStream(0, dummypacket.Length)) { var packet = SubsequentProcessPacket.FromStream(stream); string[] theArgs = new string[packet.ArgumentCount]; string readerIDstring = packet.SharedID.ToString(); if (EventWaitHandle_TryOpenExisting(this._instanceID + "-argreader" + readerIDstring, out var argWaiter)) { try { if (packet.ArgumentCount != 0) { using (MemoryMappedFile argdata = MemoryMappedFile.OpenExisting(this._instanceID + "-argdata" + readerIDstring, MemoryMappedFileRights.Read)) using (BinaryReader br = new BinaryReader(argdata.CreateViewStream(0, packet.DataLength, MemoryMappedFileAccess.Read))) { int biggestbuffer = br.ReadInt32(); byte[] buffer = new byte[biggestbuffer]; for (int i = 0; i < theArgs.Length; i++) { int bufferlength = br.ReadInt32(); br.Read(buffer, 0, bufferlength); theArgs[i] = System.Text.Encoding.Unicode.GetString(buffer, 0, bufferlength); } } } this.OnStartupNextInstance(new StartupNextInstanceEventArgs(theArgs)); } catch (Exception ex) { if (System.Diagnostics.Debugger.IsAttached) { throw; } else { this.OnStartupNextInstance(new StartupNextInstanceEventArgs(ex)); } } finally { argWaiter.Set(); argWaiter.Dispose(); } } } // this._instanceID + "-argreader" + readerID // this.OnStartupNextInstance(e); }), null, -1, false); this.OnStartup(new StartupEventArgs(args)); } } else { Guid readerID = Guid.NewGuid(); using (Mutex writerMutex = new Mutex(true, Path.Combine("Global", this._instanceID + "-argwriter"), out var isNewWriterMutex)) { if (!isNewWriterMutex) { while (!writerMutex.WaitOne()) { } } using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting(this._instanceID + "-args", MemoryMappedFileRights.Write)) using (var accessor = mmf.CreateViewStream(0, dummypacket.Length, MemoryMappedFileAccess.Write)) { try { if (args.Length == 0) { using (EventWaitHandle argWaiter = new EventWaitHandle(false, EventResetMode.ManualReset, this._instanceID + "-argreader" + readerID.ToString(), out var newInstanceForArgs)) { if (newInstanceForArgs) { packetHolder.ArgumentCount = args.Length; packetHolder.IsMemorySharing = true; packetHolder.SharedID = readerID; packetHolder.DataLength = 0; int size = packetHolder.BuildPacket(dummypacket, 0); accessor.Write(dummypacket, 0, size); waitHandle.Set(); // wait until the reader finished get the args // May cause deadlock if the main instance fail to call Set(). So a timeout is required. // 10-second is overkill but it's safe??? argWaiter.WaitOne(TimeSpan.FromSeconds(10)); } else { accessor.Write(dummypacket, 0, dummypacket.Length); waitHandle.Set(); } } } else { int sizeofInt = sizeof(int); // Ensure that the buffer will never be below 4-byte integer so that we can use the buffer for the int->byte conversion. int biggestSize = 0; long datasize = (args.Length * sizeofInt) + sizeofInt; for (int i = 0; i < args.Length; i++) { int aaaaaa = System.Text.Encoding.Unicode.GetByteCount(args[i]); if (biggestSize < aaaaaa) { biggestSize = aaaaaa; } datasize += aaaaaa; } biggestSize += sizeofInt; if (biggestSize < dummypacket.Length) { biggestSize = dummypacket.Length; } packetHolder.ArgumentCount = args.Length; packetHolder.IsMemorySharing = true; packetHolder.SharedID = readerID; packetHolder.DataLength = datasize; using (MemoryMappedFile argData = MemoryMappedFile.CreateNew(this._instanceID + "-argdata" + readerID.ToString(), datasize, MemoryMappedFileAccess.ReadWrite)) using (EventWaitHandle argWaiter = new EventWaitHandle(false, EventResetMode.ManualReset, this._instanceID + "-argreader" + readerID.ToString(), out var newInstanceForArgs)) { if (newInstanceForArgs) { byte[] buffer = new byte[biggestSize]; using (var datastream = argData.CreateViewStream(0, datasize, MemoryMappedFileAccess.Write)) { GetBytesFromIntToBuffer(biggestSize, buffer, 0); datastream.Write(buffer, 0, sizeofInt); for (int i = 0; i < args.Length; i++) { int encodedbytelength = System.Text.Encoding.Unicode.GetBytes(args[i], 0, args[i].Length, buffer, sizeofInt); GetBytesFromIntToBuffer(encodedbytelength, buffer, 0); datastream.Write(buffer, 0, encodedbytelength + sizeofInt); } datastream.Flush(); } int packetsize = packetHolder.BuildPacket(buffer, 0); accessor.Write(buffer, 0, packetsize); buffer = null; waitHandle.Set(); // wait until the reader finished get the args // May cause deadlock if the main instance fail to call Set(). So a timeout is required. // 10-second is overkill but it's safe??? argWaiter.WaitOne(TimeSpan.FromSeconds(10)); } else { // throw new Exception(); } } } } catch { accessor.Write(dummypacket, 0, dummypacket.Length); waitHandle.Set(); if (System.Diagnostics.Debugger.IsAttached) { throw; } } } if (isNewWriterMutex) { writerMutex.ReleaseMutex(); } } } } finally { if (waiter != null) { waiter.Unregister(null); } // Is this required since the mutext is disposed and the instance is exited anyway? // Better safe than sorry. if (isNewInstanceJustForMeHuh) { mutex.ReleaseMutex(); } } } }