Windows作業系統是一個多任務系統,每個任務都有相應的程序對應。熟悉windows系統的使用者知道,每個程序都有自己獨立的記憶體位址和記憶體空間。這對程序間之間的資料互相通路和互相交換帶來一定的不便,但是在實際應用中有時要在程序間進行資料交換。windows系統提供了許多方法實作程序間的資料交換,比如我們可以通過磁盤檔案來進行交換,這實際是最簡單可行的辦法,但運作速度大打折扣,特别是對于大批量資料交換時。另外我們可以通過Windows系統提供的CreateFileMaping、OpenFileMapping、MapViewofFile等API函數來實作程序間的資料交換,但實作方法相對複雜。
本文将介紹另外兩種程序間資料交換的方法,一種是通過剪貼闆的程序資料交換方法,另一種是直接記憶體讀取的程序資料交換方法。最後将用Delphi語言舉例加以實作應用。
一、通過剪貼闆的程序資料交換方法
剪貼闆是windows系統專門提供用來不同應用程式之間的資料交換,使用者隻要通過“複制”和“粘帖”兩個動作就可以實作應用程式之間的資料交換。使用者可以自定義剪貼闆格式實作資料交換的目的。
其方法步驟為:
1、資料發送程序向剪貼闆“複制”使用者自定義的資料内容
2、資料發送程序向資料接受程序發送資料交換的消息。
3、資料接受程序收到消息以後向剪貼闆“粘貼”使用者自定義的資料内容。
這種方法的實作過程如圖一所示:
該方法涉及到的重要API函數主要有:
1、RegisterClipboardFormat
這個函數是向系統剪貼闆注冊新的剪貼闆資料格式其函數調用格式為:
UINT RegisterClipboardFormat(
LPCTSTR lpszFormat // 新剪貼闆資料格式的名稱
); |
如果該名稱的剪貼闆格式已經注冊函數傳回已經的标示号,否則函數傳回一個新的标示号。
2、GlobalAlloc、GlobalLock
這兩個函數前者是用于從目前程序的記憶體空間配置設定一定位元組數的記憶體,後者是對指定的記憶體加鎖。它們的函數調用格式分别為:
HGLOBAL GlobalAlloc(
UINT uFlags, //配置設定到的記憶體屬性
DWORD dwBytes // 需要記憶體配置設定的空間大小
);
LPVOID GlobalLock(
HGLOBAL hMem // 需要加鎖的記憶體“句柄”
); |
3、Clipboard的Open、SetAsHandle、Close、GetAsHandle
這四個函數是Delphi語言Clipboard全局變量提供專門用于對剪貼闆資料“複制”和“粘帖”動作所要用到的函數。在Clipbrd.pas單元中實作。其函數格式略。
二、直接記憶體讀取的程序資料交換方法
這種方法是通過Windows系統一系列API函數調用直接讀取另一個程序的記憶體,來實作資料交換的目的。
其方法步驟為:
1、資料發送方程序資料接受方程序發送資料交換的消息,Wparam參數值為資料發送方程序标示号,Lparam參數值為要發送的資料的位址。
2、資料接受方程序收到消息以後直接讀取資料發送方程序記憶體位址的資料。
這種方法的實作過程如圖二所示:
該方法涉及的重要API函數主要有:
1、GetCurrentProcessId
這個函數主要擷取目前運作程序的程序标示号,其函數格式為:
DWORD GetCurrentProcessId(VOID) |
2、openProcess
這個函數主要獲得一個已經運作的程序的“程序句柄”,以便在另外的API函數調用。其函數格式為:
HANDLE OpenProcess(
DWORD dwDesiredAccess, // 要打開的程序的通路模式
BOOL bInheritHandle, // 該程序句柄是否在子線程中繼承
DWORD dwProcessId // 程序的标示号
); |
3、ReadProcessMemory
這個函數是直接記憶體讀取的程序資料交換方法最核心的一個函數,它實作從另一個程序中讀取記憶體資料。其函數格式為:
BOOL ReadProcessMemory(
HANDLE hProcess, //程序句柄
LPCVOID lpBaseAddress, // 要讀取記憶體的起始位址
LPVOID lpBuffer, //存放讀取的資料的變量
DWORD nSize, //需要讀取的位元組數
LPDWORD lpNumberOfBytesRead // 實際讀取到的位元組數
); |
三、兩種程序資料交換方法的應用舉例
為了更加詳細地介紹上述兩種方法,下面利用Delphi語言結合實際的例子來闡述它的應用。該例子分别用通過剪貼闆的程序資料交換的方法和直接記憶體讀取的程序資料交換方法實作兩個程序間的交換一個記錄資料,該記錄的資料格式為:
TFriend=packed record
name :array[1..8] of char;
age :byte;
address :array[1..30] of char;
end; |
另外定義兩條消息和幾個需要用到的常量:
1.WM_Datasend_byClpbrd=WM_user+1000; //用于通過剪貼闆的程序資料交換的方法的消息;
2.WM_DataSend_byMemory=WM_user+1001;// 直接記憶體讀取的程序資料交換方法的消息;
3.receivewindowcaption='DataReceiver'; //接收資料程序視窗的标題;
4.receivewindowclassname='Data Receive Window';//接受資料程序視窗的類别名稱;
5.userDefineformat='process data exchange'; //自定義剪貼闆資料格式名稱; |
以上常量和記錄結構是發送程序和接受程序的兩個程式都要用到的資料。可以單獨存放在一個檔案中用uses引用,或用{$I }的方法引用。
(一)資料發送程序程式的實作
1、在Delphi的IDE環境中建立Application
2、在Form1中加入一個Tspinedit、兩個Tedit和兩個Tbutton控件(分别為Button1和button2),兩個Edit控件分别供輸入姓名和位址,SpinEdit控件供輸入年齡。
3、重載Button1的onClick程式用于剪貼闆資料交換,如下所示:
procedure TForm1.Button1Click(Sender: TObject);
var
wnd :Hwnd;
Friend :TFriend;
hmem :Thandle;
datapointer :pointer;
CF_User :Uint;
begin
//尋找資料接受程序的視窗
wnd:=findwindow(receivewindowclassname,receivewindowcaption);
//如果找到了向剪貼闆複制資料并且向資料接受程序發送消息
if wnd<>0 then
begin
//申請記憶體
hmem:=globalAlloc(GMEM_MOVEABLE,sizeof(friend));
//給記錄指派
strpcopy(@friend.name,edit1.text);
friend.age:=byte(spinedit1.Value);
strpcopy(@friend.address,edit2.text);
//擷取申請到的記憶體位址并且把記錄的值導入記憶體
DataPointer := GlobalLock(hmem);
//把記錄資料複制到Global記憶體中
move(friend,datapointer^,sizeof(friend));
//注冊或擷取新的剪貼闆資料格式标号
CF_User:=registerclipboardformat(userdefineformat);
//向剪貼闆複制資料
clipboard.Open;
clipboard.SetAsHandle(CF_USER,hmem);
clipboard.Close;
//向接收程序視窗發送消息
sendmessage(wnd,WM_Datasend_byClpbrd,0,0);
end;
end; |
4、重載button2的OnClick程式用于直接記憶體讀取的資料交換,如下所示:
procedure TForm1.Button2Click(Sender: TObject);
var
wnd :Hwnd;
Friend :TFriend;
Begin
//尋找資料接受程序的視窗
wnd:=findwindow(receivewindowclassname,receivewindowcaption);
//如果找到了向資料接收程序視窗發送消息
if wnd<>0 then
begin
//對記錄指派
strpcopy(@friend.name,edit1.text);
friend.age:=byte(spinedit1.Value);
strpcopy(@friend.address,edit2.text);
//發送消息,把發送程序的程序标示号作為Wparam
//把記錄位址作為Lparam進行傳遞
sendmessage(wnd,WM_DataSend_byMemory,
getcurrentprocessID,lparam(@Friend));
end;
end; |
5、儲存、編譯、運作
(二)資料接受程序程式的實作
1、在Delphi的IDE環境建立Application;
2、在Form1中加入三個Tedit控件,接受發送過來的資料;
3、重載Form1的CreateParams程式,重新定義Form1的類,程式如下:
procedure TForm1.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
params.Caption:=receivewindowcaption;
Params.WinClassName :=receivewindowclassname;
end; |
4、重載在Form1的wndproc程式接受兩種方法發送過來的資料,程式如下:
procedure Tform1.wndproc(var message:Tmessage);
var
processhnd :Thandle;
Friend :TFriend;
numread :dword;
hmem :Thandle;
clipdata :pointer;
CF_User :Uint;
Begin
Case message.msg of
//處理剪貼闆方式發送過來的消息
WM_Datasend_byClpbrd:
Begin
//注冊或擷取新的剪貼闆資料格式标号
CF_User:= registerclipboardformat(userdefineformat);
if clipboard.HasFormat(CF_User) then
begin
//擷取剪貼闆的内容,并且分别指派給三個Edit
hmem:=clipboard.GetAsHandle(CF_user);
clipdata:=globallock(hmem);
if clipdata<>nil then
begin
move(clipdata^,Friend,sizeof(Friend));
edit1.text:=Friend.name;
edit2.text:=inttostr(Friend.age);
edit3.text:=Friend.address;
end;
end;
message.Result:=1;
End;
//處理直接記憶體讀取發送過來的消息
WM_DataSend_byMemory:
Begin
//擷取發送程序的“程序句柄”,設定通路模式為“讀”
processhnd:=openprocess(PROCESS_VM_READ,
false,message.WParam);
//讀取發送程序的記憶體資料
readprocessmemory(processhnd,
ptr(message.lparam),
@friend,sizeof(friend),numread);
edit1.text:=Friend.name;
edit2.text:=inttostr(Friend.age);
edit3.text:=Friend.address;
closehandle(processhnd);
message.result:=1;
End;
Else
//對于其它消息依然按照原來的方法進行消息處理
Inherited wndproc(message);
End; |
5、儲存、編譯、運作
到這裡為止已經實作上述程序間記錄資料的交換的兩種方法。運作結果如圖三所示:
圖三
以上程式僅僅是上面介紹的兩種方法最簡單應用,使用者可以根據自己的實際需要加以拓展應用。上述程式在Windows 2000+Delphi 5.0的環境下運作通過。
轉自:http://industry.ccidnet.com/art/322/20031027/68697_1.html
下面是我寫的剪貼闆交換資料的代碼 點選下載下傳