如何将 WM_COPYDATA 从 C++ 发送到 AutoHotKey?

Posted

技术标签:

【中文标题】如何将 WM_COPYDATA 从 C++ 发送到 AutoHotKey?【英文标题】:How to send WM_COPYDATA from C++ to AutoHotKey? 【发布时间】:2021-09-04 02:32:10 【问题描述】:

尝试使用 WM_COPYDATA 从 C++ 应用程序向 AutoHotkey 脚本SendMessage。 我尝试按照文档中的示例进行操作:

https://docs.microsoft.com/en-us/windows/win32/dataxchg/using-data-copy

然后我做了:

HWND htarget_window = FindWindow(NULL, L"MyGui");

std::string str = "Hello World";

COPYDATASTRUCT cds; 
cds.dwData = 1; 
cds.lpData = (PVOID) str.c_str();
cds.cbData = strlen((char*)cds.lpData); 
auto Response = SendMessage(htarget_window, WM_COPYDATA, (WPARAM)htarget_window, (LPARAM)&cds);

在 Autohotkey 脚本中:

OnMessage(0x4a   , "Receive_WM_COPYDATA")
    
Receive_WM_COPYDATA(wParam, lParam) 
           
   ; Retrieves the CopyDataStruct's lpData member.
   StringAddress := NumGet(lParam + 2*A_PtrSize)
   ; Copy the string out of the structure.
   Data := StrGet(StringAddress)    
   MsgBox Received the following string: %Data%
    

正在接收消息,但输出如下:

什么时候应该是:Hello World

我还在SendMessage 之后检查了GetLastError(),它输出0

我一定在COPYDATASTRUCT 内部做错了什么。 自动热键 x64。

【问题讨论】:

【参考方案1】:

你对StrGet()的使用是错误的:

您没有在发送的数据中包含std::string 的空终止符,但您没有将COPYDATASTRUCT::cbData 字段的值传递给StrGet(),因此它将寻找一个空终止符不存在。因此,您需要指定 COPYDATASTRUCT::cbData 字段中的长度,例如:

StringLen := NumGet(lParam + A_PtrSize, "int");
StringAddress := NumGet(lParam + 2*A_PtrSize);
Data := StrGet(StringAddress, StringLen, Encoding);

更重要的是,您没有为StrGet() 指定Encoding,因此它将以脚本的本机编码方式解释原始数据(请参阅A_IsUnicode)。不要那样做。明确 C++ 代码使用的编码。如果 std::string 包含 UTF-8 字符串,请指定 "UTF-8"。如果std::string 包含用户默认ANSI 语言环境中的字符串,请指定"CP0"。等等。您所看到的情况通常称为Mojibake,当单字节字符数据被错误地解释为错误的编码时会发生这种情况。

【讨论】:

使用最新版本的x64,脚本与你的代码崩溃:AutoHotkey closed for the following exit code: 3221226525,消息仍然是汉字,我也试过你的建议使用StringAddress := NumGet(lParam + A_PtrSize + 4)它也崩溃了,在这种情况下甚至在 MsgBox 之前就崩溃了,当我只发送一个字符时,它确实可以正确读取它,例如 std::string str = "X"; 此链接中的 4º 示例演示了在两个 AutoHotkey 脚本之间使用 WM_COPYDATA autohotkey.com/docs/commands/OnMessage.htm @Gutth 您是否确认StringLen 正在接收正确数量的发送字符?您是否验证收到的 dwData 字段为 1?也许您正在处理与预期不同的WM_COPYDATA 消息? 现在可以使用:StringLen := NumGet(lParam + A_PtrSize, "int") StringAddress := NumGet(lParam + 2*A_PtrSize) Data := StrGet(StringAddress, StringLen, Encoding),您可以在答案中编辑它吗?另外,谢谢雷米的帮助! :)

以上是关于如何将 WM_COPYDATA 从 C++ 发送到 AutoHotKey?的主要内容,如果未能解决你的问题,请参考以下文章

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

快速发送进程间信号

在 WPF 或控制台 C# 应用程序中接收 WM_COPYDATA 结构

使用 SendMessage WM_COPYDATA 发送双精度数组

如何将短字符串从 Visual Basic 应用程序发送到 Delphi 应用程序?

在 Qt 应用程序中接收 WM_COPYDATA 消息