通过Win32 SendMessage从c#发送字节[]

本文关键字:字节 Win32 SendMessage 通过 | 更新日期: 2023-09-27 17:57:44

我正在将一些代码从c++移植到c#,在让PostMessage在c#应用程序中工作时遇到了一些问题。我(还)不太擅长MFC的东西,我想我犯了一些基本的错误。在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);

我正在使用以下c#代码(基于这里的代码)来尝试做同样的事情:

[DllImport("User32.dll", EntryPoint = "FindWindow")]
public static extern Int32 FindWindow(String lpClassName, String lpWindowName);
[DllImport("User32.dll", EntryPoint = "PostMessage")]
public static extern int PostMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
    public IntPtr dwData;
    public int cbData;
    [MarshalAs(UnmanagedType.SafeArray)]
    public byte[] lpData;
}
public static int sendWindowsByteMessage(int hWnd, int wParam, byte[] data)
{
    int result = 0;
    if (hWnd > 0)
    {
         int len = data.Length;
         COPYDATASTRUCT cds;
         cds.dwData = (IntPtr)100;
         cds.lpData = data;
         cds.cbData = len + 1;
         result = PostMessage(hWnd, WM_COPYDATA, wParam, ref cds);
    }
    return result;
}
byte[] result = getResults();
int hWnd = MessageHelper.FindWindow(null, "window name");
int status = MessageHelper.sendWindowsByteMessage(hWnd, 10, result);

status的值总是0,根据PostMessage上的文档,这意味着失败。关于我犯的(可能很简单的)错误,有什么建议吗?

通过Win32 SendMessage从c#发送字节[]

WM_ COPYDATA必须发送,而不是过帐。

我也不确定您的byte[]封送是否正确。

下面是我成功使用的相同逻辑的一个版本:

    [StructLayout(LayoutKind.Sequential)]
    internal class COPYDATASTRUCT
    {
        internal uint dwData;
        internal uint cbData;
        internal IntPtr lpData;
    }
    // send DATA packet
    internal static void SendData(IntPtr hWnd, uint dwData, DATA infos)
    {
        // get pointer to DATA block
        IntPtr infoMem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DATA)));
        Marshal.StructureToPtr(infos, infoMem, false);
        // construct COPYDATASTRUCT to point to DATA block
        COPYDATASTRUCT cds = new COPYDATASTRUCT();
        cds.dwData = dwData;
        cds.lpData = infoMem;
        cds.cbData = (uint)Marshal.SizeOf(typeof(DATA));
        // get pointer to COPYDATASTRUCT block
        IntPtr cdsMem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(COPYDATASTRUCT)));
        Marshal.StructureToPtr(cds, cdsMem, false);
        // send message with block pointer to other process
        SendMessage(hWnd, WM_COPYDATA, 0, (uint)cdsMem.ToInt32());
        // Free allocated memory
        Marshal.FreeHGlobal(cdsMem);
        Marshal.FreeHGlobal(infoMem);
    }

如果目标窗口在另一个进程中,则需要使用HGlobal内存。我不确定UnmanagedType.SafeArray是否能为您做到这一点。

PostMessage可能因为窗口句柄无效而失败。调用GetLastError以查明失败的原因。实际上,您需要在这里使用SendMessage——缓冲区只保证在调用期间分配,PostMessage是异步的——它在发布消息后返回,您的cd结构可能会在调用目标窗口proc之前释放。如果需要使用PostMessage,则必须显式分配一个非托管缓冲区,将数据复制到其中,然后将其用于调用。