2010-06-17 48 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 2010-06-17 09:18:10

相關問題