浅谈Delphi中进程间的数据共享 |
DLL是 缔造Windows 利用程序,实现代码重用的主要 目的 。那么当我们需求在 历程间共享数据时, 怎么做 威力快捷容易地实现呢?在32位 利用系统中,每个 利用程序会将DLL映射到自己的地址空间,同时DLL中的数据也就随之被映射了 。这样,每个 利用程序都有自己的数据实例,在一个 利用程序中 批改DLL中的全局变量,不会影响其它的 利用程序 。DLL的 使用 仿佛与我们的 目标相背离,那么如何 威力实现我们想要的东东呢?这里给大家介绍一种特别的技术,那便是内存映射文件 。 内存映射文件提供了一种 步骤,便是在WIN32系统的地址空间保留一块内存区域,物理存储 可以向其中提交 。而且内存映射文件 不仅是磁盘文件,也 可以是WIN32的页面文件,而且后者比前者要好,由于这 象征着 可以像 拜访一个磁盘文件那样 拜访内存中的一个区域,而不用 缔造暂时文件,用完后还得删除它 。WIN32有自己的治理页面调度文件,当不需求页面调度文件时,系统会自动将有关区域 开释 。以下是具体的实现代码: library Project1; uses shareMem, windows, SysUtils, Classes; const MFileName: Pchar = ’ShareData’; //定义一个记录类型,你所需求共享的数据就 保留在这里 。 //当在 历程中调用GetDllData时, 历程中也应该定义一个与这个一样的记录类型 。 type PGlobalDllData = ^TGlobalDllData; TGlobalDllData = record s: string[50]; i: integer; end; var GlobalData: PGlobalDllData; //这是一个全局变量,指向 缔造的内存映射文件 。 MapHandle: THandle; //给外部 历程调用的过程,当外部 历程调用这个过程后,形参AGlobalData就指向了我//们 缔造的内存映射文件. 我们 可以 缔造两个 历程, 同时调用这个过程, 那么在其中一个进 //程中 批改数据后, 在另外一个 历程中既可 反响出来, 实现了我们需求的共享. procedure GetDllData(var AGlobalData: PGlobalDllData);stdcall; begin AGlobalData := GlobalData; end; procedure OpenThisData; var size: integer; begin size := sizeof(TGlobalDllData); // 缔造一个内存文件映射对象,MfileName 保留的值便是该对象的名字 。 mapHandle := CreateFileMapping(Dword(-1), nil, page_readWrite, 0, size, MFileName); if mapHandle = 0 then RaiseLastWin32Error; //把文件的视图映射到调用 历程的地址空间,该函数的返回值便是该对象的首地址 。注//意,这是调用 历程的地址,两个 利用程序调用该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从 历程中 拆散出来时,应该 开释相应的空间 procedure CloseThisData; begin unmapViewOfFile(GlobalData); closeHandle(MapHandle); end; procedure DllEntryPoint(dwReason: DWord); begin case dwReason of Dll_Process_Attach: OpenThisData; //调用DLL时传入的参数,由系统自动传入 Dll_Process_Detach: CloseThisData; // 开释DLL时传入的参数,系统自动传入 。 end; end; {$R *.res} exports GetDllData; //外部 利用程序调用的便是这个过程 。
begin DllProc := @DllEntryPoint; //该变量是一个全局变量,由它来指定DLL的入口及出 //口函数 。 DllEntryPoint(Dll_Process_Attach); end. //以上代码在DELPHI6中编译通过 。 |