为什么在提供数据负载时未收到 WM_COPYDATA 消息?
Why the WM_COPYDATA message is not being received when a data payload is provided?
我有一个非常著名的进程间数据交换设置,使用(丑陋的)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
条件在接收方 window 过程中始终为 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
(实际上,这是一个虚拟的payload,但是和真正的payload是一样的。)
string payload = "test";
container.cbData = (payload.Length + 1) * 2;
container.lpData = Marshal.StringToHGlobalUni(payload);
我还尝试通过将 SendMessage
的最后一个参数类型更改为 IntPtr
来手动编组 COPYDATASTRUCT
(使用 Marshal.StructToPtr
),不幸的是没有成功(相同的行为)。
我试图通过更改 COPYDATASTRUCT
定义来依赖 CLR 编组:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct COPYDATASTRUCT
{
public uint dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpData;
}
你猜怎么着?没有效果。
我的设置有什么问题?为什么在数据结构上附加了有效载荷时无法接收到消息?
结构定义不正确,应该是
[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public IntPtr dwData; // in C/C++ this is an UINT_PTR, not an UINT
public int cbData;
public IntPtr lpData;
}
您对 dwData 的定义在 32 位进程(4 字节)中匹配正常,但在 64 位进程(8 字节)中不匹配。由于这是结构中的第一个字段,因此如果其定义不正确,则所有投注均无效。
我有一个非常著名的进程间数据交换设置,使用(丑陋的)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
条件在接收方 window 过程中始终为 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
(实际上,这是一个虚拟的payload,但是和真正的payload是一样的。)
string payload = "test";
container.cbData = (payload.Length + 1) * 2;
container.lpData = Marshal.StringToHGlobalUni(payload);
我还尝试通过将 SendMessage
的最后一个参数类型更改为 IntPtr
来手动编组 COPYDATASTRUCT
(使用 Marshal.StructToPtr
),不幸的是没有成功(相同的行为)。
我试图通过更改 COPYDATASTRUCT
定义来依赖 CLR 编组:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct COPYDATASTRUCT
{
public uint dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpData;
}
你猜怎么着?没有效果。
我的设置有什么问题?为什么在数据结构上附加了有效载荷时无法接收到消息?
结构定义不正确,应该是
[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public IntPtr dwData; // in C/C++ this is an UINT_PTR, not an UINT
public int cbData;
public IntPtr lpData;
}
您对 dwData 的定义在 32 位进程(4 字节)中匹配正常,但在 64 位进程(8 字节)中不匹配。由于这是结构中的第一个字段,因此如果其定义不正确,则所有投注均无效。