
Introduction
With the Application Wizard of the Visual Studio, you can create an MFC application with just a few mouse clicks. But you also can build your MFC application from scratch. In this article, we build a simple application that displays the contents of a file in hexadecimal values.
Using the code
Any MFC application is represented by a class that inherits from CWinApp. We call our application class CHexApp:
class CHexApp : public CWinApp
{
protected:
virtual BOOL InitInstance();
protected:
DECLARE_MESSAGE_MAP()
};
Most of the functionality necessary to a Windows application is buried inside inherited classes that are provided by MFC. We only need to specify what is specific to our application. Therefore, we override the InitInstance method that is called by the framework.
BOOL CHexApp::InitInstance()
{
CMDIFrameWnd* pFrame = new CMainFrame;
if(pFrame)
{
AddDocTemplate(new CMultiDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CHexDoc),
RUNTIME_CLASS(CChildFrame),
RUNTIME_CLASS(CHexView)));
pFrame->LoadFrame(IDR_MAINFRAME);
pFrame->ShowWindow(m_nCmdShow);
m_pMainWnd = pFrame;
return TRUE;
}
return FALSE;
}
In this method, we create the main window of our application. As we want to display child windows inside it, our main window inherits from the CMDIFrameWnd MFC class:
class CMainFrame : public CMDIFrameWnd
{
DECLARE_DYNAMIC(CMainFrame)
protected:
BOOL LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
CWnd* pParentWnd, CCreateContext* pContext);
BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* );
protected:
afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
DECLARE_MESSAGE_MAP()
};
The classes CHexDoc and CHexView build the heart of our HexView application. They implement the document-view mechanism which is part of most MFC applications. CHexDoc is responsible for reading the contents of a file into memory. This is done inside the Serialize method:
void CHexDoc::Serialize(CArchive& archive)
{
if(!archive.IsStoring())
{
CFile* pFile = archive.GetFile();
if(pFile)
{
m_dwLength = pFile->GetLength();
m_pData = new BYTE[m_dwLength];
if(m_pData)
{
m_dwLength = pFile->Read(m_pData, m_dwLength);
}
}
}
}
The OnDraw method of class CHexView displays the data loaded into memory. Via GetDocument, the view object gets a reference to the document and its public members m_dwLength and m_pData. OnDraw then does a bit string manipulation and prints out the file contents line-by-line.
Other methods of this class (e.g. OnKeyDown) are responsible for handling user interactions.
void CHexView::OnDraw(CDC* pDC)
{
m_dwOffset = (GetScrollPos(SB_VERT) & 0xfffffff0);
CHexDoc* pDoc = (CHexDoc*) GetDocument();
ASSERT_VALID(pDoc);
for(DWORD dwLine = 0, dwOffset = m_dwOffset;
dwLine < m_dwPageLines; dwLine++, dwOffset += 16)
{
DWORD dwCount = 16 < (dwCount = pDoc->m_dwLength -
dwOffset) ? 16 : dwCount;
CString strLeft, strRight, strFormat;
for(register DWORD dwChar = 0; dwChar < dwCount; dwChar++)
{
strLeft += " %02x";
strRight += "%c";
strLeft.Format(strFormat = strLeft,
BYTE(pDoc->m_pData[dwOffset + dwChar]));
strRight.Format(strFormat = strRight,
CHAR(pDoc->m_pData[dwOffset + dwChar]));
strFormat.Format("%06x ", dwOffset);
strFormat += strLeft + CString(' ',
49 - 3 * dwChar) + strRight;
}
pDC->SelectObject(m_Font);
pDC->TextOut(10, dwOffset, strFormat);
}
}
Points of Interest
- The MFC framework assumes certain guidelines concerning the layout of an application. E.g., in a menu, a minimum of two entries (File, ?) are required. If not present, we get an assertion failure. If an application, like HexView, shall contain only a single menu entry, we have to override the methods
LoadFrame and OnCreateClient in our main frame window class. The implementation is as follows:
BOOL CMainFrame::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
CWnd* pParentWnd, CCreateContext* pContext)
{
return CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle,
pParentWnd, pContext);
}
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* p)
{
return CreateClient(lpcs, NULL);
}
- Scrolling with the mouse wheel may cause a problem. It seems to intervene the displaying mechanism. The line offsets go wrong and lines are printed only halfway. A first fix is
m_dwOffset = (GetScrollPos(SB_VERT) & 0xfffffff0).
History
- 12-20-2005: published HexView at The Code Project.
- 01-25-2006: fixed problem when displaying small files.