简体   繁体   English

C# WndProc 方法未收到预期的消息类型

[英]C# WndProc method not receiving expected Msg type

I've been trying to communicate with another software using its documented COPYDATA API.我一直在尝试使用其记录的 COPYDATA API 与另一个软件进行通信。 User Xanotos has been incredibly helpful in this question I asked which has the sending method sorted and working fine.用户 Xanotos在我询问的这个问题中提供了非常有用的帮助,该问题的发送方法已排序并且工作正常。 I am having issues that the receiving WndProc method does not seem to catch the expected response.我遇到了接收WndProc方法似乎没有捕捉到预期响应的问题。 Here is the link to COPYDATA API documentation for reference.这是COPYDATA API文档的链接以供参考。

The current method is below.目前的方法如下。 Testing has shown the WndProc does receive messages, but not the ones I expect, namely a struct depending on which message was sent.测试表明WndProc确实收到了消息,但不是我期望的消息,即取决于发送的消息的struct

Declarations:声明:

 [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 IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);

    [StructLayout(LayoutKind.Sequential)]
    public struct COPYDATASTRUCT
    {
        public IntPtr dwData;    // Any value the sender chooses.  Perhaps its main window handle?
        public int cbData;       // The count of bytes in the message.
        public IntPtr lpData;    // The address of the message.
    }
    public struct ExternalGetPositionType
    {
        public double X;
        public double Y;
        public double Z;
        public double W;
    }
    const int WM_COPYDATA = 0x004A;
    const int EXTERNAL_CD_COMMAND_RUN_ASYNC = 0x8001;
    const int EXTERNAL_CD_GET_POSITION_PCS = 0x8011;
    const int EXTERNAL_CD_GET_POSITION_MCS = 0x8012;

Sending Methods (these all work fine and return true):发送方法(这些都可以正常工作并返回 true):

public static IntPtr RunAsync(IntPtr hwnd, string str)
    {
        // We have to add a \0 terminator, so len + 1 / len + 2 for Unicode
        int len = Encoding.Default.GetByteCount(str);
        var buff = new byte[len + 1]; // len + 2 for Unicode
        Encoding.Default.GetBytes(str, 0, str.Length, buff, 0);

        IntPtr ret;

        GCHandle h = default(GCHandle);

        try
        {
            h = GCHandle.Alloc(buff, GCHandleType.Pinned);

            var cds = new COPYDATASTRUCT();
            cds.dwData = (IntPtr)EXTERNAL_CD_COMMAND_RUN_ASYNC;
            cds.lpData = h.AddrOfPinnedObject();
            cds.cbData = buff.Length;

            ret = SendMessage(hwnd, WM_COPYDATA, 0, ref cds);
        }
        finally
        {
            if (h.IsAllocated)
            {
                h.Free();
            }
        }

        return ret;
    }

    public static IntPtr GetPosition(IntPtr hwnd, bool pcs, ExternalGetPositionType position)
    {
        // We cheat here... It is much easier to pin an array than to copy around a struct
        var positions = new[]
        {
    position
};

        IntPtr ret;

        GCHandle h = default(GCHandle);

        try
        {
            h = GCHandle.Alloc(positions, GCHandleType.Pinned);

            var cds = new COPYDATASTRUCT();
            cds.dwData = pcs ? (IntPtr)EXTERNAL_CD_GET_POSITION_PCS : (IntPtr)EXTERNAL_CD_GET_POSITION_MCS;
            cds.lpData = h.AddrOfPinnedObject();
            cds.cbData = Marshal.SizeOf<ExternalGetPositionType>();

            ret = SendMessage(hwnd, WM_COPYDATA, 0, ref cds);
        }
        finally
        {
            if (h.IsAllocated)
            {
                h.Free();
            }
        }

        return ret;
    }

