读取从 c++ 发送到 C# 的 lParam 作为字符串

Posted

技术标签:

【中文标题】读取从 c++ 发送到 C# 的 lParam 作为字符串【英文标题】:Read lParam sent from c++ to C# as string 【发布时间】:2015-08-29 21:23:47 【问题描述】:

我有一个 c++ 应用程序,它使用 SendNotifyMessageCB_FINDSTRINGEXACT 重定向到 C# 代码。现在,我想将其更改为 WM_COPYDATA,但我无法使其工作。

C++ 代码:

static LRESULT CALLBACK GetMsgHookCallback(int code, WPARAM wparam, LPARAM lparam)
if (code >= 0)

    UINT msg = 0;
    UINT msg2 = 0;

    msg = RegisterWindowMessage("WILSON_HOOK_GETMSG");
    msg2 = RegisterWindowMessage("WILSON_HOOK_GETMSG_PARAMS");

    HWND dstWnd = (HWND)GetProp(GetDesktopWindow(), "WILSON_HOOK_HWND_GETMSG");

    MSG* pMsg = (MSG*)lparam;

    if (msg != 0 && pMsg->message != msg && pMsg->message != msg2)
    
        if (pMsg->message == CB_ADDSTRING)
        
            SendNotifyMessage(dstWnd, msg, (WPARAM)pMsg->hwnd, pMsg->message);
            SendNotifyMessage(dstWnd, msg2, pMsg->wParam, pMsg->lParam); //plus more code...

现在,由于我的意图是读取 pMsg->lParam 中的字符串,但我无法从 c# 端*,我正在尝试以这种方式使用 WM_COPYDATA:

                SendNotifyMessage(dstWnd, msg, (WPARAM)pMsg->hwnd, pMsg->message);
            SendNotifyMessage(dstWnd, msg2, pMsg->wParam, pMsg->lParam);

            // Added code
            CString *message = (CString*)pMsg->lParam;
            COPYDATASTRUCT cpd;
            cpd.dwData = 0;
            cpd.cbData = message->GetLength();
            cpd.lpData = (void*)message->GetBuffer(cpd.cbData);
            ::SendMessage(dstWnd, WM_COPYDATA, (WPARAM)pMsg->hwnd, (LPARAM)&cpd);
            SendNotifyMessage(dstWnd, WM_COPYDATA, (WPARAM)pMsg->hwnd, (LPARAM)&cpd);

但是,我从未在我的 c# 应用程序中收到任何 WM_COPYDATA

这里是 C# 部分:

        int CB_FINDSTRINGEXACT = 0x0158;
    public const Int32 WM_COPYDATA = 0x4A;
    private void test(IntPtr Handle, IntPtr Message, IntPtr wParam, IntPtr lParam)
    

        if (Message.ToInt32() == CB_FINDSTRINGEXACT)
        
            String one = Marshal.PtrToStringAuto(lParam); // This gives accessviolationexception
            String dos = Marshal.PtrToStringAnsi(lParam);   // returns empty string
            Console.WriteLine("SOMETHING RECEIVED: "+one+". dos: "+dos+". tres: "+lParam.ToString()); // last part is only an intptr
        
        if (Message.ToInt32() == WM_COPYDATA) // never true
            Console.WriteLine("COPYDATA: ");
    

我已经尝试了许多我读过的解决方案,但似乎没有一个有效。如何在我的 c# 函数中从 c++ 读取 lParam(实际上是一个字符串)?我想得到字符串。

编辑1:

我尝试了几种方法让 WM_COPYDATA 工作,但没有成功。他们在这里:

                    // Test 1: c# never receives anything
                COPYDATASTRUCT* copy_data = (COPYDATASTRUCT*)(pCwpStruct->lParam);
                SendMessage(dstWnd, WM_COPYDATA, (WPARAM)pCwpStruct->hwnd, (LPARAM)&copy_data);
                SendNotifyMessage(dstWnd, WM_COPYDATA, (WPARAM)pCwpStruct->hwnd, (LPARAM)&copy_data);

                // Test 2: c# never receives anything
                LPCTSTR lpszString = (LPCTSTR)pCwpStruct->lParam;
                COPYDATASTRUCT cds;
                cds.dwData = 0;
                cds.cbData = sizeof(TCHAR)* (_tcslen(lpszString) + 1);
                cds.lpData = (PVOID)lpszString;
                SendMessage(dstWnd, WM_COPYDATA, (WPARAM)pCwpStruct->hwnd, (LPARAM)(LPVOID)&cds);
                SendNotifyMessage(dstWnd, WM_COPYDATA, (WPARAM)pCwpStruct->hwnd, (LPARAM)&cds);

【问题讨论】:

【参考方案1】:

有一个评论有很多更正,但它消失了,不知道为什么。我遵循了一些建议并解决了它。这是最终代码:

C++:

                LPCTSTR lpszString = (LPCTSTR)pCwpStruct->lParam;
                COPYDATASTRUCT cds;
                cds.dwData = 0;
                cds.cbData = sizeof(TCHAR)* (_tcslen(lpszString) + 1);
                cds.lpData = (PVOID)lpszString;
                SendMessage(dstWnd, WM_COPYDATA, (WPARAM)pCwpStruct->hwnd, (LPARAM)(LPVOID)&cds);

请注意,我将 SendNotifyMessage 更改为 SendMessage。这是我让它发挥作用的唯一方法。

在 c# 应用程序中:

public override void ProcessWindowMessage(ref System.Windows.Forms.Message m)
        

            if (m.Msg == WM_COPYDATA)
            
                COPYDATASTRUCT cds;
                cds = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));

                if (cds.cbData > 0)
                
                    byte[] data = new byte[cds.cbData];
                    Marshal.Copy(cds.lpData, data, 0, cds.cbData);
                    System.Text.Encoding unicodeStr = System.Text.Encoding.ASCII;
                    char[] myString = unicodeStr.GetChars(data);
                    string returnText = new string(myString);   // Here is the info
                
                ...

【讨论】:

它与SendMessage一起工作而与SendNotifyMessage不工作的原因是SendNotifyMessage是异步的。这意味着进行调用的函数可能会在接收者收到消息之前退出。由于 Windows 消息包含指针,因此在接收者收到消息时,指向您尝试发送的数据的指针已经消失。当您使用 SendMessage 时,您的发送代码会阻塞,直到接收者获取并使用该消息。因此,当接收者收到消息时,您的发送函数中的数据仍然存在。

以上是关于读取从 c++ 发送到 C# 的 lParam 作为字符串的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ZeroMQ 从 C# 客户端向 C++ 服务器发送消息

将字符串从 C# 发送到 C++

使用 C# 从 RLM 读取许可证文件(C++ 到 C# 的翻译)

使用命名管道将图像从 C++ 发送到 C# 应用程序

将复杂的结构(带有结构的内部数组)从 C# 传递到 C++

将数据从 C++ 发送到 C# [重复]