SendMessage(WM_COPYDATA) + 记录 + 字符串

2024-01-04

我想发送一条记录,现在只有一个字符串,但我将添加更多变量。这是我第一次处理记录,所以这可能是一个愚蠢的问题。但是,为什么这有效:

type
  TDataPipe = record
    WindowTitle: String[255];
  end;

var
  Data: TDataPipe;
  copyDataStruct : TCopyDataStruct;
begin
  Data.WindowTitle:= String(PChar(HookedMessage.lParam));
  copyDataStruct.dwData := 0;
  copyDataStruct.cbData := SizeOf(Data);
  copyDataStruct.lpData := @Data;
  SendMessage(FindWindow('TForm1', nil), WM_COPYDATA, Integer(hInstance), Integer(@copyDataStruct));    
end;

接收方:

type
  TDataPipe = record
    WindowTitle: String[255];
  end;

procedure TForm1.WMCopyData(var Msg: TWMCopyData);
var
  sampleRecord : TDataPipe;
begin
  sampleRecord.WindowTitle:= TDataPipe(Msg.CopyDataStruct.lpData^).WindowTitle;
  Memo1.Lines.Add(sampleRecord.WindowTitle);
end;

为什么如果记录在案,我使用:

WindowTitle: String; //removed the fixed size

在发送端我使用:

Data.WindowTitle:= PChar(HookedMessage.lParam); //removed String()

它根本不去?

我遇到访问冲突/应用程序冻结...

场景是:发送方是一个使用 SetWindowsHookEx 挂钩的 DLL,接收方是一个加载/调用 SetWindowsHookEx 的简单 exe...


A String[255]是一个固定的 256 字节内存块,字符数据直接存储在该内存中。因此,无需序列化即可安全地按原样跨进程边界传递。

A String另一方面,是动态类型。它只包含一个指向存储在内存中其他位置的字符数据的指针。因此,你不能通过String按原样跨进程边界,您将传递的只是指针值,这对接收进程没有任何意义。你必须序列化String数据转换为平面格式,可以安全地传递到接收进程并由接收进程反序列化。例如:

发送方:

type
  PDataPipe = ^TDataPipe;
  TDataPipe = record
    WindowTitleLen: Integer;
    WindowTitleData: array[0..0] of Char;
    //WindowTitleData: array[0..WindowTitleLen-1] of Char;
  end;

var
  Wnd: HWND;
  s: String;
  Data: PDataPipe;
  DataLen: Integer;
  copyDataStruct : TCopyDataStruct;
begin
  Wnd := FindWindow('TForm1', nil);
  if Wnd = 0 then Exit;

  s := PChar(HookedMessage.lParam);
  DataLen := SizeOf(Integer) + (SizeOf(Char) * Length(s));
  GetMem(Data, DataLen);
  try
    Data.WindowTitleLen := Length(s);
    StrMove(Data.WindowTitleData, PChar(s), Length(s));

    copyDataStruct.dwData := ...; // see notes further below
    copyDataStruct.cbData := DataLen;
    copyDataStruct.lpData := Data;
    SendMessage(Wnd, WM_COPYDATA, 0, LPARAM(@copyDataStruct));    
  finally
    FreeMem(Data);
  end;
end;

接收方:

type
  PDataPipe = ^TDataPipe;
  TDataPipe = record
    WindowTitleLen: Integer;
    WindowTitleData: array[0..0] of Char;
    //WindowTitleData: array[0..WindowTitleLen-1] of Char;
  end;

procedure TForm1.WMCopyData(var Msg: TWMCopyData);
var
  Data: PDataPipe;
  s: string;
begin
  Data := PDataPipe(Msg.CopyDataStruct.lpData);
  SetString(s, Data.WindowTitleData, Data.WindowTitleLen);
  Memo1.Lines.Add(s);
end;

话虽这么说,在任何一种情况下,您确实应该将自己的自定义 ID 号分配给copyDataStruct.dwData场地。 VCL本身使用WM_COPYDATA在内部,因此您不想将这些消息与您的消息混淆,反之亦然。您可以使用RegisterWindowMessage()创建唯一的 ID 以避免与其他使用的 ID 发生冲突WM_COPYDATA users:

var
  dwMyCopyDataID: DWORD;

...

var
  ...
  copyDataStruct : TCopyDataStruct;
begin
  ...
  copyDataStruct.dwData := dwMyCopyDataID;
  ...
end;

...

initialization
  dwMyCopyDataID := RegisterWindowMessage('MyCopyDataID');
var
  dwMyCopyDataID: DWORD;

...

procedure TForm1.WMCopyData(var Msg: TWMCopyData);
var
  ...
begin
  if Msg.CopyDataStruct.dwData = dwMyCopyDataID then
  begin
    ...
  end else
    inherited;
end;

...

initialization
  dwMyCopyDataID := RegisterWindowMessage('MyCopyDataID');

最后,WPARAM的参数WM_COPYDATA is an HWND,不是一个HINSTANCE。如果发件人没有自己的HWND,只需传递 0。不要传递您的发件人的HInstance多变的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SendMessage(WM_COPYDATA) + 记录 + 字符串 的相关文章

