淺談Delphi中進(jìn)程間的數(shù)據(jù)共享

字號:

DLL是創(chuàng)建Windows應(yīng)用程序,實(shí)現(xiàn)代碼重用的重要手段。那么當(dāng)我們需要在進(jìn)程間共享數(shù)據(jù)時,怎樣做才能快捷方便地實(shí)現(xiàn)呢?在32位應(yīng)用系統(tǒng)中,每個應(yīng)用程序會將DLL映射到自己的地址空間,同時DLL中的數(shù)據(jù)也就隨之被映射了。這樣,每個應(yīng)用程序都有自己的數(shù)據(jù)實(shí)例,在一個應(yīng)用程序中修改DLL中的全局變量,不會影響其它的應(yīng)用程序。DLL的使用似乎與我們的目的相背離,那么如何才能實(shí)現(xiàn)我們想要的東東呢?這里給大家介紹一種特殊的技術(shù),那就是內(nèi)存映射文件。
    內(nèi)存映射文件提供了一種方法,就是在WIN32系統(tǒng)的地址空間保留一塊內(nèi)存區(qū)域,物理存儲可以向其中提交。并且內(nèi)存映射文件不只是磁盤文件,也可以是WIN32的頁面文件,而且后者比前者要好,因?yàn)檫@意味著可以像訪問一個磁盤文件那樣訪問內(nèi)存中的一個區(qū)域,而不用創(chuàng)建臨時文件,用完后還得刪除它。WIN32有自己的管理頁面調(diào)度文件,當(dāng)不需要頁面調(diào)度文件時,系統(tǒng)會自動將有關(guān)區(qū)域釋放。以下是具體的實(shí)現(xiàn)代碼:
    library Project1;
    uses
    shareMem,
    windows,
    SysUtils,
    Classes;
    const
    MFileName: Pchar = ’ShareData’;
    //定義一個記錄類型,你所需要共享的數(shù)據(jù)就保存在這里。
    //當(dāng)在進(jìn)程中調(diào)用GetDllData時,進(jìn)程中也應(yīng)該定義一個與這個一樣的記錄類型。
    type
    PGlobalDllData = ^TGlobalDllData;
    TGlobalDllData = record
    s: string[50];
    i: integer;
    end;
    var
    GlobalData: PGlobalDllData; //這是一個全局變量,指向創(chuàng)建的內(nèi)存映射文件。
    MapHandle: THandle;
    //給外部進(jìn)程調(diào)用的過程,當(dāng)外部進(jìn)程調(diào)用這個過程后,形參AGlobalData就指向了我//們創(chuàng)建的內(nèi)存映射文件. 我們可以創(chuàng)建兩個進(jìn)程, 同時調(diào)用這個過程, 那么在其中一個進(jìn) //程中修改數(shù)據(jù)后, 在另外一個進(jìn)程中既可反應(yīng)出來, 實(shí)現(xiàn)了我們需要的共享.
    procedure GetDllData(var AGlobalData: PGlobalDllData);stdcall; begin
    AGlobalData := GlobalData;
    end;
    procedure OpenThisData;
    var
    size: integer;
    begin
    size := sizeof(TGlobalDllData);
    //創(chuàng)建一個內(nèi)存文件映射對象,MfileName保存的值就是該對象的名字。
    mapHandle := CreateFileMapping(Dword(-1), nil, page_readWrite, 0, size, MFileName);
    if mapHandle = 0 then
    RaiseLastWin32Error;
    //把文件的視圖映射到調(diào)用進(jìn)程的地址空間,該函數(shù)的返回值就是該對象的首地址。注//意,這是調(diào)用進(jìn)程的地址,兩個應(yīng)用程序調(diào)用該DLL,返回值是不一樣的。
    GlobalData := MapViewOfFile(mapHandle, File_map_all_Access, 0, 0, size);
    Globaldata^.s := ’TEST’;
    GlobalData^.i := 5;
    if GlobalData = nil then
    begin
    CloseHandle(MapHandle);
    RaiseLastWin32Error;
    end;
    end;
    //DLL從進(jìn)程中分離出來時,應(yīng)該釋放相應(yīng)的空間
    procedure CloseThisData;
    begin
    unmapViewOfFile(GlobalData);
    closeHandle(MapHandle);
    end;
    procedure DllEntryPoint(dwReason: DWord);
    begin
    case dwReason of
    Dll_Process_Attach: OpenThisData; //調(diào)用DLL時傳入的參數(shù),由系統(tǒng)自動傳入
    Dll_Process_Detach: CloseThisData; //釋放DLL時傳入的參數(shù),系統(tǒng)自動傳入。
    end;
    end;
    {$R *.res}
    exports
    GetDllData; //外部應(yīng)用程序調(diào)用的就是這個過程。
    begin
    DllProc := @DllEntryPoint; //該變量是一個全局變量,由它來指定DLL的入口及出 //口函數(shù)。
    DllEntryPoint(Dll_Process_Attach);
    end.
    //以上代碼在Delphi6中編譯通過。