读取从 c++ 发送到 C# 的 lParam 作为字符串
Posted
技术标签:
【中文标题】读取从 c++ 发送到 C# 的 lParam 作为字符串【英文标题】:Read lParam sent from c++ to C# as string 【发布时间】:2015-08-29 21:23:47 【问题描述】:我有一个 c++ 应用程序,它使用 SendNotifyMessage
将 CB_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)©_data);
SendNotifyMessage(dstWnd, WM_COPYDATA, (WPARAM)pCwpStruct->hwnd, (LPARAM)©_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++ 服务器发送消息