随机推荐

  • Prometheus中将两个不同的指标分组后如何划分?

    我目前正在尝试对可用区内的 Kubernetes Pod 堆叠发出警报 我成功地使用了两种不同的指标 可以看到应用程序有多少个 pod 正在特定的可用区域上运行 但是 由于扩展 我希望警报基于百分比 因此 当某个可用区上运行特定百分比的 P
  • 通过 BeeTee 应用程序连接到其他蓝牙设备

    我需要实现一个自建蓝牙应用程序来将所有蓝牙设备连接到 iPhone 我知道 CoreBluetooth 框架不可能做到这一点 我使用私有API并将DeviceManager和BluetoothManager的头文件添加到私有框架中 并从下载
  • 在 Dockerfile 中覆盖 FROM 镜像的 ENV

    从下图可以看出 https registry hub docker com u cloudesire activemq dockerfile https registry hub docker com u cloudesire active
  • 获取 OpenGL 最大纹理尺寸

    我正在开发一个 Android 应用程序 它将广泛使用位图 并且我正在寻找一种可靠的方法来获取不同设备上 OpenGL 的最大纹理大小 我知道最小尺寸 2048x2048 但这还不够好 因为已经有分辨率更高的平板电脑 例如 2560x160
  • 如果结构具有 ReadOnlySpan 字段,如何将 ref 结构参数传递给 MethodInfo

    我有一个MethodInfo代表一个方法的对象 该方法采用ref struct作为参数 并且该结构有一个ReadOnlySpan
  • 使用 GoLang Web 服务器提供静态内容

    我正在探索 Go 的深度 并且一直在尝试编写一个简单的 Web 应用程序来理解所有内容 我正在尝试提供 React js 应用程序 下面是Go服务器的代码 我有默认路线 服务于index html工作正常 我正在努力允许将静态文件提供给该索
  • Python - 访问列表中嵌套字典中的值

    我有一个 JSON API 响应 如下所示 json data sales list date all country all units product promotions 0 downloads 1 updates 2 refunds
  • “错误:无法生成视图绑定器 java.lang.NullPointerException”的可能原因

    我正在使用 Android Studio 来处理我的 Android 项目 当构建因奇怪的堆栈跟踪而崩溃时 我遇到了一个问题 如下所示 Error Execution failed for task app compileDevDebugJ
  • DrRacket、R5RS和错误程序

    我喜欢 DrRacket IDE 但目前我正在构建一个我希望独立于它的宠物项目 这意味着我致力于仅使用 R5RS 标准程序 问题是 在 DrRacket 中有一个名为 错误 的过程 我想继续使用它 但我在标准中找不到它 我想知道是否有一种方
  • publishHtml reportFiles 参数语法是什么

    我正在尝试通过 Jenkinsfile 为 Jenkins 配置 HTML Publisher 插件来发布一些 html 文件 如下所示 publishHTML target allowMissing false alwaysLinkToL
  • 如何在 R 中创建条件虚拟对象?

    我有一个时间序列数据的数据框 其中包含每日温度观测值 我需要创建一个虚拟变量 对温度高于阈值 5C 的每一天进行计数 这本身很容易 但存在一个附加条件 仅在连续十天高于阈值后才开始计数 这是一个示例数据框 df lt data frame
  • 如何在酶中等待私人功能的承诺?

    我是 React 和任何 JavaScript 测试框架的新手 我有一个简单的组件 可以从 API 检索项目并将其显示在屏幕上 函数 getItems 是从 componentWillMount 调用的 是否可以等到 getItems 完成
  • Bitfinex 数据 API

    我正在尝试使用 bitfinex REST api 获取历史 OHLC 数据 文档如下 https bitfinex readme io v2 reference rest public candles https bitfinex rea
  • 如何在 C++ 中比较两个位图屏幕截图的字节到字节

    在问题的最后我的最后编辑 大家好 我必须实现一个功能来比较屏幕一部分的两个镜头 以便知道是否存在差异 变化 我写了类似下面的代码 但我无法让它工作 在代码中 COORDINATES RECT 是一个结构体 typedef struct CO
  • 当 Windows 进入睡眠模式然后唤醒时 setTimeout 不起作用

    我在 Chrome 中注意到了这一点 有人知道出了什么问题或解决方法吗 您可以使用setInterval相反 它继续运行 如果您需要一次性解决方案 请使用clearInterval删除计时器 setInterval如果计算机处于睡眠状态 而
  • 在视图模式中打开会话

    鉴于我选择的 JPA Hibernate 实现 Spring 和 开发框架 我问这个问题 我一直在思考实体层中的关系 例如 我有一个包含许多订单行的订单实体 我已经设置了我的应用程序 以便它急切地加载每个订单的订单行 您是否认为这是一种解决
  • C 使用信号同步进程

    好吧 我正在尝试自学如何发送信号 但我遇到了一个小问题 我不知道我做错了什么 现在发生的事情是 它正在执行父级 然后转到子级 然后返回父级 它没有执行我希望它执行的操作 即执行父级 用户定义其运行的时间量 然后杀死它然后转到子进程并在相同的
  • 使 tkinter 按钮大小相同

    我想让所有 tkinter 按钮的大小相同 无论文本如何 是否可以拉伸其他按钮以相互匹配或设置特定尺寸 因为我很难在文档中找到如何执行此操作 目前 按钮根据文本的大小进行拉伸 我的意思的例子 https i stack imgur com
  • 在 Selenium IDE 中使用 waitForCondition ( script,timeout )

    我使用 Firefox 的 Selenium IDE 扩展录制了一个脚本 我想添加命令 waitForCondition 我发现它需要两个参数 脚本和超时 在 Selenium IDE 中 每个命令都有 3 个文本字段 命令名称 我假设为
  • SendMessage(WM_COPYDATA) + 记录 + 字符串

    我想发送一条记录 现在只有一个字符串 但我将添加更多变量 这是我第一次处理记录 所以这可能是一个愚蠢的问题 但是 为什么这有效 type TDataPipe record WindowTitle String 255 end var Dat