2010-06-17 2 views
2

J'utilise pour envoyer une donnée sur deux processus séparés mais il échoue. cela ne fonctionne que sous le même processus ... c'est un concept.comment envoyer un enregistrement de données en utilisant SendMessage (..) dans un processus séparé

// -------------------------------------------- ---------------------------------------
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; 

// ----------- -------------------------------------------------- ----------------------
Sous-applications
// --------------------- -------------------------------------------------- ------------

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; 

Répondre

14

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; 
+0

merci pour les conseils cela fonctionne très bien .. – XBasic3000

Questions connexes