在测试文件映射的创建和打开时,经常出现“句柄无效”错误。 仔细查看MSDN后,我发现函数无法识别。 在这里翻译相关的说明
手动创建文件映射(
HANDLE hFile,//物理文件句柄
LP security _ attributeslpattributes,//安全设置
DWORD flProtect,//保护设置
DWORD dwMaximumSizeHigh,//顶级文件大小
DWORD dwMaximumSizeLow,//子文件大小
LPCTSTR lpName //共享内存名称
);
1 )物理文件句柄
如果需要创建不依赖于物理文件的存储器映射,则可获得的物理文件句柄可以设置为0xfffffff(invalid_handle_value )。
如果需要与物理文件关联,请确保创建物理文件时的访问模式与“保护设置”匹配。 例如,如果:物理文件是只读的,并且内存映射需要读写,则会发生错误。 建议以独占方式创建物理文件。
如果使用INVALID_HANDLE_VALUE,则还必须设置需要申请的内存空间的大小,无论物理文件句柄的参数是否有效。 这样,无论物理文件的大小如何,CreateFileMapping都可以创建超过实际文件大小的内存空间。 如果物理文件有效,则大小参数为0。 返回的内存空间地址范围与物理文件大小相同。 返回的文件映射的地址空间通过复制、集成或命名获得,初始内容为0。
2 )保护设置
虽然是安全设置,但通常设置为NULL即可,使用默认的安全设置。 如果windows2k需要限制,请考虑限制将内存文件映射用于在整个网络上共享的APP应用程序进程。
3 )上级文件大小
树叶们,我想现在我们的机器是32位的东边。 32位进程不能得到可寻址的专用32位地址空间。 一般设定为0吧。 我不打算把那个设定为超过0的状况。
4 )下级文件大小
这个还可以设置,但是为了让其他共享用户知道有关你申请的文件映射的信息,我在获取的地址空间的开头添加了结构化描述信息,记录了内存映射的大小、名称等,实际申请的空间比输入的空间要多我觉得像这样BSTR这样的方式很合理。
5 )共享内存名称
这是我今天测试时撞到墙上的灾难。 为了对内存的互斥访问,我设置了互斥句柄。 您选择了与共享内存相同的名称。 在这之后,由于他们使用了共同的namespace而发生了错误。 呵呵。
7 )调用CreateFileMapping时GetLastError的对应错误
如果尝试创建长度为零的ERROR_FILE_INVALID文件映射,则必须使用此报告
ERROR_INVALID_HANDLE如果发现您的名称内存空间与现有内存映射、互斥量、信号量和临界区域同名,那就麻烦了
ERROR_ALREADY_EXISTS表示内存空间的名称已经存在
8 )相关服务或平台的命名保留
终端服务:
命名时,全局或会话名称空间的主文件映射可以包含" Global "或" Local "前缀。 其他部分可以包含()以外的字符。 请参阅Kernel Object Name Spaces。
Windows 2000 or later:
如果终端服务没有执行“Global”和“Local”前缀的特殊含义,将被忽略
2
在开发软件的过程中,经常会遇到在进程之间共享数据的需求。 例如,a进程生成计算数据,b进程生成显示数据的图形。 这种开发方式可以将一个大程序分成独立的小程序,提高软件的成功率,适合与团队一起开发,加快软件的开发速度。 使用文件映射共享数据吧。 首先,使用函数CreateFileMapping创建要共享的文件数据句柄,然后使用MapViewOfFile获取共享内存地址,然后使用OpenFileMapping函数在其他进程中打开共享文件的名称函数CreateFileMapping、MapViewOfFile声明如下: winbaseapi _ _ outhandlewinapicreatefilemappinga (_ _ inhandlehfile,__in_ )。
__in DWORD dwMaximumSizeHigh, __in DWORD dwMaximumSizeLow, __in_opt LPCSTR lpName ); WINBASEAPI __out HANDLE WINAPI CreateFileMappingW( __in HANDLE hFile, __in_opt LPSECURITY_ATTRIBUTES lpFileMappingAttributes, __in DWORD flProtect, __in DWORD dwMaximumSizeHigh, __in DWORD dwMaximumSizeLow, __in_opt LPCWSTR lpName ); #ifdef UNICODE #define CreateFileMapping CreateFileMappingW #else #define CreateFileMapping CreateFileMappingA #endif // !UNICODE WINBASEAPI __out LPVOID WINAPI MapViewOfFile( __in HANDLE hFileMappingObject, __in DWORD dwDesiredAccess, __in DWORD dwFileOffsetHigh, __in DWORD dwFileOffsetLow, __in SIZE_T dwNumberOfBytesToMap ); hFile 是创建共享文件的句柄。 lpFileMappingAttributes 是文件共享的属性。 flProtect 是当文件映射时读写文件的属性。 dwMaximumSizeHigh 是文件共享的大小高位字节。 dwMaximumSizeLow 是文件共享的大小低位字节。 lpName 是共享文件对象名称。 hFileMappingObject 是共享文件对象。 dwDesiredAccess 是文件共享属性。 dwFileOffsetHigh 是文件共享区的偏移地址。 dwFileOffsetLow 是文件共享区的偏移地址。 dwNumberOfBytesToMap 是共享数据长度。 调用函数的例子如下: #001 // 文件共享。 #002 // 蔡军生 2007/10/27 QQ:9073204 深圳 #003 void FileMapping(void) #004 { #005 // 打开共享的文件对象。 #006 m_hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, #007 FALSE,_T("TestFileMap")); #008 if (m_hMapFile) #009 { #010 // 显示共享的文件数据。 #011 LPTSTR lpMapAddr = (LPTSTR)MapViewOfFile(m_hMapFile,FILE_MAP_ALL_ACCESS, #012 0,0,0); #013 OutputDebugString(lpMapAddr); #014 } #015 else #016 { #017 // 创建共享文件。 #018 m_hMapFile = CreateFileMapping( (HANDLE)0xFFFFFFFF,NULL, #019 PAGE_READWRITE,0,1024,_T("TestFileMap")); #020 #021 // 拷贝数据到共享文件里。 #022 LPTSTR lpMapAddr = (LPTSTR)MapViewOfFile(m_hMapFile,FILE_MAP_ALL_ACCESS, #023 0,0,0); #024 std::wstring strTest(_T("TestFileMap")); #025 wcscpy(lpMapAddr,strTest.c_str()); #026 #027 FlushViewOfFile(lpMapAddr,strTest.length()+1); #028 } #029 }
3
内存映射API函数CreateFileMapping创建一个有名的共享内存:
HANDLE CreateFileMapping(
HANDLE hFile, // 映射文件的句柄,
//设为0xFFFFFFFF以创建一个进程间共享的对象
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 安全属性
DWORD flProtect, // 保护方式
DWORD dwMaximumSizeHigh, //对象的大小
DWORD dwMaximumSizeLow,
LPCTSTR lpName // 必须为映射文件命名
);
与虚拟内存类似,保护方式可以是PAGE_READONLY或是PAGE_READWRITE。如果多进程都对同一共享内存进行写访问,则必须保持相互间同步。映射文件还可以指定PAGE_WRITECOPY标志,可以保证其原始数据不会遭到破坏,同时允许其他进程在必要时自由的操作数据的拷贝。
在创建文件映射对象后使用可以调用MapViewOfFile函数映射到本进程的地址空间内。
下面说明创建一个名为MySharedMem的长度为4096字节的有名映射文件:
HANDLE hMySharedMapFile=CreateFileMapping((HANDLE)0xFFFFFFFF),
NULL,PAGE_READWRITE,0,0x1000,"MySharedMem");
并映射缓存区视图:
LPSTR pszMySharedMapView=(LPSTR)MapViewOfFile(hMySharedMapFile,
FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);
其他进程访问共享对象,需要获得对象名并调用OpenFileMapping函数。
HANDLE hMySharedMapFile=OpenFileMapping(FILE_MAP_WRITE,
FALSE,"MySharedMem");
一旦其他进程获得映射对象的句柄,可以象创建进程那样调用MapViewOfFile函数来映射对象视图。用户可以使用该对象视图来进行数据读写操作,以达到数据通讯的目的。
当用户进程结束使用共享内存后,调用UnmapViewOfFile函数以取消其地址空间内的视图:
if (!UnmapViewOfFile(pszMySharedMapView))
{
AfxMessageBox("could not unmap view of file");
}