Last active
July 28, 2022 18:17
-
-
Save sevaa/9a7dbe682258a2a3c2f404be90d119be to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Win32.SafeHandles; | |
using System.Diagnostics; | |
using System.Text; | |
using System; | |
using System.Threading; | |
namespace COMNET | |
{ | |
public class Program | |
{ | |
[STAThread] | |
public static int Main(string[] args) | |
{ | |
string Cookie = "0123456789"; //In a real application, probably somehow conditional | |
//Run the server process - if that somehow fails, an exception will be thrown | |
StartServer(Cookie); | |
//Pull the server object from the ROT | |
IProtocol Server = new RunningObjectTable().Get(Protocol.MONIKER_PREFIX + Cookie) as IProtocol; | |
//Invoke the method | |
string Response = Server.Hello(17, ASCIIEncoding.ASCII.GetBytes("Hello from client")); | |
Console.WriteLine(Response); | |
return 0; | |
} | |
private static void StartServer(string Cookie) | |
{ | |
using (EventWaitHandle Evt = new EventWaitHandle(false, EventResetMode.AutoReset, Protocol.STARTED_EVENT + Cookie)) | |
{ | |
using (Process? Proc = Process.Start(new ProcessStartInfo("Server.exe", Cookie))) | |
{ | |
if (Proc == null) | |
throw new Exception($"Server could not start"); | |
using (ProcessWaitHandle HProcess = new ProcessWaitHandle(Proc)) | |
{ | |
if (WaitHandle.WaitAny(new WaitHandle[] { Evt, HProcess }) == 1) | |
{ | |
Proc.WaitForExit(); | |
throw new Exception($"Server could not start with exit code {Proc.ExitCode}"); | |
} | |
} | |
} | |
} | |
} | |
public class ProcessWaitHandle : WaitHandle | |
{ | |
public ProcessWaitHandle(Process p) | |
{ | |
SafeWaitHandle = new SafeWaitHandle(p.Handle, false); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Runtime.InteropServices; | |
namespace COMNET | |
{ | |
public class Protocol | |
{ | |
public static readonly string | |
STARTED_EVENT = "COMNET_Started_", | |
MONIKER_PREFIX = "COMNET/"; | |
} | |
[Guid("00020400-0000-0000-C000-000000000046")] //IDispatch, so that it marshals without registration | |
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] | |
public interface IProtocol | |
{ | |
string Hello(int n, byte[] b); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Runtime.InteropServices; | |
using System.Runtime.InteropServices.ComTypes; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace COMNET | |
{ | |
internal class RunningObjectTable | |
{ | |
#region API | |
[DllImport("ole32.dll")] | |
private static extern int CreateItemMoniker([MarshalAs(UnmanagedType.LPWStr)] string | |
lpszDelim, [MarshalAs(UnmanagedType.LPWStr)] string lpszItem, | |
out IMoniker ppmk); | |
[DllImport("ole32.dll")] | |
private static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot); | |
#endregion | |
private IRunningObjectTable m_rot; | |
public RunningObjectTable() | |
{ | |
GetRunningObjectTable(0, out m_rot); | |
} | |
private IMoniker CreateItemMoniker(string s) | |
{ | |
IMoniker mon; | |
CreateItemMoniker("", s, out mon); | |
return mon; | |
} | |
public int Register(string ItemName, object o) | |
{ | |
return m_rot.Register(0, o, CreateItemMoniker(ItemName)); | |
} | |
public void Unregister(int ROTCookie) | |
{ | |
m_rot.Revoke(ROTCookie); | |
} | |
public object Get(string ItemName) | |
{ | |
object o; | |
m_rot.GetObject(CreateItemMoniker(ItemName), out o); | |
return o; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Runtime.InteropServices; | |
using System.Text; | |
using System.Threading; | |
using System; | |
namespace COMNET | |
{ | |
public class Program | |
{ | |
[MTAThread] | |
public static int Main(string[] args) | |
{ | |
string Cookie = args[0]; | |
//Create a server object, register in the Running Object Table with a cookie derived name | |
new RunningObjectTable().Register(Protocol.MONIKER_PREFIX + Cookie, new ServerImpl()) | |
//Report readiness to the parent process | |
using (EventWaitHandle StartedEvent = EventWaitHandle.OpenExisting(Protocol.STARTED_EVENT + Cookie)) | |
StartedEvent.Set(); | |
//And wait for ever. | |
EventWaitHandle QuitEvent = new EventWaitHandle(false, EventResetMode.AutoReset); | |
QuitEvent.WaitOne(); | |
return 0; | |
} | |
} | |
//The server object | |
[ClassInterface(ClassInterfaceType.None)] | |
public class ServerImpl : IProtocol | |
{ | |
public string Hello(int n, byte[] b) | |
{ | |
return $"Hello from server: got {n} and {ASCIIEncoding.ASCII.GetString(b)}"; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Companion gist for this blog post
It demonstrates a simple COM based cross process communication on the cheap, for managed code. Originally compiled against .NET 6, but it works equally well under .NET Framework 4.7.2, if recompiled.
A similar IPC technique in native C++ code is under this gist.