内存映射文件
内存映射文件的3种用途:
1 载入.exe 或者DLL
2 用内存映射文件来访问磁盘上的文件
3 进程间通信
1 执行程序.exe 一般载入的基地址是0X00400000,而DLL一般载入的基地址是0X10000000.
2 同一个执行程序或者DLL的多个实例,不会共享静态数据。
3 .exe 和DLL 使用的内存页面属性是写时复制。
怎么在同一个执行程序或者DLL的不同实例,来共享静态数据呢?
比如想知道,同一个程序,运行了多个实例!
使用EXE文件结构的段信息。
“Shared” 表示共享段 多个实例都共享
#pragma data_seg("Shared")
volatile LONG g_lApplicationInstances = 0;
#pragma data_seg()
volatile LONG g_lApplicationInstances = 0;
#pragma data_seg()
// Tell the linker to make the Shared section readable, writable, and shared.
#pragma comment(linker, "/Section:Shared,RWS")
/****************************************************************************** Module: AppInst.cpp Notices: Copyright (c) 2008 Jeffrey Richter & Christophe Nasarre ******************************************************************************/ #include "..\CommonFiles\CmnHdr.h" /* See Appendix A. */ #include <windowsx.h> #include <tchar.h> #include "Resource.h" /////////////////////////////////////////////////////////////////////////////// // The system-wide window message, unique to the application UINT g_uMsgAppInstCountUpdate = WM_APP+123; /////////////////////////////////////////////////////////////////////////////// // Tell the compiler to put this initialized variable in its own Shared // section so it is shared by all instances of this application. #pragma data_seg("Shared") volatile LONG g_lApplicationInstances = 0; #pragma data_seg() // Tell the linker to make the Shared section readable, writable, and shared. #pragma comment(linker, "/Section:Shared,RWS") /////////////////////////////////////////////////////////////////////////////// BOOL Dlg_OnInitDialog(HWND hWnd, HWND hWndFocus, LPARAM lParam) { chSETDLGICONS(hWnd, IDI_APPINST); // Force the static control to be initialized correctly. PostMessage(HWND_BROADCAST, g_uMsgAppInstCountUpdate, 0, 0); return(TRUE); } /////////////////////////////////////////////////////////////////////////////// void Dlg_OnCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify) { switch (id) { case IDCANCEL: EndDialog(hWnd, id); break; } } /////////////////////////////////////////////////////////////////////////////// INT_PTR WINAPI Dlg_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == g_uMsgAppInstCountUpdate) { SetDlgItemInt(hWnd, IDC_COUNT, g_lApplicationInstances, FALSE); } switch (uMsg) { chHANDLE_DLGMSG(hWnd, WM_INITDIALOG, Dlg_OnInitDialog); chHANDLE_DLGMSG(hWnd, WM_COMMAND, Dlg_OnCommand); } return(FALSE); } /////////////////////////////////////////////////////////////////////////////// int WINAPI _tWinMain(HINSTANCE hInstExe, HINSTANCE, PTSTR, int) { // Get the numeric value of the systemwide window message used to notify // all top-level windows when the module's usage count has changed. g_uMsgAppInstCountUpdate = RegisterWindowMessage(TEXT("MsgAppInstCountUpdate")); // There is another instance of this application running InterlockedExchangeAdd(&g_lApplicationInstances, 1); DialogBox(hInstExe, MAKEINTRESOURCE(IDD_APPINST), NULL, Dlg_Proc); // This instance of the application is terminating InterlockedExchangeAdd(&g_lApplicationInstances, -1); // Have all other instances update their display PostMessage(HWND_BROADCAST, g_uMsgAppInstCountUpdate, 0, 0); return(0); } //////////////////////////////// End of File //////////////////////////////////
2 映射到内存的数据文件
使用内存映射文件
1 创建或者打开文件内核对象
CreateFile 创建或者打开一个文件,函数详情见MSDN
2 创建一个文件映射内存对象
HANDLE
WINAPI
CreateFileMappingA(
__in HANDLE hFile, 创建的文件内核对象
__in_opt LPSECURITY_ATTRIBUTES lpFileMappingAttributes, 安全属性一般为NULL
__in DWORD flProtect, 保护属性 下图
__in DWORD dwMaximumSizeHigh, 文件大小高字节,文件大于4G,才需要用到
__in DWORD dwMaximumSizeLow, 文件大小低字节,相当于文件大小,如果这个2个参数都为0,使用文件内核对象的文件大小
__in_opt LPCSTR lpName 文件映射对象名称,可以用来在不同进程间共享
);
WINAPI
CreateFileMappingA(
__in HANDLE hFile, 创建的文件内核对象
__in_opt LPSECURITY_ATTRIBUTES lpFileMappingAttributes, 安全属性一般为NULL
__in DWORD flProtect, 保护属性 下图
__in DWORD dwMaximumSizeHigh, 文件大小高字节,文件大于4G,才需要用到
__in DWORD dwMaximumSizeLow, 文件大小低字节,相当于文件大小,如果这个2个参数都为0,使用文件内核对象的文件大小
__in_opt LPCSTR lpName 文件映射对象名称,可以用来在不同进程间共享
);
3 把文件映射对象的数据映射到进程地址空间
LPVOID
WINAPI
MapViewOfFile(
__in HANDLE hFileMappingObject, // 文件映射内核对象
__in DWORD dwDesiredAccess, 访问权限
__in DWORD dwFileOffsetHigh, 文件偏移量高字节
__in DWORD dwFileOffsetLow, 低字节,必须是64KB整数倍
__in SIZE_T dwNumberOfBytesToMap 需要映射的字节大小
);
WINAPI
MapViewOfFile(
__in HANDLE hFileMappingObject, // 文件映射内核对象
__in DWORD dwDesiredAccess, 访问权限
__in DWORD dwFileOffsetHigh, 文件偏移量高字节
__in DWORD dwFileOffsetLow, 低字节,必须是64KB整数倍
__in SIZE_T dwNumberOfBytesToMap 需要映射的字节大小
);
MapVieOfFileEx 可以用于内存映射文件是链表的情况。
用完内存映射对象后,必须清理释放。
1 取消进程地址空间到文件映射对象的关联
BOOL UnmapViewOfFile(PLVOID pvBaseAddress);
参数是调用MapViewOfFile返回的地址。
2 关闭文件映射内核对象
CloseHandle
3 关闭文件内核对象
CloseHandle
示例代码:
// MemoryMapFile.cpp : Defines the entry point for the console application. // #include <Windows.h> #include <process.h> #include <tchar.h> int _tmain(int argc, _TCHAR* argv[]) { int len = sizeof(TCHAR); HANDLE hFile = CreateFile(TEXT("1.txt"),GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); DWORD dwSize = GetFileSize(hFile,NULL); //创建文件映射内存 HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE,0,dwSize + 1,NULL); //创建映射视图 LPSTR lpstr = (LPSTR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0,/*文件指针偏移量*/ 0, 0 /*Use fileSize*/); lpstr[dwSize] = 0; _strrev(lpstr); //刷新视图 FlushViewOfFile(lpstr, 10); //断开视图映射 UnmapViewOfFile(lpstr); CloseHandle(hMapFile); SetFilePointer(hFile,dwSize,NULL,FILE_BEGIN); SetEndOfFile(hFile); CloseHandle(hFile); return 0; }
用内存映射文件在进程中共享数据
以页交换文件为存储器的内存映射文件
在调用CreateFileMapping时,第一个参数传 INVALID_HANDLE_VALUE就可以了,大小是参数4,参数5.
// MemoryMapFile.cpp : Defines the entry point for the console application. // #include <Windows.h> #include <process.h> #include <tchar.h> #include <stdio.h> int _tmain(int argc, _TCHAR* argv[]) { const DWORD dwSize = 4 * 1024; //创建文件映射内存 HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,0,dwSize,TEXT("111")); if(ERROR_ALREADY_EXISTS == GetLastError()) { printf("exists\n"); hMapFile = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, TEXT("111")); //创建映射视图 PTCHAR lpstr = (PTCHAR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0,/*文件指针偏移量*/ 0, 0 /*Use fileSize*/); printf("%S\n",lpstr); goto leave; } //创建映射视图 PTCHAR lpstr = (PTCHAR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0,/*文件指针偏移量*/ 0, 0 /*Use fileSize*/); _tcscpy(lpstr,TEXT("123456")); //刷新视图 FlushViewOfFile(lpstr, 10); leave: //断开视图映射 UnmapViewOfFile(lpstr); getchar(); CloseHandle(hMapFile); return 0; }