通过 SendMessage 的 C# 应用程序间通信

Posted

技术标签:

【中文标题】通过 SendMessage 的 C# 应用程序间通信【英文标题】:C# Inter-Application Communications through SendMessage 【发布时间】:2015-02-19 15:23:38 【问题描述】:

因此,在为我的不同进程通信寻找合适的方法时遇到了很多问题,我拼凑了这个:

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" );

使用方式如下:

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 );


在接收端

// 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

现在,一切都很好,我已经彻底测试过;

我从 Runtime.InteropServices 借用了 SendMessage。 消息已成功发送。 但是,它仅限于两个可悲的 IntPtr。

所以我决定最好的办法是发送一个指向某个非托管内存的指针,以及该内存的大小。

发送成功,但是在两个不同的程序实例中,指针显然没有指向同一个地方。看起来 Marshal.AllocHGlobal 的 IntPtr 是一些仅与当前程序相关的任意本地指针,因此给了我读/写访问冲突、一些随机空值或一些随机其他字符的例外情况,在某些时候我什至采样了一个来自某处的随机“l32.dll”字符串。诡异!

我只是,只是想知道如何获得一个指针,它将指向相同的数据,跨越两个不同的应用程序。我什至不知道从哪里开始寻找这个答案,所以我在这里问。

有没有办法通过 Marshals 获得该指针,或者我需要别的东西。 我可以弄清楚细节,我只需要知道一些指针,如果在多个程序中使用,它会指向指向相同的数据

另外,如果我正在做的事情非常可怕而且是个坏主意,我想知道替代方案,只要它们不是: 命名管道、RPC、Memorymapped、文件,互斥体;因为,出于某种原因,我在 .NET 2.0 中工作,而那些在那里不可用;并且 Mutex 不传输数据;而且我喜欢我的硬盘漂亮、干净、不忙且处于原始状态。

再次提醒:目标是在同一程序的多个实例或可能的其他程序之间传递任何类型和任何大小的数据(我可以接受一些限制),这是一个.EXE在自己的ApplicationDomain等中。

忘了提一下,这必须在 .NET 2.0 中,我需要的只是某种指向多个应用程序之间相同数据的指针。

【问题讨论】:

是的,ReadProcessMemory 需要的数据多于两个 IntPtr 可以处理的数据。我不一定要寻找一种管理方式来做到这一点。我只想要一些在应用程序之间有效的“全局”指针,并且开销最小。或者,我可以发送多个 SendMessage 并将它们同步以执行 ReadProcessMemory hax。 我“专业”需要的是 .NET 远程方法调用,它基本上是一个 TCP 连接,在应用程序之间使用 HTTP 协议发送数据,以执行类似于我需要的操作。我需要离线无协议数据连接;并且 Windows 程序遭受的随机化使得有必要将指针传递给进程和数据。似乎没有办法改善这一点。 【参考方案1】:

我猜你要么需要在源进程上OpenHandle,然后从那里ReadProcessMemory(因为你广播的内存地址是应用程序的本地地址),或者使用memory-mapped files或共享内存空间。无论哪种方式,您都在挖掘 Win32 P/Invoke 领域,因为两者都不能在 .NET 2.0 上完全托管。

编辑:您似乎编辑了您的问题,将这些问题作为可行的候选者删除。您要求 IPC 方法,同时排除所有 IPC 方法(没有理由)。

【讨论】:

打开一个句柄并从 ReadProcessMemory 中读取需要额外的东西,比如知道源程序;这太麻烦了,只有在没有其他方法的情况下我才会实施。我也不一定要寻找一种“管理”的方式来做到这一点。 你为什么要把 MMF 扔出窗外?它们不一定会保存到磁盘,您可以在创建时指定一个“瞬态”内存映射文件。 .NET-2.0 不支持。如果它们可用,我会很乐意使用它们。他们也没有做我想让他们做的事。 您说您不一定要寻找“托管”方式来执行此操作 - 所以 P/Invoke MMF API(以 CreateFileMapping 开头)。 正如我所说,MMF 是不可能的。【参考方案2】:

哇!为什么不使用 WCF 通过 IPC 在进程之间进行通信?

http://tech.pro/tutorial/855/wcf-tutorial-basic-interprocess-communication

http://dotnet-experience.blogspot.com.es/2012/02/inter-process-duplex-communication-with.html

【讨论】:

.NET 3.0。我想要.NET 2.0

以上是关于通过 SendMessage 的 C# 应用程序间通信的主要内容,如果未能解决你的问题,请参考以下文章

C#调用SendMessage 用法

C# 问题SendMessage,

MFC sendmessage实现进程间通信

c# SendMessage发送汉字

VC进程间通信之消息传递PostMessge()或SendMessage()

c# SendMessage 发送 click消息