内存映射文件
内存映射文件的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()
// 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 文件映射对象名称,可以用来在不同进程间共享
);
3 把文件映射对象的数据映射到进程地址空间
LPVOID
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;
}