?? 用delphi實(shí)現(xiàn)程序間的數(shù)據(jù)傳遞 (2001年5月15日).txt
字號(hào):
用Delphi實(shí)現(xiàn)程序間的數(shù)據(jù)傳遞 (2001年5月15日)
本站更新 分類:系統(tǒng) 作者:wangjing 推薦: 閱讀次數(shù):305
(http://www.codesky.net)
--------------------------------------------------------------------------------
在實(shí)際應(yīng)用中,我們經(jīng)常需要多個(gè)程序相互配合來(lái)完成某些特定功能。例如兩個(gè)應(yīng)用程序間的同步、互斥;應(yīng)用程序在起第二份實(shí)例時(shí)的參數(shù)自動(dòng)傳遞…。要實(shí)現(xiàn)這些功能,就必須能實(shí)現(xiàn)程序間的數(shù)據(jù)傳遞。
有些特殊的高級(jí)技術(shù)可在不同的程序間傳遞數(shù)據(jù),如剪貼板、動(dòng)態(tài)數(shù)據(jù)交換以及OLE自動(dòng)化,但有條件限制并且相對(duì)較復(fù)雜。這里,我介紹三種有效的底層技術(shù),希望對(duì)編程愛(ài)好者有所幫助。
利用WM_COPYDATA消息
使用該消息涉及一個(gè)TcopyDataStruct結(jié)構(gòu)類型的指針。該結(jié)構(gòu)中有三個(gè)成員:
dwData 是一個(gè)32位的附加參數(shù)
cbData 表示要傳遞的數(shù)據(jù)區(qū)的大小
lpData 表示要傳遞的數(shù)據(jù)區(qū)的指針
下面舉個(gè)例子。該例子由兩個(gè)程序構(gòu)成,分別為SendData和GetData。
SendData程序向GetData程序發(fā)送消息,并傳遞edit1中的字符串;GetData在收到消息后,把SendData發(fā)送的字符串接受下來(lái),并顯示在相應(yīng)的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 ); //為傳遞的數(shù)據(jù)區(qū)分配內(nèi)存
StrCopy (ds.lpData, PChar (Edit1.Text));
Hd := FindWindow (nil, 'Form2'); // 獲得接受窗口的句柄
if Hd <> 0 then
SendMessage (Hd, WM_COPYDATA, Handle,
Cardinal(@ds)) // 發(fā)送WM_COPYDATA消息
else
ShowMessage ('目標(biāo)窗口沒(méi)找到!');
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);//接受數(shù)據(jù)并顯示。
end;
使用這種方法是WIN32應(yīng)用程序進(jìn)行交互的最簡(jiǎn)單的方法。
使用全局原子
Win32系統(tǒng)中,為了實(shí)現(xiàn)信息共享,系統(tǒng)維護(hù)了一張全局原子表。每個(gè)原子中存放了一些共享數(shù)據(jù)。關(guān)于對(duì)原子的操作,有一組專門(mén)的API函數(shù):
GlobalAddAtom 在表中增加全局原子
GlobalDeleteAtom 在表中刪除全局原子
GlobalFindAtom 在表中搜索全局原子
GlobalGetAtomName 從表中獲取全局原子
筆者用這種方法實(shí)現(xiàn)了避免程序二次啟動(dòng),但把第二次啟動(dòng)所帶的參數(shù)傳到第一個(gè)實(shí)例中以進(jìn)行相應(yīng)的處理的程序?;咎幚砣缦拢?
在工程文件中:
program Pvdde;
uses
Forms,shellapi,Windows,dialogs,dde in 'dde.pas' {Form1};
{$R *.RES}
begin
if GlobalFindAtom(PChar('PDDE_IS_RUNNING')) = 0 then
//避免二次啟動(dòng)
begin
K:=GlobalAddAtom(PChar('PDDE_IS_RUNNING'));
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end
else
begin
//傳遞二次啟動(dòng)時(shí)的參數(shù)到第一個(gè)實(shí)例
H := FindWindow(PChar('TForm1'), PChar('資料保密 嚴(yán)禁外傳'));
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.
在相應(yīng)的窗口單元dde.pas增加對(duì)自定義消息WM_MYMESSAGE的處理:
procedure TForm1.MyMessage(var T:TMessage);
{對(duì) WM_MYMESSAGE消息進(jìn)行處理 }
var
P:Array [0..255] of char;
begin
GlobalGetAtomName(T.LParam, P,255); { 接受數(shù)據(jù)到p數(shù)組中 }
。。。
end;
使用存儲(chǔ)映象文件
這種方法相對(duì)較復(fù)雜一些。
當(dāng)Win95與Winows Nt向內(nèi)存中裝載文件時(shí),使用了特殊的全局內(nèi)存區(qū)。在該區(qū)域內(nèi),應(yīng)用程序的虛擬內(nèi)存地址和文件中的相應(yīng)位置一一對(duì)應(yīng)。由于所有進(jìn)程共享了一個(gè)用于存儲(chǔ)映象文件的全局內(nèi)存區(qū)域,因而當(dāng)兩個(gè)進(jìn)程裝載相同模塊(應(yīng)用程序或DLL文件)時(shí),它們實(shí)際可以在內(nèi)存中共享其執(zhí)行代碼。
筆者通過(guò)調(diào)用一個(gè)帶有特殊參數(shù)的CreateFileMapping函數(shù),來(lái)間接達(dá)到程序間共享內(nèi)存的目的。下面簡(jiǎn)要解釋一下該函數(shù)。
HANDLE CreateFileMapping(
HANDLE hFile, //文件句柄
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 可選安全屬性
DWORD flProtect, // 映象文件保護(hù)方式
DWORD dwMaximumSizeHigh, // 映象文件區(qū)域的底值
DWORD dwMaximumSizeLow, // 映象文件區(qū)域的頂值
LPCTSTR lpName // 映象文件的名字
);
如果hFile是0xFFFFFFFF,在調(diào)用程序中必須指定dwMaximumSizeHigh 和dwMaximumSizeLow參數(shù)的值以確定映象文件的大小。通過(guò)這樣的參數(shù)指定,該函數(shù)就創(chuàng)建了一個(gè)由操作系統(tǒng)頁(yè)文件支持的特殊邏輯映象文件,而不是由實(shí)際操作系統(tǒng)的文件支持的邏輯映象文件。這個(gè)邏輯映象文件可以通過(guò)復(fù)制、繼承或者按名字來(lái)達(dá)到共享。至于其它參數(shù)的詳細(xì)說(shuō)明,請(qǐng)參看在線幫助。
在建立了映象文件之后,我們可以通過(guò)調(diào)用另外一個(gè)API函數(shù)MapViewOfFile來(lái)訪問(wèn)它的內(nèi)存,該函數(shù)會(huì)返回一個(gè)指向共享內(nèi)存塊的特定指針。
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // 映象文件句柄
DWORD dwDesiredAccess, // 訪問(wèn)方式
DWORD dwFileOffsetHigh, // 映象文件區(qū)域的底值
DWORD dwFileOffsetLow, // 映象文件區(qū)域的頂值
DWORD dwNumberOfBytesToMap // 映射字節(jié)數(shù)
);
如果 dwNumberOfBytesToMap 是0,映射整個(gè)文件。
以下舉例說(shuō)明:
private
hMapFile: THandle;
MapFilePointer: Pointer;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
hMapFile := CreateFileMapping (
$FFFFFFFF, // 特殊內(nèi)存映射句柄
nil, page_ReadWrite, 0,10000,
'DdhDemoMappedFile'); // 文件名
if hMapFile <> 0 then
MapFilePointer := MapViewOfFile (
hMapFile, // 上面映象文件的句柄
File_Map_All_Access,
0, 0, 0) // 訪問(wèn)整個(gè)映象文件
else
ShowMessage ('hMapFile = 0');
if MapFilePointer = nil then
ShowMessage ('MapFilePointer = nil');
end;
procedure TForm1.BtnWriteClick(Sender: TObject);
begin
StrCopy (PChar (MapFilePointer),
PChar (EditWrite.Text));//把內(nèi)容寫(xiě)入共享內(nèi)存
end;
procedure TForm1.BtnReadClick(Sender: TObject);
var
S: string;
begin
S := PChar (MapFilePointer);//從共享內(nèi)存讀出內(nèi)容
EditRead.Text := S;
end;
用這種方法,不但可以在不同的程序之間共享數(shù)據(jù),還可以在同一程序的不同實(shí)例間共享數(shù)據(jù)。為了及時(shí)通知其它進(jìn)程共享數(shù)據(jù)的變化,可以自定義一條用戶消息,通過(guò)發(fā)消息來(lái)實(shí)現(xiàn),這里不再贅述。
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -