2010-06-17 1 views
2

Я использую для отправки данных по двум отдельным процессам, но это не удается. он работает только при одном и том же процессе ... это концепция.как отправить запись данных с помощью SendMessage (..) в отдельный процесс

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

ответ

14

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

thanx для советов это прекрасно работает .. – XBasic3000