我有一个非常有名的使用(丑)WM_COPYDATA
消息的进程间数据交换设置。这不是我的决定,我必须在传统应用程序中支持它。为什么在提供数据有效载荷时没有收到WM_COPYDATA消息?
const uint WM_COPYDATA = 0x004A;
[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public uint dwData;
public int cbData;
public IntPtr lpData;
}
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hwnd, uint msg, IntPtr wparam, ref COPYDATASTRUCT lparam);
如果我送只是一个普通的结构,不附加额外的数据,它工作得很好:
COPYDATASTRUCT container;
container.dwData = 42;
container.cbData = 0;
container.lpData = IntPtr.Zero;
SendMessage(myHwnd, WM_COPYDATA, IntPtr.Zero, ref container);
在接收端(外部WinForms应用程序),我得到这个消息并能正确地读出的dwData
字段:
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_COPYDATA)
{
var container = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));
MessageBox.Show(container.dwData.ToString()); // 42
}
base.WndProc(ref m);
}
但只要附上一些额外的有效载荷,所述外部应用程序停止接收此消息。 m.Msg == WM_COPYDATA
条件在接收器窗口过程中始终为false
,并且发件人从SendMessage
调用获得0
结果。
COPYDATASTRUCT container;
container.dwData = 42;
container.cbData = 4;
container.lpData = Marshal.AllocHGlobal(4);
int result = SendMessage(hwnd, WM_COPYDATA, IntPtr.Zero, ref container); // 0
(其实,这是一个虚拟的有效载荷,但与真实的,它是相同的。)
string payload = "test";
container.cbData = (payload.Length + 1) * 2;
container.lpData = Marshal.StringToHGlobalUni(payload);
我也试图通过改变手动元帅COPYDATASTRUCT
(使用Marshal.StructToPtr
) SendMessage
的最后一个参数类型为IntPtr
,但不幸没有成功(相同的行为)。
我试图依靠CLR编组通过改变COPYDATASTRUCT
定义:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct COPYDATASTRUCT
{
public uint dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpData;
}
你猜怎么着?没有效果。
我的设置有什么问题?为什么当有效载荷连接到数据结构时无法接收消息?
dwData是一个IntPtr(可变大小32或64),而不是32位值。它可能在32位上工作,但会在64位上失败。 lpData必须是一个IntPtr,而不是一个字符串。 https://stackoverflow.com/questions/6779731/c-sharp-using-sendmessage-problem-with-wm-copydata –
在C#中复制甚至简单的C++结构可能会非常棘手;除了普通的P/Invoke之外,C++/CLI可能更好。 –
@SimonMourier,似乎这个错误'dwData'类型是问题。如果你将它作为答案发布,我会接受它。 'lpData'可以是一个'string',但是,它只是需要适当编组('[MarshalAs(UnmanagedType.LPWStr)'')。 – dymanoid