如何在单独的进程中使用 SendMessage(..) 发送数据记录

发布于 2024-09-06 03:18:51 字数 1066 浏览 9 评论 0原文

我用来在两个单独的进程上发送数据,但失败了。它只能在相同的进程下工作......这是概念。

//------------------------------------------------ -----------------------------------
主要应用
//------------------------------------------------ -----------------------------------

Type
   PMyrec = ^TMyrec; 
   TMyrec = Record
   name : string;
   add : string;
   age : integer;
end;

:OnButtonSend
var aData : PMyrec;
begin
   new(aData);
   aData.Name := 'MyName';
   aData.Add := 'My Address';
   aData.Age : 18;
   SendMessage(FindWindow('SubApps'),WM_MyMessage,0,Integer(@aData));
end;

//---------- -------------------------------------------------- -----------------------
子应用程序
//------------------------------------------------ -----------------------------------

Type
   PMyrec = ^TMyrec; 
   TMyrec = Record
   name : string;
   add : string;
   age : integer;
end;

:OnCaptureMessage

var
  aData : PMyrec;
begin
  aData := PMyrec(Msg.LParam);
  showmessage(aData^.Name);
end;

i use to send a data on two separate process but it fails. it works only under same process... this is concept.

//-----------------------------------------------------------------------------------
MainApps
//-----------------------------------------------------------------------------------

Type
   PMyrec = ^TMyrec; 
   TMyrec = Record
   name : string;
   add : string;
   age : integer;
end;

:OnButtonSend
var aData : PMyrec;
begin
   new(aData);
   aData.Name := 'MyName';
   aData.Add := 'My Address';
   aData.Age : 18;
   SendMessage(FindWindow('SubApps'),WM_MyMessage,0,Integer(@aData));
end;

//-----------------------------------------------------------------------------------
SubApps
//-----------------------------------------------------------------------------------

Type
   PMyrec = ^TMyrec; 
   TMyrec = Record
   name : string;
   add : string;
   age : integer;
end;

:OnCaptureMessage

var
  aData : PMyrec;
begin
  aData := PMyrec(Msg.LParam);
  showmessage(aData^.Name);
end;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

虫児飞 2024-09-13 03:18:52

你说得对。地址仅在单个进程内才有意义。您在第一个进程中创建的 PMyRec 值只是目标进程中的垃圾地址。

要通过窗口消息将任意内存块发送到另一个进程,您应该使用 wm_CopyData 消息。您向该消息提供数据的地址和大小,操作系统负责将其复制到目标进程的地址空间中。

由于您的数据包含一个字符串,该字符串在内部表示为另一个指针,因此仅复制记录的 12 个字节是不够的。您需要分配额外的内存来将记录和字符串数据保存在单个内存块中,以便 wm_CopyData 可以复制它并且目标进程可以读取它。

这是一种方法,使用流将数据收集到单个内存块中。

procedure SendRecord(Source, Target: HWnd; const Rec: TMyRec);
var
  Buffer: TMemoryStream;
  Len: Integer;
  CopyData: TCopyDataStruct;
begin
  Buffer := TMemoryStream.Create;
  try
    Len := Length(Rec.name);
    Buffer.Write(Len, SizeOf(Len));
    if Len > 0 then
      Buffer.Write(Rec.name[1], Len * SizeOf(Char));
    Len := Length(Rec.add);
    Buffer.Write(Len, SizeOf(Len));
    if Len > 0 then
      Buffer.Write(Rec.add[1], Len * SizeOf(Char));
    Buffer.Write(Rec.age, SizeOf(Rec.age));
    CopyData.dwData := 0;
    CopyData.cbData := Buffer.Size;
    CopyData.lpData := Buffer.Memory;
    SendMessage(Target, wm_CopyData, Source, LParam(@CopyData));
  finally
    Buffer.free;
  end;
end;

除了字符串的字符之外,我们还写入字符串的长度,以便接收者知道每个字符串有多少个字符。接收者的代码将如下所示:

procedure TBasicForm.WMCopyData(var Message: TWMCopyData);
var
  Rec: TMyRec;
  Len: Integer;
  Buffer: TStream;
