轉載:https://www.cnblogs.com/hrhguanli/p/4007100.html
1. 用途和基本操作
用於不同進程之間的內存共享操作, 能夠將一個物理文件映射到內存其中然后直接利用分配到的或者打開的命名共享內存的地址空間實現資源共享訪問
2. 相關流程
1) 新建命名共享內存
首先利用CreateFile或者CreateFileForMapping獲得一個用於映射的物理文件句柄, 然后利用該文件句柄結合CreateFileMapping得到一個命名的共享內存映射文件句柄。
//CreateFileMapping 為指定文件創建一個有名或無名的文件映象; HANDLE CreateFileMapping( HANDLE hFile, // 映射文件的句柄 LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 安全描寫敘述符指針 DWORD flProtect, // 對映射對象的保護 DWORD dwMaximumSizeHigh, // 對象最大長度的高32位 DWORD dwMaximumSizeLow, // 對象最大長度的低32位 LPCTSTR lpName // 文件內存映射對象的名字 );
注意:
hFile:映射文件的句柄,文件的打開模式必須與flProtect參數指定的相一致;假設這個參數值為0xFFFFFFFF,那么必須在dwMaximumSizeHigh和dwMaximumSizeLow參數中指定映射對象的大小。而且將在操作系統虛擬內存頁面替換文件里創建文件映射對象,而不是使用磁盤文件,同一時候必須給出這個映射對象的大小。文件映射對象通過副本,遺傳或名字來共享。
lpFileMappingAttributes:安全描寫敘述符指針,決定返回句柄能否被子進程繼承,假設是NULL,那么子進程不能繼承。WinNt中,假設是NULL,那么文件映射對象得到一個默認的安全描寫敘述符。
flProtect:為得到的文件試圖指定保護模式,能夠被設置為下列值:
PAGE_READONLY :僅僅讀屬性,而且hFile相應的文件必須以GENERIC_READ形式打開。
PAGE_READWRITE:可讀可寫屬性,而且hFile相應的文件必須以GENERIC_READ 和 GENERIC_WRITE形式打開。
PAGE_WRITECOPY:對可寫區域復制后操作,而且hFile相應的文件必須以GENERIC_READ 和 GENERIC_WRITE形式打開。
dwMaximumSizeHigh,dwMaximumSizeLow:假設這兩個參數為0,則文件映射對象的最大長度等於hFile指定的文件長度。
lpName:文件映射對象的名字,假設這個名字已存在,則依照flProtect指定的來處理映射對象。假設此參數為空,則創建一個無名字的文件映射對象。假設此參數的名字與系統事件的名字同樣,則函數運行失敗,GetLastError返回 ERROR_INVALID_HANDLE;
返回值:函數調用成功返回文件映射對象的句柄,假設文件映射對象已經存在則返回原有映射對象的句柄,GetLastError返回ERROR_ALREADY_EXISTS。函數運行失敗返回Null。
2) 打開命名共享內存
假設須要共享已經存在的命名共享內存映射文件, 使用OpenFileMapping函數。
//OpenFileMapping 打開一個已命名的文件映射對象
HANDLE OpenFileMapping( DWORD dwDesiredAccess, // 訪問模式 BOOL bInheritHandle, // 繼承標志 LPCTSTR lpName // 文件映射對象名指針 );
注意:
dwDesiredAccess:訪問模式與MapViewOfFile中的訪問模式同樣。
bInheritHandle:繼承標志,能否夠被一個新的進程繼承使用,假設為TRUE,就能夠被一個新進程繼承句柄。
返回值:
成功返回一個已命名的文件映射對象,失敗返回NULL。
3) 獲得地址空間指針
進行內存映射文件的讀寫和一般的文件讀寫不同, 是直接面對你申請的地址空間, 為此須要使用MapViewOfFile得到相關的地址LPVOID類型的指針。假設須要進行文件寫入, 能夠通過類型轉換直接對於內存地址進行賦值, 比方:
memcpy( lpAddress, lpBuf, ....)
這里自然須要防止內存溢出的情況。
假設是讀取操作,將參數順序調整一下就能夠了。
MapViewOfFile 在調用進程的地址空間映射一個文件視圖 LPVOID MapViewOfFile( HANDLE hFileMappingObject, // 已創建的文件映射對象句柄 DWORD dwDesiredAccess, // 訪問模式 DWORD dwFileOffsetHigh, // 文件偏移的高32位 DWORD dwFileOffsetLow, // 文件偏移的低32位 DWORD dwNumberOfBytesToMap // 映射視圖的大小 );
注意:
hFileMappingObject: 由CreateFileMapping 或 OpenFileMapping 返回的文件映射對象句柄。
dwDesiredAccess:映射視圖的訪問模式,與創建文件映射對象的保護模式flProtect有關,能夠被設置為下列值:
FILE_MAP_WRITE:一個可讀寫屬性的文件視圖被創建,保護模式為PAGE_READWRITE
FILE_MAP_READ :一個僅僅讀屬性的文件視圖被創建,保護模式為PAGE_READWRITE 或 PAGE_READONLY
FILE_MAP_ALL_ACCESS:與FILE_MAP_WRITE模式同樣
FILE_MAP_COPY:保護模式為PAGE_WRITECOPY時,得到一個視圖文件,當你對視圖文件寫操作時,頁面自己主動交換,而且你所做的改動不會損壞原始數據資料。
dwNumberOfBytesToMap:映射文件部分的大小,假設為0,則映射整個文件。
返回值:
假設成功返回返回映射視圖的起始地址,假設失敗返回NULL。
4)MapViewOfFileEx 在調用進程的地址空間映射一個文件視圖,而且同意調用進程為映射視圖指定特殊的內存地址
LPVOID MapViewOfFileEx( HANDLE hFileMappingObject, // 文件映射對象的句柄 DWORD dwDesiredAccess, // 訪問模式 DWORD dwFileOffsetHigh, // 文件偏移的高32位 DWORD dwFileOffsetLow, // 文件偏移的低32位 DWORD dwNumberOfBytesToMap, // 映射視圖的大小 LPVOID lpBaseAddress // 指定映射視圖的事實上內存地址 );
注意:
與MapViewOfFile使用方法同樣,可是假設指定的內存地址空間大小不夠,則函數運行失敗。
5) 將內存拷貝到所映射的物理文件上面
FlushMapViewOfFile函數能夠將內存里面的內容DUMP到物理磁盤上面
FlushViewOfFile 把文件映射視圖中的改動的內容或所有寫回到磁盤文件里
BOOL FlushViewOfFile( LPCVOID lpBaseAddress, // 改動內容的起始地址 DWORD dwNumberOfBytesToFlush // 改動的字節數目 );
函數運行成功返回非零。
6) 卸載內存映射文件地址指針
UnmapViewOffFile函數就是卸載
UnmapViewOfFile 刪除文件的映射視圖
BOOL UnmapViewOfFile( LPCVOID lpBaseAddress // 映射視圖起始地址 );
注意:
lpBaseAddress:映射視圖起始地址,由 MapViewOfFile 函數 MapViewOfFileEx產生。
返回值:
假設調用成功返回非零,而且全部指定地址內的臟頁面會被寫入硬盤。調用失敗返回零。
7) 關閉內存映射文件
太簡單了, CloseHandle搞定