WndProc Method - This is where things don't work as expected. WndProc方法 - 这是事情没有按预期工作的地方。 The if(m.Msg == WM_COPYDATA) never returns true when GetPosition is called.调用GetPosition时, if(m.Msg == WM_COPYDATA)永远不会返回 true。

protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_COPYDATA) //this does not execute
        {
            COPYDATASTRUCT cds = Marshal.PtrToStructure<COPYDATASTRUCT>(m.LParam);
            label5.Text = "message received";
            if (cds.dwData == (IntPtr)EXTERNAL_CD_COMMAND_RUN_ASYNC)
            {
                label5.Text = "NORMAL";
                string str = Marshal.PtrToStringAnsi(cds.lpData);

                Debug.WriteLine($"EXTERNAL_CD_COMMAND_RUN_ASYNC: {str}");
                toolStripStatusLabel1.Text = $"COMMAND";
                m.Result = (IntPtr)100; // If you want to return a value
            }
            else if (cds.dwData == (IntPtr)EXTERNAL_CD_GET_POSITION_PCS) //this does not execute
            {
                label5.Text = "MSC";
                if (cds.cbData >= Marshal.SizeOf<ExternalGetPositionType>())
                {
                    var position = Marshal.PtrToStructure<ExternalGetPositionType>(cds.lpData);

                    Debug.WriteLine($"EXTERNAL_CD_GET_POSITION_PCS: X = {position.X}, Y = {position.Y}, Z = {position.Z}, W = {position.W}");
                    toolStripStatusLabel1.Text = $"External MCS = {position.X}";
                    label4.Text = position.X.ToString();

                    m.Result = (IntPtr)200;
                }
                else
                {
                    m.Result = (IntPtr)0;
                }
            }
            else if (cds.dwData == (IntPtr)EXTERNAL_CD_GET_POSITION_MCS) //this does not execute
            {
                label5.Text = "MSC"; //this does not execute
                if (cds.cbData >= Marshal.SizeOf<ExternalGetPositionType>())
                {
                    var position = Marshal.PtrToStructure<ExternalGetPositionType>(cds.lpData);

                    Debug.WriteLine($"EXTERNAL_CD_GET_POSITION_MCS: X = {position.X}, Y = {position.Y}, Z = {position.Z}, W = {position.W}");
                    toolStripStatusLabel1.Text = $"External MCS = {position.X}";
                    label4.Text = position.X.ToString(); 

                    m.Result = (IntPtr)300;
                }
                else
                {
                    m.Result = (IntPtr)0;
                }
            }

            return;
        }
        MessageBox.Show(m.Msg.ToString()); //this DOES execute
        
        base.WndProc(ref m);
    }

Both programs are 32 bit.这两个程序都是 32 位的。

Any ideas why I am not receiving the expected Msg ?任何想法为什么我没有收到预期的Msg

The documentation you provided is unclear, but it seems you need to set wParam as the receiving window handle to be able to receive data in response.您提供的文档不清楚,但似乎您需要将wParam设置为接收 window 句柄才能接收数据作为响应。

At the bottom of page 3 it has an example:在第 3 页的底部有一个示例:

::SendMessage(m_pWnd->GetSafeHwnd(), WM_COPYDATA,(WPARAM)this->GetSafeHwnd(,(LPARAM)&MyCDS); ::SendMessage(m_pWnd->GetSafeHwnd(), WM_COPYDATA,(WPARAM)this->GetSafeHwnd(,(LPARAM)&MyCDS);

Whereas your code has this:而你的代码有这个:

ret = SendMessage(hwnd, WM_COPYDATA, 0, ref cds);

Instead you need相反,你需要

ret = SendMessage(hwnd, WM_COPYDATA, this.Handle, ref cds);

You must also redefine wParam on SendMessage as IntPtr .您还必须SendMessage上的wParam重新定义为IntPtr It is in any case wrong, and probably only worked because you were on 32-bit.无论如何它都是错误的,并且可能只是因为您使用的是 32 位才有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM