内存映像共享数据

DLL的结构:
链接方式
隐式链接方式
在DLL代码中可以像下面这样明确声明导出函数:
export
FunctionName Index 16 Name MyName,
ProcedureName Index 17 Name YourName,

格式:“函数名 Index xx Name 导出名字”
在应用程序方面,要求像下面一样明确声明相应的引入函数:
procedure MyName;external 'MyLib.dll';
显示链接方式
直接调用LoadLibrary函数,并指定DLL的路径作为参数。
返回HINSTANCE,参数,应用程序GetProcAddress函数时使用这个参数。
GetProcAddress函数将函数名或编号转换为DLL内部的地址。

type
TDllFunction = Function(Src:String; Key:String):string;stdcall;

var
Hmydll: HWND;
mydllfun:TDllFunction;
s,ke:string;
begin
Hmydll := LoadLibrary('mydll.dll');
@mydllfun := GetProcAddress(Hmydll, 'EncrypKey');
if @mydllfun <> nil then
begin
mydllfun(s,ke);
end;
FreeLibrary(Hmydll);
end;

Windows将遵循下面的搜索顺序来定位DLL;
1)包含EXE文件的目录
2)进行的当前工作目录
3)Windows系统目录
4)Windows目录
5)列在Path环境变量中的一系列目录

调用方式:
1)通过过程、函数名
2)通过过程、函数别名
3)通过过程、函数的编号
Function GetString :string;stdcall;external 'Mydll.dll' name 'Mygetstr';
Name 子句指定的函数名Getstring实际上是调用Mydll.dll中的MyGetstr,当程序调用GetString时,实际上是调用 MyGetstr
Function GetString :string;stdcall;external 'Mydll.dll' Index 5;
Index子句 通过函数编号引入函数,这也可以减少DLL的加载时间。但是,建议不使用这种方式。

DLL数据作用范围:
DLL函数中的局部变量的作用范围限于定义的函数中。
DLL源代码中的全局变量对每一个与DLL相连的进程都是全局的。



内存映像:
通过使用映像文件在进程间实现共享文件内存数据块,如果利用相同的映像名字或文件句柄,则不同的进程可通过一个地址指针来读写同一个文件或同一个内存数据块,并把它当做该进程内地址空间的一部分。

Windows向内存装载文件时,使用了特殊的的全局内存区。在该区域内,应用程序的虚拟内存地址和文件中的相应位置对应。由于所有进程共享了一个用于存储映像文件的全局内存区域,因而当两个进程装载相同模块时,它们实际上是在内存中共享其执行代码。

内存映象文件可以映射一个文件、一个文件中的指定区域或者指定的内存块,其中数据就可以用内存读写指令来直接访问,而不必频繁地调用ReadFile或WriteFile这样的I/O系统函数,从而提高了文件存取速度和效率。
创建映像文件:
CreateFileMappin(
hFile:THandle;
hpFileMappingAttributes:PSecurityAttributes;
flProtect:DWORD;
dwMaximumSizeHigh:DWORD;
dwMaximmunSizeLow:DWORD;
lpName:Pchar
);THandle;

hFile:是调用 FileOpen()或FileCreate()函数后返回的文件句柄。如果不是共享文件,而是共享内存区域,在这里需要设为$FFFFFFFF ;
hpFileMappingAttributes:参数是文件映像的安全属性结构(一般设为nil) ;
flProtect:参数是文件视图的保护类型(PAGE_READ 为可读,PAGE_WRITE为可写、PAGE_READWRITE为可读可写) ;
dwMaximumSizeHigh:参数用于指定文件映像的大小的高32位;
dwMaximmunSizeLow:参数用于指定文件映像的大小的低32位;
lpName:参数用于指定映象名。

打开映像文件:
OpenFileMapping(
dwDesiredAccess:DWORD;
bInheritHandle:BOOL;
lpName:PChar
):THandle;
dwDesiredAccess:参数用于指定访问数据的模式(FILE_MAP_READ为可读、 FILE_MAP_WRITE为可写 FILE_MAP_ALL_ACCESS为可读写) ;
bInheritHandle:参数指定OpenFileMapping函数返回 的句柄在以后新建的子进程中是否得到继承
lpName:参数用于指定映像名。

映射到本进程中:
MapViewOfFile(
hFileMappingObject:THandle;
dwDesiredAccess:DWORD;
dwFileOffsetHigh:DWORD;
dwFileOffsetLow:DWORD;
dwNumberOfBytesToMap:DWORD
)Pointer;

hFileMappingObject:参数通过CreateFileMapping()或OpenFileMapping()返回的文件映像的句柄 ;
dwDesiredAccess:参数用于指定访问数据的模式(FILE_MAP_READ为可读、 FILE_MAP_WRITE为可写 FILE_MAP_ALL_ACCESS为可读写) ;
dwFileOffsetHigh:参数用于指定数据映像文件中的起始位置的高32位
dwFileOffsetLow:参数用于指定数据映像文件中的起始位置的低32位 ;
dwNumberOfBytesToMap:参数用于指定需要映射的字节数,设为0表示文件或内存区域的全部。


关闭映射:
UnmapViewOfFile(
lpBaseAddress:Pointer
):BOOL;

用于关闭由MapViewOfFile建立的内存映射
lpBaseAddress:参数是MapViewOfFile函数返回的内存地址指针。