begin
  Buffer := TReadOnlyMemoryStream.Create(
    Message.CopyDataStruct.lpData, Message.CopyDataStruct.cbData);
  try
    if Message.CopyDataStruct.dwData = 0 then begin
      Buffer.Read(Len, SizeOf(Len));
      SetLength(Rec.name, Len);
      if Len > 0 then
        Buffer.Read(Rec.name[1], Len * SizeOf(Char));

      Buffer.Read(Len, SizeOf(Len));
      SetLength(Rec.add, Len);
      if Len > 0 then
        Buffer.Read(Rec.add[1], Len * SizeOf(Len));

      Buffer.Read(Rec.age, SizeOf(Rec.age));

      // TODO: Do stuff with Rec here.

      Message.Result := 1;
    end else
      inherited;
  finally
    Buffer.Free;
  end;
end;

我使用了非标准的 TReadOnlyMemoryStream 因为它使一切变得更容易。这是一个简单的实现:

type
  TReadOnlyMemoryStream = class(TCustomMemoryStream)
  public
    constructor Create(Mem: Pointer; Size: LongInt);
    function Write(const Buffer; Count: LongInt): LongInt; override;
  end;

constructor TReadOnlyMemoryStream.Create;
begin
  inherited Create;
  SetPointer(Mem, Size);
end;

function TReadOnlyMemoryStream.Write;
begin
  Result := 0;
end;

You're right. Addresses only have meaning within a single process. The PMyRec value you create in the first process is just a garbage address in the target process.

To send an arbitrary block of memory to another process via a window message, you should use the wm_CopyData message. You give that message the address of the data and the size, and the OS takes care of copying it into the target process's address space.

Since your data includes a string, which is represented internally as a another pointer, it won't be enough to just copy the 12 bytes of your record. You'll need to allocate additional memory to hold the record and the string data in a single block of memory so wm_CopyData can copy it and the target process can read it.

Here's one way to do it, using a stream to collect the data into a single block of memory.

procedure SendRecord(Source, Target: HWnd; const Rec: TMyRec);
var
  Buffer: TMemoryStream;
  Len: Integer;
  CopyData: TCopyDataStruct;
begin
  Buffer := TMemoryStream.Create;
  try
    Len := Length(Rec.name);
    Buffer.Write(Len, SizeOf(Len));
    if Len > 0 then
      Buffer.Write(Rec.name[1], Len * SizeOf(Char));
    Len := Length(Rec.add);
    Buffer.Write(Len, SizeOf(Len));
    if Len > 0 then
      Buffer.Write(Rec.add[1], Len * SizeOf(Char));
    Buffer.Write(Rec.age, SizeOf(Rec.age));
    CopyData.dwData := 0;
    CopyData.cbData := Buffer.Size;
    CopyData.lpData := Buffer.Memory;
    SendMessage(Target, wm_CopyData, Source, LParam(@CopyData));
  finally
    Buffer.free;
  end;
end;

We write the lengths of the strings in addition to the strings' characters so that the recipient knows how many characters belong to each one. The recipient's code will look like this:

procedure TBasicForm.WMCopyData(var Message: TWMCopyData);
var
  Rec: TMyRec;
  Len: Integer;
  Buffer: TStream;
begin
  Buffer := TReadOnlyMemoryStream.Create(
    Message.CopyDataStruct.lpData, Message.CopyDataStruct.cbData);
  try
    if Message.CopyDataStruct.dwData = 0 then begin
      Buffer.Read(Len, SizeOf(Len));
      SetLength(Rec.name, Len);
      if Len > 0 then
        Buffer.Read(Rec.name[1], Len * SizeOf(Char));

      Buffer.Read(Len, SizeOf(Len));
      SetLength(Rec.add, Len);
      if Len > 0 then
        Buffer.Read(Rec.add[1], Len * SizeOf(Len));

      Buffer.Read(Rec.age, SizeOf(Rec.age));

      // TODO: Do stuff with Rec here.

      Message.Result := 1;
    end else
      inherited;
  finally
    Buffer.Free;
  end;
end;

I've used the non-standard TReadOnlyMemoryStream since it makes everything easier. Here's a simple implementation for it:

type
  TReadOnlyMemoryStream = class(TCustomMemoryStream)
  public
    constructor Create(Mem: Pointer; Size: LongInt);
    function Write(const Buffer; Count: LongInt): LongInt; override;
  end;

constructor TReadOnlyMemoryStream.Create;
begin
  inherited Create;
  SetPointer(Mem, Size);
end;

function TReadOnlyMemoryStream.Write;
begin
  Result := 0;
end;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文