使用user32 SendMessage调用Marshal.Copy时的AccessViolation

时间:2014-10-15 05:02:58

标签: c# winforms pointers ipc sendmessage

我正在为我的组织编写一个新工具,它必须通过SendMessage与传统工具进行对话。

我刚刚使用此处的代码创建了一个测试应用: http://www.c-sharpcorner.com/Blogs/6444/

我编辑了发送代码以符合我的目的。但是我在“GetMessage”表单中接收消息时遇到了一些问题。消息确实通过但是在尝试将数据转换为字符串时程序会中断。

这是我的代码:

发送:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, ref COPYDATASTRUCT lParam);

[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

private void button1_Click(object sender, EventArgs e)
{
    IntPtr hwnd = FindWindow(null, "GetMessage");

    if (hwnd != null)
    {            
        string message = textBox1.Text + "-" + System.DateTime.Now.ToString();
        COPYDATASTRUCT cds;
        cds.dwData = 0;
        cds.lpData = (int)Marshal.StringToHGlobalAnsi(message);
        cds.cbData = message.Length;
        SendMessage(hwnd, (int)WM_COPYDATA, 0, ref cds);
    }
}

收到:

private const int WM_COPYDATA = 0x4A;

[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
    public int dwData;
    public int cbData;
    public int lpData;
}

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_COPYDATA:

            COPYDATASTRUCT CD = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));
            byte[] B = new byte[CD.cbData];
            IntPtr lpData = new IntPtr(CD.lpData);

            //string test = Marshal.PtrToStringAuto(lpData, CD.lpData); // this doesn't work either
            Marshal.Copy(lpData, B, 0, CD.cbData); // access violation here
            string strData = Encoding.Default.GetString(B);
            listBox1.Items.Add(strData);

            break;

        default:
            base.WndProc(ref m);
            break;
    }
}

我得到的错误:

  

尝试读取或写入受保护的内存。这通常是一个   表明其他内存已损坏。

我已经尝试将发送中的消息字符串设置为字段(因此它不会超出范围),将发送消息的“int wParam”参数设置为“IntPtr”并使用IntPtr.Zero而不是我的SendMessage调用中为0,null终止字符串,如下所示:

cds.lpData = (int)Marshal.StringToHGlobalAnsi(message + '\0');
cds.cbData = (message+'\0').Length;

仍然遇到同样的问题。

1 个答案:

答案 0 :(得分:0)

我解决了这个问题,我认为问题在于我使用的是int而不是IntPtr用于我的SendMessage和COPYDATASTRUCT。

我从http://pinvoke.net/default.aspx/user32.SendMessagehttp://pinvoke.net/default.aspx/Structures/COPYDATASTRUCT.html

获得了这些信息

这是工作代码:

private const int WM_COPYDATA = 0x004A;

[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
    public IntPtr dwData;
    public int cbData;
    public IntPtr lpData;
}

发送:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
//static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); // original
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, ref COPYDATASTRUCT cds); // override

private void SendMsg()
{
    if (_hwnd != null)
    {
        COPYDATASTRUCT cds;
        cds.dwData = IntPtr.Zero;
        cds.lpData = Marshal.StringToHGlobalAnsi(stockCode);
        cds.cbData = stockCode.Length;
        SendMessage(_hwnd, (int) WM_COPYDATA, IntPtr.Zero, ref cds);
    }
}

收到:

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_COPYDATA:

            COPYDATASTRUCT CD = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));
            byte[] B = new byte[CD.cbData];
            IntPtr lpData = CD.lpData;

            Marshal.Copy(lpData, B, 0, CD.cbData);
            string strData = Encoding.Default.GetString(B);
            listBox1.Items.Add(strData);

            break;

        default:
            base.WndProc(ref m);
            break;
    }
}

我相信这是在64位窗口上工作。