Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how send data record using SendMessage(..) in separate process

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;
like image 929
XBasic3000 Avatar asked Dec 05 '22 02:12

XBasic3000


1 Answers

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;
like image 179
Rob Kennedy Avatar answered Jan 01 '23 21:01

Rob Kennedy