文件映射(Memory-Mapped File,简称内存映射)是一种将磁盘文件的部分或全部内容直接映射到进程虚拟内存地址空间的技术。通过这种方式,进程可以像访问普通内存一样读写文件,无需使用read、write等传统 I/O 函数,大幅简化了文件操作流程,同时也能提升 I/O 效率(尤其适合大文件或频繁读写场景)。
在这里,我们并不是去文件映射,而是利用文件映射,跳过文件而直接使用内存映射,让任何进程都可以访问这个内存。实现共享内存,达到进程通信的目的。
A进程代码(主进程)
一、创建映射的内存
此内存为共享内存,用“名字”标识
"名字" 是唯一的,需要你自己取个名字,要是和其它人重名,那就会打开别人的内存,而不是自己创建的。
Dim hMapFile As HANDLE = CreateFileMapping( _
INVALID_HANDLE_VALUE, _ ' 不关联实际文件(匿名共享内存)
NULL, _ ' 默认安全属性
PAGE_READWRITE, _ ' 可读可写
0, _ ' 高位文件大小(0表示由低位决定)
1060 * 1000, _ ' 共享内存大小(需要多少就创建多少)
"名字") ' 全局命名(跨会话访问需加Global\前缀)
if hMapFile =0 then 创建失败
二、映射共享内存到自己进程
需要把 【共享内存】映射到自己进程,返回内存地址
Dim pBuf As LPVOID = MapViewOfFile( _
hMapFile, _ ' 共享内存对象句柄
FILE_MAP_ALL_ACCESS, _ ' 读写权限
0, 0, 1060 * 1000) ' 映射全部内容
三、读写内存
有内存地址后,你可以用 Peek Poke 读写内存,也可以用指针读写。
四、关闭和释放
用完后,当然需要释放,不然内存泄露。
UnmapViewOfFile(pBuf) ' 解除映射
CloseHandle(hMapFile) ' 关闭共享内存对象
B进程代码(副进程)
副进程可以很多个,不单单是一个。
一、打开共享内存
和 A进程创建的内存,“名字” 一样就可以打开了
Dim hMapFile As HANDLE= OpenFileMapping(FILE_MAP_ALL_ACCESS, False, "名字")
if hMapFile =0 then 打开失败,可能名字错了或没创建
二、映射共享内存到自己进程
这个操作和A进程相同
Dim pBuf As LPVOID = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0)
三、读写内存
有内存地址后,你可以用 Peek Poke 读写内存,也可以用指针读写。
四、关闭和释放
用完后,当然需要释放,不然内存泄露。
UnmapViewOfFile(pBuf) ' 解除映射
CloseHandle(hMapFile) ' 关闭共享内存对象
AB进程同时读写
同时读写,是经常发生的,这个和 多线程读写相同内存一样,也有一个专用的互斥体,来保证同一时刻,只能有一个进程在读写,其它的排队等待。
代码暂时省。。。。可以问AI
越界读写
创建的内存大小是固定的,你要是超过大小,还读写,等待的你的就是软件崩溃。没什么大不了的,重新开软件就好。
封装类
为了简化代码操作,于是封装了一个类,方便使用,封装类进VFB的QQ群里下载,放到VFB的私库文件夹中,即可使用。
已经增加读写锁,不会因为同时读写发生混乱,也增加了边界检查,避免越界发生软件奔溃
安装好私库后,自己代码就简化为
Dim Shared a As 进程通信之内存共享类 = "名字"
默认内存大小为 1024 字节,可以自己定义大小
Dim Shared a As 进程通信之内存共享类 = Type("名字",100)
使用共享内存就这样写
a.tLong(0) = 100
Print a.tLong(0)
当然还有其它类型
Declare Property tLong(位置 As ULong) As Long '返回属性 ,“位置”就是在共享内存中的相对位置,从0开始,单位是字节。
Declare Property tLong(位置 As ULong, 值 As Long) '给属性赋值
Declare Property tULong(位置 As ULong) As ULong '返回属性 ,“位置”就是在共享内存中的相对位置,从0开始,单位是字节。
Declare Property tULong(位置 As ULong, 值 As ULong) '给属性赋值
Declare Property tSingle(位置 As ULong) As Single '返回属性 ,“位置”就是在共享内存中的相对位置,从0开始,单位是字节。
Declare Property tSingle(位置 As ULong, 值 As Single) '给属性赋值
Declare Property tDouble(位置 As ULong) As Double '返回属性 ,“位置”就是在共享内存中的相对位置,从0开始,单位是字节。
Declare Property tDouble(位置 As ULong, 值 As Double) '给属性赋值
Declare Property tLongInt(位置 As ULong) As LongInt '返回属性 ,“位置”就是在共享内存中的相对位置,从0开始,单位是字节。
Declare Property tLongInt(位置 As ULong, 值 As LongInt) '给属性赋值
Declare Property tULongInt(位置 As ULong) As ULongInt '返回属性 ,“位置”就是在共享内存中的相对位置,从0开始,单位是字节。
Declare Property tULongInt(位置 As ULong, 值 As ULongInt) '给属性赋值
Declare Property tString(位置 As ULong) As String '返回属性,超过“尺寸”字符会被截断,遇到0也截断,不支持带0 的字符,自己控制字符长度,避免覆盖后面数据
Declare Property tString(位置 As ULong, 值 As String) '给属性赋值
Declare Property tWString(位置 As ULong) As StringW '返回属性,超过“尺寸”字符会被截断,遇到0也截断,不支持带0 的字符,自己控制字符长度(1字符占2字节),避免覆盖后面数据
Declare Property tWString(位置 As ULong, 值 As Wstring) '给属性赋值
这个位置,就是字节为单位,比方 long 类型占4个字节,你要使用 2个 Long 那么
a.tLong(0) = 100 ‘第1个
a.tLong(4) = 100 ‘第2个
因此,共享内存中需要保存什么数据,需要自己计算好位置进行读写。
评论一下?