我正在尝试使用RegisteredWindowMessage API函数将文本从一个应用程序发送到另一个应用程序,我有以下代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Common
{
public static class RegisteredMsg
{
private const string MyMessage = "9C7EDA65363F4fdaAF32";
private static IntPtr m_targetWindow = new IntPtr(0xFFFF);
private static object m_object = new object();
private static HandleRef m_handleRef;
private static HandleRef m_handleRef;
public static uint RegisteredMessage
{
get { return m_regMsg; }
private set
{
m_regMsg = RegisterWindowMessage(SynchroMessage);
}
}
//-----------------------------------------------------------------
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
//-----------------------------------------------------------------
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
//-----------------------------------------------------------------
static RegisteredMsg()
{
m_handleRef = new HandleRef(m_object, m_targetWindow);
}
//-----------------------------------------------------------------
public static void PostUpdateMsg(string text)
{
IntPtr lpData = Marshal.StringToHGlobalAuto(text);
IntPtr lpLength = new IntPtr(text.Length);
if (!PostMessage(m_handleRef, RegisteredMessage, lpData, lpLength))
{
throw new Exception("Could not post message.");
}
}
//-----------------------------------------------------------------
public static string GetMessageText(Message msg)
{
string text = "";
int length = msg.LParam.ToInt32();
text = Marshal.PtrToStringAuto(msg.WParam, length);
Marshal.FreeHGlobal(msg.WParam);
return text;
}
}
}
发布消息有效,但当接收应用程序调用GetMessageText时,该字符串包含“\ 0 \ 0 \ 0 \ 0”(这不是发送应用程序发送的内容)。
我这样称呼它:
RegisteredMsg.PostUpdateMsg("test");
并像这样接收:
protected override void WndProc(ref Message msg)
{
base.WndProc(ref msg);
if (Convert.ToUInt32(msg.Msg) == RegisteredMsg.RegisteredMessage)
{
string text = RegisteredMsg.GetMessageText(msg);
}
}
编辑#0
我也是这样尝试的,接收到的数组中的所有字节都是'\ 0':
//-------------------------------------------------------------------------
public static void PostUpdateMsg(string text)
{
byte[] array = StringToByteArray(text);
IntPtr lpData = Marshal.AllocHGlobal(array.Length);
Marshal.Copy(array, 0, lpData, array.Length);
IntPtr lpLength = new IntPtr(text.Length);
if (!PostMessage(m_handleRef, RegisteredMessage, lpData, lpLength))
{
throw new Exception("Could not post message.");
}
}
//-------------------------------------------------------------------------public static string GetMessageText(Message msg)
{
string text = "";
int length = msg.LParam.ToInt32();
byte[] array = new byte[length];
Marshal.Copy(msg.WParam, array, 0, length);
text = RegisteredMsg.ByteArrayToString(array);
return text;
}
编辑#1
我也从PostUpdateMessage中调用了这个方法,只是为了确保我发送的是我认为发送的内容:
private static void TestIntPtr(IntPtr ptr, int length)
{
string text = "";
byte[] array = new byte[length];
Marshal.Copy(ptr, array, 0, length);
text = ByteArrayToString(array); // <<------------
}
当执行指示的行时,text
变量确实=“test”,所以我在发送端正确执行。看起来内存在到达接收应用程序之前就已经被清除了。
编辑#2
我还尝试将IntPtr
(指向我要发送的字符串)全局发送到其父类,以确保它能够活得足够长,以便在另一端可行。那里也没有快乐。
编辑#3
我还恢复使用StringToHGlobalAuto
,然后运行“它仍然可以在发送应用程序中”测试(参见上面的编辑#1),该测试证明了我构建{的方式{1}}也很好。
答案 0 :(得分:3)
PostMessage()手册说明;
系统仅对系统消息进行编组(系统消息中的那些消息) 范围0到(WM_USER-1))。要发送其他消息(那些&gt; = WM_USER) 另一个过程,你必须做自定义编组。
据我了解,您将在本地非托管堆上分配指针,并将长度发送到单独的进程,其中指针指向完全不同的内容。数据不会传递。
为简单起见(即避免自定义封送),您可能希望使用WM_COPYDATA代替在应用程序之间传递数据。
答案 1 :(得分:3)
这在设计上无法奏效。指针仅在创建它的过程中有效。每个进程都有自己的虚拟内存块。检索指向内存的内容需要ReadProcessMemory()。或者,您可以使用VirtualAllocEx()在目标进程中分配内存,并使用WriteProcessMemory()写入内存。 Windows支持WM_COPYDATA消息来为您处理此事。
这都是相当低级和痛苦的。有更好的IPC机制可用。在.NET中运行良好的是套接字,管道,WCF。
答案 2 :(得分:1)
我认为问题在于消息传递机制本身。 您正在将一些数据复制到指针(指向第一个进程中的内存块)并将此指针发送到另一个应用程序/进程。 当您在另一个进程中使用指针时,它指向的内存位置是另一个进程中的内存块,它不包含您在进程1中复制的内容。
如果你想发送比Windows消息的一对更长的内容,你应该看看WM_COPYDATA - 这条消息正是你想做的。