【发布时间】:2011-05-31 14:36:28
【问题描述】:
我正在尝试将一些 C++ 代码移植到 C#,我需要做的一件事是使用 PostMessage 将字节数组传递到另一个进程的窗口。我正在尝试将源代码提供给其他程序,以便确切了解它的预期,但与此同时,原始 C++ 代码如下所示:
unsigned long result[5] = {0};
//Put some data in the array
unsigned int res = result[0];
Text winName = "window name";
HWND hWnd = FindWindow(winName.getConstPtr(), NULL);
BOOL result = PostMessage(hWnd, WM_COMMAND, 10, res);
这就是我现在所拥有的:
[DllImport("User32.dll", SetLastError = true, EntryPoint = "FindWindow")]
public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
[DllImport("User32.dll", SetLastError = true, EntryPoint = "SendMessage")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public int dwData;
public int cbData;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=32)]
public byte[] lpData;
}
public const int WM_COPYDATA = 0x4A;
public static int sendWindowsByteMessage(IntPtr hWnd, int wParam, byte[] data)
{
int result = 0;
if (hWnd != IntPtr.Zero)
{
int len = data.Length;
COPYDATASTRUCT cds;
cds.dwData = wParam;
cds.lpData = data;
cds.cbData = len;
result = SendMessage(hWnd, WM_COPYDATA, wParam, ref cds);
}
return result;
}
//*****//
IntPtr hWnd = MessageHelper.FindWindow(null, windowName);
if (hWnd != IntPtr.Zero)
{
int result = MessageHelper.sendWindowsByteMessage(hWnd, wParam, lParam);
if (result == 0)
{
int errCode = Marshal.GetLastWin32Error();
}
}
请注意,我必须从 C++ 中的 PostMessage 切换到 C# 中的 SendMessage。
所以现在发生的情况是我得到的结果和 errCode 都为 0,我认为这意味着消息没有被处理 - 实际上查看另一个应用程序,我没有看到预期的响应。我已经验证了hWnd != IntPtr.Zero,所以我认为消息正在发布到正确的窗口,但是消息数据是错误的。任何想法我做错了什么?
更新
在尝试了 cmets 中的建议后,我仍然没有任何运气。这是我目前得到的:
[DllImport("User32.dll", SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}
public struct BYTEARRDATA
{
public byte[] data;
}
public static IntPtr IntPtrAlloc<T>(T param)
{
IntPtr retval = Marshal.AllocHGlobal(Marshal.SizeOf(param));
Marshal.StructureToPtr(param, retval, false);
return (retval);
}
public static void IntPtrFree(IntPtr preAllocated)
{
//Ignores errors if preAllocated is IntPtr.Zero!
if (IntPtr.Zero != preAllocated)
{
Marshal.FreeHGlobal(preAllocated);
preAllocated = IntPtr.Zero;
}
}
BYTEARRDATA d;
d.data = data;
IntPtr buffer = IntPtrAlloc(d);
COPYDATASTRUCT cds;
cds.dwData = new IntPtr(wParam);
cds.lpData = buffer;
cds.cbData = Marshal.SizeOf(d);
IntPtr copyDataBuff = IntPtrAlloc(cds);
IntPtr r = SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, copyDataBuff);
if (r != IntPtr.Zero)
{
result = r.ToInt32();
}
IntPtrFree(copyDataBuff);
copyDataBuff = IntPtr.Zero;
IntPtrFree(buffer);
buffer = IntPtr.Zero;
这是一个 64 位进程试图联系一个 32 位进程,所以那里可能有问题,但我不确定是什么。
【问题讨论】:
-
你为什么要从
PostMessage切换到SendMessage? -
在我的previous question 上查看这个答案 - 长话短说,PostMessage 是异步的,SendMessage 是同步的,并且调用需要同步,以便数据在调用长度内有效。
-
试图将数据从 64 位进程传递到 32 位进程将是一个问题。您在
copyDataBuff中传递的指针是64 位的,但是您将它传递给一个32 位进程,它不知道如何处理它。如果两个进程都是 32 位,此代码是否有效? -
我尝试创建一个包含此代码的 32 位项目,从该项目中,SendMessage 仍然返回 0,因此 32/64 位不是问题,或者不是唯一的问题。
-
接收程序是否需要 WM_COMMAND?当它期望 WM_COMMAND 时发送 WM_COPYDATA 将不起作用。