Advanced MFC Programming

Advanced MFC Programming Advanced MFC Programming

math.hcmuns.edu.vn
from math.hcmuns.edu.vn More from this publisher
11.04.2014 Views

Chapter 13. Adding Special Features to Application The file or memory used for this purpose is called File Mapping Object and must be created using special function. After it is created successfully, each process can open a view of the file or memory, which will be mapped to the address space of the calling process. File Mapping Functions There are three functions that can be used to implement file or memory mapping: HANDLE ::CreateFileMapping ( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCTSTR lpName ); HANDLE ::OpenFileMapping ( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName ); LPVOID ::MapViewOfFile ( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, DWORD dwNumberOfBytesToMap ); File mapping object can be initiated by calling function ::CreateFileMapping(…). If we want to share a file, we need to pass the file handle to the first parameter (hFile) of this function. If we want to share a block of memory, we need to pass 0xFFFFFFFF to this parameter. The fourth and fifth parameters specify the size of the object. For file sharing, they can be set to zero, in which case the whole file will be shared. In the case of memory sharing, they must be greater than zero. Parameter lpFileMappingAttributes can be used to specify the security attributes of the object, in most cases we can assign zero to it and use the default attributes. Parameter flprotect specifies read and write permission. The most important parameter is the last one, which must be the address of buffers that contain a name assigned to the file mapping object. If any other process wants to access this object, it must also use the same name to create a view of the file mapping object. After the file mapping object is created successfully, the owner (the process that created the object) can create a view of file to map the buffers to its own address space by calling function ::MapViewOfFile(…). When doing this, we must pass the handle returned by function ::CreateFileMapping(…) to parameter hFileMappingObject. If we pass 0 to parameters dwFileOffsetHigh, dwFileOffsetLow and dwNumberOfBytesToMap, the whole file or memory will be mapped. Finally, parameter dwDesiredAccess allows us to specify desired access right. This function will return a void type pointer, which could be cast to any type of pointer. If any other process wants to access the file mapping object, it must call functions ::OpenFileMapping(…) and ::MapViewOfFile(…) to first access it then create a view of file. When calling function ::OpenFileMapping(…), it must pass the object name (specified by function ::CreateFileMapping(…) when the file mapping object was created) to parameter lpName. The buffers can be mapped to the address space of the process by calling function ::MapViewOffile(…), which is exactly the same with creating view of file for the owner of the object. Samples Samples 13.12\Send and 13.12\MsgRcv demonstrate how to share a block of memory between two applications. They are based on samples 13.8\Send and 13.8\MsgRcv respectively. First, the “Sender” application is modified so that its edit box will allow multiple line text input (When inputting the text, CTRL+RETURN key stroke can be used to start a new line), and the original variable CSenderDlg::m_nSent is replaced by CSenderDlg::m_szText, which is a CString type variable. The file mapping object is created in function CSenderDlg::OnInitDialog() as follows: BOOL CSenderDlg::OnInitDialog() { g_uMsgSendStr=::RegisterWindowMessage(MSG_SENDSTRING); g_uMsgReceived=::RegisterWindowMessage(MSG_RECEIVED); 424

Chapter 13. Adding Special Features to Application …… } m_hMapFile=::CreateFileMapping ( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, BUFFER_SIZE, MAPPING_PROJECT ); Here, BUFFER_SIZE is a macro defined as an integer in header file “Common.h”. Also, MAPPING_PROJECT is a macro defined as a string. They will be used by both “Sender” and “MsgRcv”. In message handler CSenderDlg::OnButtonSend(), before the message is sent out, we obtain the text from the edit box, create a view of file and put the text into the buffers. Then message MSG_SENDSTRING is sent to “MsgRcv”: void CSenderDlg::OnButtonSend() { CWnd *pWnd; LPSTR lpMapAddress; UpdateData(TRUE); lpMapAddress=(LPSTR)MapViewOfFile ( m_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); } if(lpMapAddress != NULL) { memcpy(lpMapAddress, m_szText, max(m_szText.GetLength(), BUFFER_SIZE)); } pWnd=CWnd::FindWindow(CLASS_NAME_RECIEVER, NULL); if(pWnd != NULL && ::IsWindow(pWnd->m_hWnd)) { pWnd->PostMessage(g_uMsgSendStr, (WPARAM)GetSafeHwnd(), (LPARAM)NULL); } In project “MsgRcv”, the client window is implemented using edit view instead of original list view, this makes it easier for us to display text. After receiving the message, we open the file mapping object, create a view of file, then retrieve text from the buffers. Then we access the edit view, select all the text contained in the view, and replace the selected text with the newly obtained text. Finally, the acknowledge message is sent back: LONG CMainFrame::OnSendStr(UINT wParam, LONG lParam) { CWnd *pWnd; CString szText; HANDLE hMapFile; LPSTR lpMapAddress; pWnd=CWnd::FromHandle((HWND)wParam); ASSERT(pWnd != NULL); pWnd->PostMessage(g_uMsgReceived); hMapFile=::OpenFileMapping ( FILE_MAP_ALL_ACCESS, FALSE, 425

Chapter 13. Adding Special Features to Application<br />

……<br />

}<br />

m_hMapFile=::CreateFileMapping<br />

(<br />

(HANDLE)0xFFFFFFFF,<br />

NULL,<br />

PAGE_READWRITE,<br />

0,<br />

BUFFER_SIZE,<br />

MAPPING_PROJECT<br />

);<br />

Here, BUFFER_SIZE is a macro defined as an integer in header file “Common.h”. Also,<br />

MAPPING_PROJECT is a macro defined as a string. They will be used by both “Sender” and “MsgRcv”. In<br />

message handler CSenderDlg::OnButtonSend(), before the message is sent out, we obtain the text from the<br />

edit box, create a view of file and put the text into the buffers. Then message MSG_SENDSTRING is sent to<br />

“MsgRcv”:<br />

void CSenderDlg::OnButtonSend()<br />

{<br />

CWnd *pWnd;<br />

LPSTR lpMapAddress;<br />

UpdateData(TRUE);<br />

lpMapAddress=(LPSTR)MapViewOfFile<br />

(<br />

m_hMapFile,<br />

FILE_MAP_ALL_ACCESS,<br />

0,<br />

0,<br />

0<br />

);<br />

}<br />

if(lpMapAddress != NULL)<br />

{<br />

memcpy(lpMapAddress, m_szText, max(m_szText.GetLength(), BUFFER_SIZE));<br />

}<br />

pWnd=CWnd::FindWindow(CLASS_NAME_RECIEVER, NULL);<br />

if(pWnd != NULL && ::IsWindow(pWnd->m_hWnd))<br />

{<br />

pWnd->PostMessage(g_uMsgSendStr, (WPARAM)GetSafeHwnd(), (LPARAM)NULL);<br />

}<br />

In project “MsgRcv”, the client window is implemented using edit view instead of original list view,<br />

this makes it easier for us to display text. After receiving the message, we open the file mapping object,<br />

create a view of file, then retrieve text from the buffers. Then we access the edit view, select all the text<br />

contained in the view, and replace the selected text with the newly obtained text. Finally, the acknowledge<br />

message is sent back:<br />

LONG CMainFrame::OnSendStr(UINT wParam, LONG lParam)<br />

{<br />

CWnd *pWnd;<br />

CString szText;<br />

HANDLE hMapFile;<br />

LPSTR lpMapAddress;<br />

pWnd=CWnd::FromHandle((HWND)wParam);<br />

ASSERT(pWnd != NULL);<br />

pWnd->PostMessage(g_uMsgReceived);<br />

hMapFile=::OpenFileMapping<br />

(<br />

FILE_MAP_ALL_ACCESS,<br />

FALSE,<br />

425

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!