あなたが正しい。アドレスは、単一のプロセス内でのみ意味を持ちます。最初のプロセスで作成した PMyRec 値は、ターゲット プロセスのガベージ アドレスにすぎません。
ウィンドウメッセージを介して任意のメモリブロックを別のプロセスに送信するには、wm_CopyData
メッセージを使用する必要があります。そのメッセージにデータのアドレスとサイズを指定すると、OS がそれをターゲット プロセスのアドレス空間にコピーします。
データには別のポインターとして内部的に表される文字列が含まれているため、レコードの 12 バイトをコピーするだけでは十分ではありません。レコードと文字列データを 1 つのメモリ ブロックに保持するために、追加のメモリを割り当てる必要があります。これにより、レコードをwm_CopyData
コピーして、ターゲット プロセスがそれを読み取れるようになります。
これは、ストリームを使用してデータを単一のメモリ ブロックに収集する方法の 1 つです。
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;