//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // SmesaMmfIpc.cs from SmesaNewTab.cs // v2.6.1.34 Features Memory Mapped file // form of Inter-Process-Communications. //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // v2.6.0.32 15-Feb-2018 -JpE- // v2.6.1.32 20-Feb-2018 0151 Threading. // v3.0.0.36 28-Feb-2018 0420 MyApp WPF. // v3.0.1.37 01-Mar-2018 Reverted Hybrid // v3.1.1.39 08-Mar-2018 Awesome and // Inspiring! Args passed while running! // v3.1.3.41 19-Mar-2018 2331 Final Adj! // v3.1.3.43 20-Mar-2018 PrefClick Code. // v3.3.5.48 21-Apr-18 Integrated w/PB+ // v4.3.5.49 22-Apr-2018 Integrated. // v4.4.5.53 14-May Bring to Front mods. // v4.7.0.71 19-Sep About Colors. // v4.7.0.72 21-Sep-2018 RC // v4.8.1.79 11-Oct Peruse & Polish. // v4.8.2.80 15-Oct B2F Mechanism // v4.8.2.81 23-Oct Mapper2 interfaced // v4.8.3.85 09-Nov-2018 Favorites Mods. // v4.9.4.90 27-Nov-2018 ReadRemovals() and // GetSelectedIndex() integration completed. // NOTE: See calls to GetSelectedIndex(); //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ using System; using System.IO; using System.Linq; using System.Text; using System.Diagnostics; using System.Windows.Forms; using System.Collections.Generic; using System.Security.Permissions; using System.IO.MemoryMappedFiles; using System.Collections.ObjectModel; using System.Runtime.InteropServices; // Custom NameSpace & Class Library (.dll) using MyCustomLibrary; // Aliases using MCD = MyCustomLibrary.Dialogs; using SMS = MyEditor.Properties.Settings; using SMR = MyEditor.Properties.Resources; using SNM = MyCustomLibrary.SafeNativeMethods; namespace MyEditor { public partial class Smesa { #region Server side IPC MsgN Mods v4.8.2.81.G03 /// if (byte 8190 was flipped /// to 1) then bring Editor to front. /// I correctly assumed that /// 0 is same as null in byte files. /// SO, I will call B2F if 1 and rewrite /// a zero. If 0 is found return back! /// If something else found, from 2-255, /// then that's future growth. /// v4.8.2.81.G02 : 2018-Oct-23 /// Purposely Designed to leave many uses /// for other msgs to Smesa from abroad /// as reuses of the same Watcher /// Event/Delegate & !Handler. /// /// private int CheckForMsgN(long length) { Mx2.WaitOne(); var file = Mapped; var args = new object[] { file, SMS.Default.EditorSize, SMS.Default.EditorOffset1 -2, // See Note Above about ^ this. length, true, Path .GetFileNameWithoutExtension( file), false }; var bites = MemoryMapper .ReverseReadBytes(args); if (bites.Count == 0) { Mx2.ReleaseMutex(); return 4; } if (bites.Count == 1) { if ( bites[0] == 0) { Mx2.ReleaseMutex(); return 3; } if ( bites[0] == 1) { if (TabControl.InvokeRequired) Invoke(new Invoker3(B2F)); else B2F(); // ^ Bring M.E. to Front. Then // Reset v bites to 0. (aka NULL) args[3] = new Collection {0}; if (!MemoryMapper .ReverseWriteBytes(args)) { MessageBox.Show(SMR.MsgN); Mx2.ReleaseMutex(); return 2; } } if (bites[0] > 1) PbSignal(bites[0]); } else BatchRead(bites); Mx2.ReleaseMutex(); // NOTE: return 1; } // todo future msgs to Smesa from abroad. #region Future Mods /* Don't forget that you're going to want * to Zero out any other bites used, or NOT. * Some may become resident as things evolve. * v4.8.2.81 23-Oct-2018 */ private static void PbSignal(byte p) { if (p == 2) DoThis(); if (p == 3) DoThat(); // etc, etc. } private static void DoThat() { const string x = "Doing that!"; MessageBox.Show(x); // expansion ready } private static void DoThis() { const string x = "Doing this!"; MessageBox.Show(x); // expansion ready } private static void BatchRead(IList result) { const string x = "Batch Read!"; MessageBox.Show( string.Format( x + "\n\ndefault = {0}\n\n" + "Count is {1}", result[0], result.Count)); // extreme expansion ready } #endregion Future Mods using MsgN & IPC #endregion IPC MsgN Mods v4.8.2.81.G03 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ #region Server-Side MMF-IPC Handling // Inter-Process-Communications (IPC) with // Memory Mapped File (MMF) & File Watcher. // Smesa is Owner & 1st Instance Server-Side // Code MmfClientSideWrite is Client for 2nd // Instances of MyEditor. (Now in MCT2) /// /// Only ran, once at launch, and /// whenever a msg comes in from abroad. /// This creates _mmf, Delegate, Eventhandler /// & a Reader for it. 2nd instances just /// never see this Server-Side code period. /// /// [ComVisible(false)] private void MmfServerSide(bool read = false) { if (Watcher != null) Watcher.EnableRaisingEvents = false; var temp = MmfManage(read); // NOTE: Clean Exit if not a Mail Run. if (temp.Count < 1) // v MsgN Hook v48281 { if (read && CheckForMsgN(1) > 2) CheckForRemovals(); // <===<< v49386 } else ServerSideMsgReceived(temp); // Mail Received ^ acting on it! if (Watcher != null) Watcher .EnableRaisingEvents = true; } // FOR RELEASE TESTING & DEBUGGING PRINTBLASTER private static void SetPaths(string mapped) { var pb = BlasterPath = WriteShared.AppRoot + SMR.PrintApp; var dir = string.IsNullOrEmpty(pb) || !File.Exists(pb) ? Path.GetDirectoryName(mapped) : Path.GetDirectoryName(BlasterPath); EditorPath = dir + SMR.EdApp; var docs = MyToolbox.GetDocFolder; var file = docs + SMR.PathMe; File.WriteAllText(file, EditorPath); File.SetLastAccessTime( file, DateTime.Now); var path = docs + SMR.PathEd; var maps = dir + "\\" + Path.GetFileName(mapped); File.WriteAllText(path, maps); File.SetLastAccessTime( path, DateTime.Now); // v4.8.2.80 dir = Path.GetDirectoryName(mapped); var me = dir + SMR.ME; File.WriteAllText(me, dir); } private static void LogOut() { var dir = Path.GetDirectoryName(Mapped); var log = dir + SMR.ME; if (File.Exists(log)) File.Delete(log); } /// Args passed in from 2nd Instance! /// Acts on Msg Passed from 2nd Instance client. /// Awesome and inspiring mods! (Rev3.4) /// /// private void ServerSideMsgReceived( ICollection temp) { if (TabControl.InvokeRequired) { // If Called From Worker Thread Invoke(new Invoker1(TabPrompt)); temp.Add(Convert.ToString(_tab)); _myContext.Post(MultiSelect, temp); Invoke(new Invoker3(B2F)); } else // also handles UI thread (test) calls. { temp.Add(Convert.ToString( TabPrompt(TabControl.SelectedIndex))); MultiSelect(temp); B2F(); } } /// This has 2b seperate for /// Invokers (as above) re-written for /// SafeNativeCode Class: Must be static. /// v4.4.5.53 15-May-2018 /// private static void B2F() { SNM.B2F(Process .GetCurrentProcess() .MainWindowHandle); } private static Collection MmfManage(bool read) { var size = SMS.Default.EditorSize; var temp = new Collection(); using (var t = MemoryMappedFile.CreateFromFile( Mapped, FileMode.OpenOrCreate, Path.GetFileNameWithoutExtension( Mapped), size)) { if (read) { // 1st instance Gets Msg from // 2nd instance OR other Apps. #region Read Mail var view = SMS.Default.EditorView1; var offset = SMS.Default.EditorOffset1; using (var reader = t.CreateViewAccessor( offset, view, MemoryMappedFileAccess.ReadWrite)) { // Assessor itself is now Offset. var position = 0; while (position <= view) { var strl = reader.ReadUInt16(position); // ^^^^ = This next byte-array's length. if (strl < 1) break; // No More Are Used. var buff = new byte[strl]; reader.ReadArray( position += 2, buff, 0, strl); position += strl; var str = Encoding.UTF32.GetString(buff); if (string.IsNullOrEmpty(str)) break; temp.Add(str); } // Remember how many bytes were used... var used = position; // <-= Speed Enhancement! // Mail Read, Now Shred only the bytes used. position = 0; // REM: ^ Accessor itself is now offset. while (position <= used // was < // stops at end ^^^^ of current msg... && position <= view) //<-= or file. { // then zeros v out used bytes for next write. reader.Write(position, (ushort) 0); position += 2; } } #endregion Reader } } return temp; } /* Only seen by the 1st Instance of our App. */ private void WaitForProcess2() { if (InvokeRequired) Invoke(new Invoker1(WaitCursor)); else // Display v Spinning Blue Donut! Cursor = Cursors.WaitCursor; List pros; var p = Process.GetCurrentProcess(); do { p.WaitForExit(250); pros = Process.GetProcessesByName( Process.GetCurrentProcess() .ProcessName).ToList(); } while (pros.Count > 1); if (InvokeRequired) Invoke(new Invoker1(ArrowCursor)); else Cursor = Cursors.Arrow; } private void ArrowCursor() { Cursor = Cursors.Arrow; } private void WaitCursor() { Cursor = Cursors.WaitCursor; } #endregion Server-Side MMF-IPC //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ #region Server-Side MMF Watcher, Event & Handler /* Only seen by the 1st Instance of our App. */ private void MmfChangedEventHandler( object sender, EventArgs e) { if (!SMS.Default.MultiTab) return; // It's a Mail Run, brb! WaitForProcess2(); // Okay, Mail Read and Shred, Bye! MmfServerSide(true); } // Only seen by the 1st Instance of our App. [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] private void MmfEventDelegate() { var m = Mapped; Watcher.NotifyFilter = NotifyFilters.LastWrite; Watcher.InternalBufferSize = 2048; //SMS.Default.EditorSize Watcher.EnableRaisingEvents = false; // Setup File System Watcher: Watcher.Path = // for Mapped File. Path.GetDirectoryName(m); Watcher.Filter = Path.GetFileName(m); if (File.Exists(m)) File.Delete(m); // Setup Server-Side of memory-mapped-file: MmfServerSide(); // Create Eventhandler... Watcher.Changed += MmfChangedEventHandler; Watcher.EnableRaisingEvents = true; } #endregion SS MMF Watcher, Event & Handler //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ } }