Вы правы. Адреса имеют смысл только в одном процессе. Значение 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;
thanx для советов это прекрасно работает .. – XBasic3000