使用内存映像文件I/O需遵循以下步骤:
1)打开磁盘文件。可采用CreateFile或OpenFile函数。一般采用OpenFile()函数;
function OpenFile(const lpFileName;LPCSTR;var lpRcOpenBuff:TOFSTRUCT;uStyle:UINT):HFILE;stdcall;

2)创建文件映像对象。
为了使用内存映像文件,要通过函数CreateFileMapping创建文件映像对象。CreateFileMapping 函数的第一个参数使用上一步得到的文件句柄; 当然也可以设置为$FFFFFFFF,这时文件映像对象是基于内存的,而不是基于文件的,lpszMapName参数是给文件夹映像对象起的名字,必须确保其惟一性,因为与一个未知进程的名字冲突会产生非希望的共享。
除了CreateFileMapping函数之外,还有两个函数可以操作文件映像对象,分别是OpenFileMapping和Duplicatehandle.

3)创建视图对象
创建视图对象。MapViewOfFile()函数。
示例:两个EXE文件共享内存数据块
发送数据端
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
const
WM_DATA = WM_USER+1024 ; // 自定义消息
type
PShareMem = ^TShareMem;
TShareMem = record
Data:array[0..255] of Char; // 共享数据
end;
TfrmSend = class(TForm)
btn: TButton;
procedure btnClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmSend: TfrmSend;
PShare : PShareMem;
implementation
{$R *.dfm}
var
HMapping:THandle;
HMapMutex:THandle;
const
MAPFILESIZE = 1000;
REQUEST_TIMEOUT=1000;
procedure OpenMap; // 打开建立共享内存
begin
{创建一个映像文件}
HMapping := CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,SizeOf(TShareMem),PChar('MyMap'));
if (HMapping=0) then
begin
ShowMessage('不能创建内存映像文件');
Application.Terminate;
Exit;
end;
{ 将映像文件映射到进程的地址空间 }
PShare := PShareMem(MapViewOfFile(HMapping,FILE_MAP_ALL_ACCESS,0,0,0));
if PShare=nil then
begin
CloseHandle(HMapping);
ShowMessage('Can''t View Memory Map');
Application.Terminate;
Exit;
end;
end;
procedure CloseMap; //关闭共享内存
begin
if PShare<>nil then
begin
UnmapViewOfFile(PShare);
end;
if HMapping<>0 then
begin
CloseHandle(HMapping);
end;
end;
function LockMap:Boolean; //建立互斥对象
begin
Result := True;
{ 创建互斥对象 }
HMapMutex := CreateMutex(nil,False,PChar('My Mutex'));
if HMapMutex=0 then
begin
ShowMessage('不能创建互斥对象');
Result := False;
end
else
begin
if WaitForSingleObject(HMapMutex,REQUEST_TIMEOUT)=WAIT_FAILED then
begin
ShowMessage('不能对互斥对象加锁!');
Result := False;
end;
end;
end;
procedure UnlockMap; //释放互斥对象
begin
ReleaseMutex(HMapMutex);
CloseHandle(HMapMutex);
end;
procedure TfrmSend.btnClick(Sender: TObject);
var
str:PChar;
begin
//
str := PChar('简单的共享内存的例子');
// 把数据拷贝到共享内存
CopyMemory(@(pShare^.Data),str,Length(str));
// 向接收数据端程序(程序标题是MyForm)发消息
PostMessage(FindWindow(nil,'MyForm'),WM_DATA,1,1);
end;
procedure TfrmSend.FormCreate(Sender: TObject);
begin
OpenMap;
LockMap;
end;
procedure TfrmSend.FormDestroy(Sender: TObject);
begin
UnlockMap;
CloseMap;
end;
end.
接收数据端
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;
const
WM_DATA = WM_USER+1024 ; // 自定义消息
type
PShareMem = ^TShareMem;
TShareMem = record
Data:array[0..255] of Char; // 共享数据
end;
type
TfrmRecv = class(TForm)
btnClose: TBitBtn;
memoMessage: TMemo;
procedure btnCloseClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure GetShareInfo(var Msg:TMessage);message WM_DATA;
end;
var
frmRecv: TfrmRecv;
PShare:PShareMem;
MapHandle:THandle;
implementation
{$R *.dfm}
{ TfrmRecv }
procedure TfrmRecv.btnCloseClick(Sender: TObject);
begin
//
CloseHandle(MapHandle);
Close;
end;
procedure TfrmRecv.FormCreate(Sender: TObject);
begin
//
MapHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS,False,PChar('MyMap'));
if MapHandle=0 then
begin
ShowMessage('不能定位内存映像文件块!');
Halt;
end;
PShare := PShareMem(MapViewOfFile(MapHandle,FILE_MAP_ALL_ACCESS,0,0,0));;
if PShare=nil then
begin
CloseHandle(MapHandle);
ShowMessage('Can''View Memory Map');
Application.Terminate;
Exit;
end;
FillChar(PShare^,SizeOf(TShareMem),0);
end;
procedure TfrmRecv.GetShareInfo(var Msg: TMessage);
begin
//
if Msg.LParam=1 then
begin
memoMessage.Lines[0] := PShare^.Data;
end;
end;
end.



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小蚂蚁_CrkRes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值