內(nèi)存映射API函數(shù)CreateFileMapping創(chuàng)建一個有名的共享內(nèi)存:
HANDLE CreateFileMapping(
HANDLE hFile, // 映射文件的句柄,
//設(shè)為0xFFFFFFFF以創(chuàng)建一個進(jìn)程間共享的對象
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 安全屬性
DWORD flProtect, // 保護(hù)方式
DWORD dwMaximumSizeHigh, //對象的大小
DWORD dwMaximumSizeLow,
LPCTSTR lpName // 必須為映射文件命名
);
與虛擬內(nèi)存類似,保護(hù)方式可以是PAGE_READONLY或是PAGE_READWRITE。如果多進(jìn)程都對同一共享內(nèi)存進(jìn)行寫訪問,則必須保持相互間同步。映射文件還可以指定PAGE_WRITECOPY標(biāo)志,可以保證其原始數(shù)據(jù)不會遭到破壞,同時允許其他進(jìn)程在必要時自由的操作數(shù)據(jù)的拷貝。
在創(chuàng)建文件映射對象后使用可以調(diào)用MapViewOfFile函數(shù)映射到本進(jìn)程的地址空間內(nèi)。
下面說明創(chuàng)建一個名為MySharedMem的長度為4096字節(jié)的有名映射文件:
HANDLE hMySharedMapFile=CreateFileMapping((HANDLE)0xFFFFFFFF),
NULL,PAGE_READWRITE,0,0x1000,"MySharedMem");
并映射緩存區(qū)視圖:
LPSTR pszMySharedMapView=(LPSTR)MapViewOfFile(hMySharedMapFile,
FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);
其他進(jìn)程訪問共享對象,需要獲得對象名并調(diào)用OpenFileMapping函數(shù)。
HANDLE hMySharedMapFile=OpenFileMapping(FILE_MAP_WRITE,
FALSE,"MySharedMem");
一旦其他進(jìn)程獲得映射對象的句柄,可以象創(chuàng)建進(jìn)程那樣調(diào)用MapViewOfFile函數(shù)來映射對象視圖。用戶可以使用該對象視圖來進(jìn)行數(shù)據(jù)讀寫操作,以達(dá)到數(shù)據(jù)通訊的目的。
當(dāng)用戶進(jìn)程結(jié)束使用共享內(nèi)存后,調(diào)用UnmapViewOfFile函數(shù)以取消其地址空間內(nèi)的視圖:
if (!UnmapViewOfFile(pszMySharedMapView))
{
AfxMessageBox("could not unmap view of file");
}
//=================================================================================
//
CreateFileMapping的MSDN翻譯和使用心得//=================================================================================
測試創(chuàng)建和打開文件映射的時候老是得到"句柄無效"的錯誤, 仔細(xì)看了MSDN以后才發(fā)覺是函數(shù)認(rèn)識不透, 這里把相關(guān)的解釋翻譯出來
HANDLE CreateFileMapping(
HANDLE hFile, //物理文件句柄
LPSECURITY_ATTRIBUTES lpAttributes, //安全設(shè)置
DWORD flProtect, //保護(hù)設(shè)置
DWORD dwMaximumSizeHigh, //高位文件大小
DWORD dwMaximumSizeLow, //低位文件大小
LPCTSTR lpName //共享內(nèi)存名稱
);
1) 物理文件句柄
任何可以獲得的物理文件句柄, 如果你需要創(chuàng)建一個物理文件無關(guān)的內(nèi)存映射也無妨, 將它設(shè)置成為 0xFFFFFFFF(INVALID_HANDLE_VALUE)就可以了.
如果需要和物理文件關(guān)聯(lián), 要確保你的物理文件創(chuàng)建的時候的訪問模式和"保護(hù)設(shè)置"匹配, 比如: 物理文件只讀, 內(nèi)存映射需要讀寫就會發(fā)生錯誤. 推薦你的物理文件使用獨占方式創(chuàng)建.
如果使用 INVALID_HANDLE_VALUE, 也需要設(shè)置需要申請的內(nèi)存空間的大小, 無論物理文件句柄參數(shù)是否有效, 這樣 CreateFileMapping 就可以創(chuàng)建一個和物理文件大小無關(guān)的內(nèi)存空間給你, 甚至超過實際文件大小, 如果你的物理文件有效, 而大小參數(shù)為0, 則返回給你的是一個和物理文件大小一樣的內(nèi)存空間地址范圍. 返回給你的文件映射地址空間是可以通過復(fù)制, 集成或者命名得到, 初始內(nèi)容為0.
2) 保護(hù)設(shè)置
就是安全設(shè)置, 不過一般設(shè)置NULL就可以了, 使用默認(rèn)的安全配置. 在win2k下如果需要進(jìn)行限制, 這是針對那些將內(nèi)存文件映射共享給整個網(wǎng)絡(luò)上面的應(yīng)用進(jìn)程使用是, 可以考慮進(jìn)行限制.
3) 高位文件大小
弟兄們, 我想目前我們的機(jī)器都是32位的東東, 不可能得到超過32位進(jìn)程所能尋址的私有32位地址空間, 一般還是設(shè)置0吧, 我沒有也不想嘗試將它設(shè)置超過0的情況.
4) 低位文件大小
這個還是可以進(jìn)行設(shè)置的, 不過為了讓其他共享用戶知道你申請的文件映射的相關(guān)信息, 我使用的時候是在獲得的地址空間頭部添加一個結(jié)構(gòu)化描述信息, 記錄內(nèi)存映射的大小, 名稱等, 這樣實際申請的空間就比輸入的增加了一個頭信息結(jié)構(gòu)大小了, 我認(rèn)為這樣類似BSTR的方式應(yīng)該是比較合理的.
5) 共享內(nèi)存名稱
這個就是我今天測試的時候碰壁的禍根, 因為為了對于內(nèi)存進(jìn)行互斥訪問, 我設(shè)置了一個互斥句柄, 而名稱我選擇和命名共享內(nèi)存同名, 之下就是因為他們使用共同的namespace導(dǎo)致了錯誤, 呵呵.
7) 調(diào)用CreateFileMapping的時候GetLastError的對應(yīng)錯誤
ERROR_FILE_INVALID 如果企圖創(chuàng)建一個零長度的文件映射, 應(yīng)有此報
ERROR_INVALID_HANDLE 如果發(fā)現(xiàn)你的命名內(nèi)存空間和現(xiàn)有的內(nèi)存映射, 互斥量, 信號量, 臨界區(qū)同名就麻煩了
ERROR_ALREADY_EXISTS 表示內(nèi)存空間命名已經(jīng)存在
8) 相關(guān)服務(wù)或者平臺的命名保留
Terminal Services:
命名可以包含 "Global" 或者 "Local" 前綴在全局或者會話名空間初級文件映射. 其他部分可以包含任何除了()以外的字符, 可以參考 Kernel Object Name Spaces.
Windows 2000 or later:
如果 Terminal Services 沒有運行 "Global" 和 "Local" 前綴的特殊含義就被忽略了