Windows上CAtlFileMapping共用記憶體的使用以及內部機制

來源:互聯網
上載者:User

標籤:自己的   already   nmap   chunk   turn   protect   標識   sts   選擇   

前言:

使用CEF載入網頁。做JS與C++互動時。須要向主表單發送一些訊息來通知介面做對應的處理。可是,因為CEF使用chrome核心是多進程架構的。渲染引擎與主程式都不在同一個進程裡面。因此。理所當然的就想到了使用共用記憶體了。為了更easy地使用,我們選擇的是ATL裡面封裝的共用記憶體操作類:CAtlFileMapping。

CAtlFileMapping使用:

定義結構體,包括你所須要共用的資料,這裡我們僅僅須要共用主表單的控制代碼

//自己定義進程共用資料結構體struct PROCESS_SHARE_DATA{HWNDhMainWnd;};
使用</span>VS內建GUID產生工具建立一個GUID,來唯一標識這塊共用記憶體</p><p>const TCHAR szShareGuid[] = _T("4F836C8D-F55E-4D88-A0BF-9ACDC0A33B31");定義共用記憶體全域變數
extern CAtlFileMapping<PROCESS_SHARE_DATA> g_ShareData;

初始化這塊共用記憶體,並給資料賦值

g_ShareData.MapSharedMem(sizeof(PROCESS_SHARE_DATA), szShareGuid);((PROCESS_SHARE_DATA*)g_ShareData)->hMainWnd=pMainWnd->GetHWND();
好了。這樣共用記憶體資料已經初始化完畢了。CEF進程在建立後也能夠直接使用這個資料了。

開啟共用記憶體,取出須要的資料
g_ShareData.OpenMapping(szShareGuid, sizeof(PROCESS_SHARE_DATA));HWND hWnd = ((PROCESS_SHARE_DATA*)g_ShareData)->hMainWnd;
然後,把這塊共用記憶體控制代碼關閉

g_ShareData.Unmap();
挺簡單的吧。我們無需知道內部的API調用及實現,就能夠輕鬆在多個進程間共用資料了。

可是。作為程式猿。我們應該知其然知其所以然。

那就進去看看實現吧,反正ATL的代碼都能夠看到。

內部實現:

首先是MapSharedMem,建立一塊共用記憶體,

HRESULT MapSharedMem(</span>

_In_ SIZE_T nMappingSize,_In_z_ LPCTSTR szName,_Out_opt_ BOOL* pbAlreadyExisted = NULL,_In_opt_ LPSECURITY_ATTRIBUTES lpsa = NULL,_In_ DWORD dwMappingProtection = PAGE_READWRITE,_In_ DWORD dwViewDesiredAccess = FILE_MAP_ALL_ACCESS) throw(){ATLASSUME(m_pData == NULL);ATLASSUME(m_hMapping == NULL);ATLASSERT(nMappingSize > 0);ATLASSERT(szName != NULL); // if you just want a regular chunk of memory, use a heap allocatorm_nMappingSize = nMappingSize;ULARGE_INTEGER nSize;nSize.QuadPart = nMappingSize;m_hMapping = ::CreateFileMapping(INVALID_HANDLE_VALUE, lpsa, dwMappingProtection, nSize.HighPart, nSize.LowPart, szName);if (m_hMapping == NULL)return AtlHresultFromLastError();if (pbAlreadyExisted != NULL)*pbAlreadyExisted = (GetLastError() == ERROR_ALREADY_EXISTS);m_dwViewDesiredAccess = dwViewDesiredAccess;m_nOffset.QuadPart = 0;m_pData = ::MapViewOfFileEx(m_hMapping, m_dwViewDesiredAccess, m_nOffset.HighPart, m_nOffset.LowPart, m_nMappingSize, NULL);if (m_pData == NULL){HRESULT hr;hr = AtlHresultFromLastError();::CloseHandle(m_hMapping);m_hMapping = NULL;return hr;}return S_OK;}
通過CreateFileMapping傳入一個INVALID_HANDLE_VALUE建立一個與物理檔案無關的記憶體映射。傳入映射記憶體的大小。

然後調用MapViewOfFileEx將其映射到記憶體中。返回記憶體首地址m_pData,這是一個CAtlFileMappingBase的成員變數。

然後我們查看CAtlFileMapping的定義

template <typename T = char>class CAtlFileMapping : public CAtlFileMappingBase{public:operator T*() const throw(){return reinterpret_cast<T*>(GetData());}};

派生自CAtlFileMappingBase,然後對*進行了重載。使用reinterpret_cast將記憶體映射地址轉換成我們的資料結構的地址,這樣我們就能夠通過CAtlFileMapping指標來直接訪問我們定義的資料結構的資料了。

其它進程使用共用記憶體,再看OpenMapping函數的實現

HRESULT OpenMapping(_In_z_ LPCTSTR szName,_In_ SIZE_T nMappingSize,_In_ ULONGLONG nOffset = 0,_In_ DWORD dwViewDesiredAccess = FILE_MAP_ALL_ACCESS) throw(){ATLASSUME(m_pData == NULL);ATLASSUME(m_hMapping == NULL);ATLASSERT(szName != NULL); // if you just want a regular chunk of memory, use a heap allocatorm_nMappingSize = nMappingSize;m_dwViewDesiredAccess = dwViewDesiredAccess;m_hMapping = ::OpenFileMapping(m_dwViewDesiredAccess, FALSE, szName);if (m_hMapping == NULL)return AtlHresultFromLastError();m_dwViewDesiredAccess = dwViewDesiredAccess;m_nOffset.QuadPart = nOffset;m_pData = ::MapViewOfFileEx(m_hMapping, m_dwViewDesiredAccess, m_nOffset.HighPart, m_nOffset.LowPart, m_nMappingSize, NULL);if (m_pData == NULL){HRESULT hr;hr = AtlHresultFromLastError();::CloseHandle(m_hMapping);m_hMapping = NULL;return hr;}return S_OK;}

由於我們的共用記憶體建立時,使用了一個唯一的GUID標識,通過API OpenFileMapping來找到這個共用記憶體的核心對象,然後MapViewOfFileEx相同的將其映射到當前進程的記憶體空間裡面,這樣我們就能夠訪問共用記憶體裡面的資料了。

使用完畢後。核心對象都要釋放掉。再看Unmap的實現代碼

HRESULT Unmap() throw(){HRESULT hr = S_OK;if (m_pData != NULL){if (!::UnmapViewOfFile(m_pData))hr = AtlHresultFromLastError();m_pData = NULL;}if (m_hMapping != NULL){if (!::CloseHandle(m_hMapping) && SUCCEEDED(hr))hr = AtlHresultFromLastError();m_hMapping = NULL;}return hr;}
首先解除當前進程的記憶體映射,然後關閉映射核心對象的控制代碼。


總結:

使用CreateFileMapping建立一個唯一標識(GUID)的記憶體映射,MapViewOfFileEx將其映射到當前進程的記憶體空間。儲存須要共用的資料到這塊記憶體中去。

其它進程訪問共用記憶體時。OpenFileMapping通過唯一標識(GUID)擷取這塊共用記憶體的核心控制代碼,調用MapViewOfFileEx映射到自己的記憶體空間,然後就能夠讀取裡面的資料了,使用完畢後使用UnmapViewOfFile解除映射。CloseHandle關閉核心物件控點。

儘管使用CAtlFileMapping更加簡單、方便。可是我們還是須要瞭解記憶體映射的機制的。




Windows上CAtlFileMapping共用記憶體的使用以及內部機制

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.