Search code examples
c#pointers.net-2.0sendmessageinter-process-communicat

C# Inter-Application Communications through SendMessage


So after a lot of problems finding a proper way to make a way for my different processes to communicate, I cobbled together this:

public const uint HWND_BROADCAST = 0xffff;
[DllImport( "user32" )]
public static extern bool SendMessage(IntPtr hwnd, IntPtr msg, IntPtr wparam, IntPtr lparam);
[DllImport( "user32" )]
public static extern int RegisterWindowMessage(string message);
public static readonly uint WM_COPYDATA = (uint)RegisterWindowMessage( "WM_COPYDATA_DESKTOP_TODOLIST_9234892348932GIBBERISH" );

Which is used in the following way:

public static void SendMessage(string Message) {
SendMessage( (IntPtr)HWND_BROADCAST, (IntPtr)WM_COPYDATA, (IntPtr)Rawify( ref Message ), (IntPtr)Message.Length );
}

// Preparing the message for pointer-sending
public static IntPtr Rawify(ref string target) {
char[] CHARS = target.ToCharArray();

// Copy string to raw memory block of bytes
int count = target.Length;
IntPtr P = Marshal.AllocHGlobal( 2 * count );
for (int I = 0; I < count; I++) {    Marshal.WriteInt16( (IntPtr)((int)P + I * 2), target[I] );    }

return P;
}

public static string Cook(IntPtr target, IntPtr length) {
int count = (int)length;
char[] CHARS = new char[count];

// Copy raw memory to char array->string
for (int I = 0; I < count; I++) {    CHARS[I] = (char)Marshal.ReadInt16( (IntPtr)((int)target + I * 2) );    }

return new string( CHARS );
}
}

And on the receiving end

// Receiver for alternate applications
protected override void WndProc(ref Message m) {
if (m.Msg == Native.Messaging.WM_COPYDATA) { MessageBox.Show( "[" + Native.Messaging.Cook( m.WParam, m.LParam ) + "]" ); }
base.WndProc( ref m ); // Default handling
}

Now, all is peachy and I've tested thoroughly;

What happens is I've borrowed SendMessage from Runtime.InteropServices. The message is sent successfully across. However, it's limited to two pathetic IntPtr's.

So I decided the best thing to do is sent over a pointer to some unmanaged memory, and the size of that memory.

The sending is successful, however in the two different program instances, the pointer, apparently, doesn't point to the same place. It looks like the IntPtr that Marshal.AllocHGlobal is some arbitrary local pointer relevant only the current program, thus giving me exceptions for read/write access violations, or some random nulls, or some random other characters, and at some point I even sampled a random "l32.dll" string from somewhere. Spooky!

I only, and simply want to know how to get a Pointer, that would point to the SAME DATA, across two different applications. I'm so clueless where to even start searching for this answer, hence why I ask here.

Is there a way to get that pointer with Marshals, or I need something else. I can figure out the details, I just need to be let known about some Pointer, that points to the same data if used in multiple programs.

Alternatively, if what I'm doing is grotesquely horrible and a bad idea, I'd like to be informed of alternatives, so long as they are not: Named pipes, RPC, Memorymapped, Files, Mutex; because, for reasons, I'm working in .NET 2.0, and those are not available there; And Mutex doesn't transfer data; And I like my hard disk nice, clean, un-busy and in pristine condition.

Again, Reminder: The goal is to communicate DATA of ANY TYPE and ANY SIZE (I can accept some limits), BETWEEN multiple INSTANCES of the same PROGRAM, or possibly other PROGRAMS, that is an .EXE in its own ApplicationDomain and etc.

Forgot to mention, this has to be in .NET 2.0, and all I need is a POINTER of some kind that points to the SAME DATA between multiple applications.


Solution

  • I'm guessing you'd either need to OpenHandle on the source process and ReadProcessMemory from there (since the memory address you're broadcasting is local to the application), or use memory-mapped files or shared memory space. Either way you are digging into Win32 P/Invoke land as neither is available fully managed on .NET 2.0.

    Edit: It appears you edited your question to remove these as viable candidates. You're asking for methods of IPC while excluding all methods of IPC (without a reason).