delphi中程序間數據傳遞。及消息使用(轉)

在實際應用中,我們經常需要多個程序相互配合來完成某些特定功能。例如兩個應用程序間的同步、互斥;應用程序在起第二份實例時的參數自動傳遞…。要實現這些功能,就必須能實現程序間的數據傳遞。

有些特殊的高級技術可在不同的程序間傳遞數據,如剪貼板、動態數據交換以及OLE自動化,但有條件限制並且相對較複雜。這裏,我介紹三種有效的底層技術,希望對編程愛好者有所幫助。

利用WM_COPYDATA消息
 
使用該消息涉及一個TcopyDataStruct結構類型的指針。該結構中有三個成員:
dwData 是一個32位的附加參數
cbData 表示要傳遞的數據區的大小
lpData 表示要傳遞的數據區的指針

下面舉個例子。該例子由兩個程序構成,分別爲SendData和GetData。

SendData程序向GetData程序發送消息,並傳遞edit1中的字符串;GetData在收到消息後,把SendData發送的字符串接受下來,並顯示在相應的edit1中。

SendData程序:
……

var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
ds: TCopyDataStruct;
hd: THandle;
begin
ds.cbData := Length (Edit1.Text) + 1;
GetMem (ds.lpData, ds.cbData ); //爲傳遞的數據區分配內存
StrCopy (ds.lpData, PChar (Edit1.Text));
Hd := FindWindow (nil, 'Form2'); // 獲得接受窗口的句柄
if Hd <> 0 then
SendMessage (Hd, WM_COPYDATA, Handle,
Cardinal(@ds)) // 發送WM_COPYDATA消息
else
ShowMessage ('目標窗口沒找到!');
FreeMem (ds.lpData); //釋放資源
end;

GetData程序:
 
TForm2 = class(TForm)
Edit1: TEdit;
private
{ Private declarations }
public
procedure Mymessage(var t:TWmCopyData);message WM_COPYDATA;
{ Public declarations }
end;

var
Form2: TForm2;
implementation
procedure TForm2.Mymessage(var t:TWmCopyData);
begin
Edit1.text:=StrPas(t.CopyDataStruct^.lpData);//接受數據並顯示。
end;

使用這種方法是WIN32應用程序進行交互的最簡單的方法。

使用全局原子
Win32系統中,爲了實現信息共享,系統維護了一張全局原子表。每個原子中存放了一些共享數據。關於對原子的操作,有一組專門的API函數:

GlobalAddAtom 在表中增加全局原子
GlobalDeleteAtom 在表中刪除全局原子
GlobalFindAtom 在表中搜索全局原子
GlobalGetAtomName 從表中獲取全局原子

筆者用這種方法實現了避免程序二次啓動,但把第二次啓動所帶的參數傳到第一個實例中以進行相應的處理的程序。基本處理如下:

在工程文件中:

program Pvdde;
uses
Forms,shellapi,Windows,dialogs,dde in 'dde.pas' {Form1};
{$R *.RES}
begin
if GlobalFindAtom(PChar('PDDE_IS_RUNNING')) = 0 then
//避免二次啓動
begin
K:=GlobalAddAtom(PChar('PDDE_IS_RUNNING'));
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end
else
begin

//傳遞二次啓動時的參數到第一個實例

H := FindWindow(PChar('TForm1'), PChar('資料保密 嚴禁外傳'));
if ParamCount > 0 then
begin
L := GlobalAddAtom(PChar(ParamStr(1)));
if H<>0 then
SendMessage(H, WM_MYMESSAGE, 0, L);
{ 傳遞原子句柄 }
GlobalDeleteAtom(L); { 使用後釋放 }
end;

Application.Terminate;
end;
end.

在相應的窗口單元dde.pas增加對自定義消息WM_MYMESSAGE的處理:

procedure TForm1.MyMessage(var T:TMessage);
{對 WM_MYMESSAGE消息進行處理 }
var
P:Array [0..255] of char;
begin
GlobalGetAtomName(T.LParam, P,255); { 接受數據到p數組中 }
。。。

end;

使用存儲映象文件
這種方法相對較複雜一些。

當Win95與Winows Nt向內存中裝載文件時,使用了特殊的全局內存區。在該區域內,應用程序的虛擬內存地址和文件中的相應位置一一對應。由於所有進程共享了一個用於存儲映象文件的全局內存區域,因而當兩個進程裝載相同模塊(應用程序或DLL文件)時,它們實際可以在內存中共享其執行代碼。

筆者通過調用一個帶有特殊參數的CreateFileMapping函數,來間接達到程序間共享內存的目的。下面簡要解釋一下該函數。

HANDLE CreateFileMapping(
HANDLE hFile, //文件句柄
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 可選安全屬性
DWORD flProtect, // 映象文件保護方式
DWORD dwMaximumSizeHigh, // 映象文件區域的底值
DWORD dwMaximumSizeLow, // 映象文件區域的頂值
LPCTSTR lpName // 映象文件的名字
);

如果hFile是0xFFFFFFFF,在調用程序中必須指定dwMaximumSizeHigh 和dwMaximumSizeLow參數的值以確定映象文件的大小。通過這樣的參數指定,該函數就創建了一個由操作系統頁文件支持的特殊邏輯映象文件,而不是由實際操作系統的文件支持的邏輯映象文件。這個邏輯映象文件可以通過複製、繼承或者按名字來達到共享。至於其它參數的詳細說明,請參看在線幫助。

在建立了映象文件之後,我們可以通過調用另外一個API函數MapViewOfFile來訪問它的內存,該函數會返回一個指向共享內存塊的特定指針。

LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // 映象文件句柄
DWORD dwDesiredAccess, // 訪問方式
DWORD dwFileOffsetHigh, // 映象文件區域的底值
DWORD dwFileOffsetLow, // 映象文件區域的頂值
DWORD dwNumberOfBytesToMap // 映射字節數
);

如果 dwNumberOfBytesToMap 是0,映射整個文件。以下舉例說明:

private
hMapfile: THandle;
MapFilePointer: Pointer;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
hMapFile := CreateFileMapping (
$FFFFFFFF, // 特殊內存映射句柄
nil, page_ReadWrite, 0,10000,
'DdhDemoMappedFile'); // 文件名
if hMapFile <> 0 then
MapFilePointer := MapViewOfFile (
hMapFile, // 上面映象文件的句柄
File_Map_All_Access,
0, 0, 0) // 訪問整個映象文件
else
ShowMessage ('hMapFile = 0');
if MapFilePointer = nil then
ShowMessage ('MapFilePointer = nil');
end;

procedure TForm1.BtnWriteClick(Sender: TObject);
begin
StrCopy (PChar (MapFilePointer),
PChar (EditWrite.Text));//把內容寫入共享內存
end;

procedure TForm1.BtnReadClick(Sender: TObject);
var
S: string;
begin
S := PChar (MapFilePointer);//從共享內存讀出內容
EditRead.Text := S;
end;

用這種方法,不但可以在不同的程序之間共享數據,還可以在同一程序的不同實例間共享數據。爲了及時通知其它進程共享數據的變化,可以自定義一條用戶消息,通過發消息來實現,這裏不再贅述。

利用以上三種方法均可以有效地實現數據傳遞、共享,所有的例子程序均在Delphi 3.0,4.0下調試通過。如需源碼,寫信至[email protected]索要 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章