大家知道在Window 9x中一個應用程序不能直接訪問另一個程序的內存地址,因為WIN9x為每個運行中的進程提供了自己的虛擬空間,這起到了很好的保護作用,然而,它也使得兩個程序間不能輕易的交換數據,但是這並不是說程序間就一定不能進行數據傳送了,Win9x為我們提供了幾個特殊的方法來實現這個目的,如通過Windows消息WM_CopyData 和存儲影響文件等方法。
使用消息WM_CopyData傳送需要傳遞的數據緩沖區的內存地址,前面講過,我們不能從一個應用程序向另一個程序發送內存塊的地址,因為一個虛擬存儲空間中的地址在另一個地址空間中沒有意義。但是WM_CopyData消息回在後台執行一些特殊操作之後在傳遞數據,因此我們能夠在接受方得到正確的地址。該消息使用時需要傳遞正在發送消息的窗口的句柄,及一個指TCopyDataStruct結構的指針。該結構如下:
tagCOPYDATASTRUCT = packed record
dwData: DWord;
//這是一個附加的32位參數;
cbData: DWord;
//我們將要傳遞的數據緩沖區的大小;
lpData: Pointer;
//指向數據緩沖區的指針。
end;
TCopyDataStruct=tag COPYDATASTRUCT;
一個例子,SendData程序包含一個文本框,在它的OnChange事件中將文本框中的內容發送到GetData程序重並顯示出來。
在SendCopyData程序裡,文本框OnChange事件的處理函數如下:
procedure TForm1.InputEditChange(Sender: TObject);
var
cds: TCopyDataStruct;
ss: PChar;
targetHandle: THandle;
begin
cds.cbData:=Length(InputEdit.Text)+1;
GetMem(ss,cds.cbData); //申請cbData大小的緩沖區,並把指針賦給ss;
strCopy(ss,Pchar(InputEdit.text));
cds.lpData:=ss; //設置緩沖區指針
targetHandle:=FindWindow(′TForm1′,′GetCopyData′); //用API函數獲取″GetCopyData″窗口句柄
if targetHandle=0 then
begin
ShowMessage(′Don′'t find target window′);
exit;
end;
SendMessage(targetHandle,WM_COPYDATA,Handle,Integer((@cds)));//將cds結構指針發送個目標窗口;
//targetHandle使目標窗口句柄;
//Handle 發送消息的窗口句柄;
FreeMem(ss);
end;
在GetCopyData程序中,通過一個定制的消息處理程序接受wm_CopyData消息:
public
procedure GetCopyData(var msg: TWMCopyData); message WM_COPYDATA;
procedure TForm1.GetCopyData(var msg: TWMCopyData);
begin
with msg.CopyDataStruct^ do
begin
Form1.Edit1.Text:=PChar(lpdata);
end;
end;
其中TWMCopyData結構定義如下:
TWMCopyData = record
Msg: Cardinal;
From: HWND; //發送該消息的窗口的句柄
CopyDataStruct: PCopyDataStruct; //即SendCopyData程序中cds結構的指針
Result: Longint;
end;
除了用wm_CopyData消息傳遞數據外,Windows還提供了File_Mapping內存共享技術用於實現程序間數據共享。使用與上例窗口相似的兩個程序來說明
在MapWrite程序中:
Private
HMapFile: Thanale;
MapFilePointer: Pointer;
procedure TForm1.FormCreate(Sender: TObject);
begin
//使用API函數來建立映象文件
hMapFile:=CreateFileMapping(
$FFFFFFFF, //指定共享內存
nil,
Page_ReadWrite, //共享方式
0,
1000, //共享內存大小
′MyMappedFile′); //映象文件的名字
if hMapFile<>0 then //如果映象文件建立成功
//MapVIEwOfFile函數返回一個指向共享內存塊的在該程序內存空間中有效的指針
MapFilePointer:=MapVIEw OfFile(hMapFile,File-Map-All-Access,0,0,0)
else
ShowMessage(′Can′'t Create MapFile′);
if MapFilePointer=nil then
ShowMessage(′MapFilePointer=nil′);
end;
procedure TForm1.Edit1Change(Sender: TObject);
begin
StrCopy(PChar(MapFilePointer),PChar(Edit1.Text));//將文本框中的字符串copy到共享內存中
end;
在MapRead程序中使用API函數OpenFileMapping打開MapWrite程序中已建立的映象文件
procedure TForm1.FormCreate(Sender: TObject);
begin
hMapFile:=OpenFileMapping(FILE_MAP_READ,true,′MyMappedFile′); //取得′MyMappedFile′映象文件的句柄
if hMapFile<>0 then
MapFilePointer:=MapVIEwOfFile(hMapFile,File_Map_All_Access,0,0,0)
else
begin
ShowMessage(′Can not open Mapp File′);
Timer1.Enabled:=false;
end;
end;
//定時從共享內存中讀取數據並顯示出來
procedure TForm1.Timer1Timer(Sender: TObject);
var
ss: String;
begin
ss:=PChar(MapFilePointer);
Edit1.Text:=ss;
end;
當然最後我們要釋放共享內存句柄
UnMapVIEwOfFile(MapFilePointer);
CloseHandle(hMapFile);