Vous avez raison. Les adresses n'ont de sens que dans un seul processus. La valeur PMyRec que vous créez dans le premier processus est juste une adresse de mémoire dans le processus cible.
Pour envoyer un bloc de mémoire arbitraire à un autre processus via un message de fenêtre, vous devez utiliser le message wm_CopyData
. Vous donnez ce message l'adresse des données et la taille, et le système d'exploitation prend soin de le copier dans l'espace d'adressage du processus cible.
Étant donné que vos données incluent une chaîne, qui est représentée en interne sous la forme d'un autre pointeur, il ne suffit pas de simplement copier les 12 octets de votre enregistrement. Vous devrez allouer de la mémoire supplémentaire pour contenir l'enregistrement et les données de chaîne dans un seul bloc de mémoire afin que wm_CopyData
puisse le copier et que le processus cible puisse le lire.
Voici une façon de le faire, en utilisant un flux pour collecter les données dans un seul bloc de mémoire.
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;
Nous écrivons les longueurs des cordes en plus des caractères des chaînes afin que le destinataire sait combien de personnages appartiennent à chacun. Le code du destinataire ressemblera à ceci:
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;
Je l'ai utilisé le TReadOnlyMemoryStream
non standard, car il rend tout plus facile. Voici une implémentation simple pour cela:
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;
merci pour les conseils cela fonctionne très bien .. – XBasic3000