Click here to Skip to main content
Click here to Skip to main content
Go to top

HexView - an introductory MFC application

, 27 Jan 2006
Rate this:
Please Sign up or sign in to vote.
This article introduces MFC programming basics

HexView screenshot

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:

// HexApp.h

class CHexApp : public CWinApp 
{
protected:
    //{{AFX_VIRTUAL(CHexApp)
    virtual BOOL InitInstance();
    //}}AFX_VIRTUAL

protected:
    //}}AFX_MSG(CHexApp)
    //}}AFX_MSG

    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.

// HexApp.cpp

BOOL CHexApp::InitInstance()
{
    // Fensterobjekt erzeugen
    CMDIFrameWnd* pFrame = new CMainFrame;

    if(pFrame)
    {
        // Schablone für Dokument erzeugen
        AddDocTemplate(new CMultiDocTemplate(
            IDR_MAINFRAME,
            RUNTIME_CLASS(CHexDoc),
            RUNTIME_CLASS(CChildFrame),
            RUNTIME_CLASS(CHexView)));

        // Resourcen laden
        pFrame->LoadFrame(IDR_MAINFRAME);
        
        // Fenster zeigen
        pFrame->ShowWindow(m_nCmdShow);

        // Fensterobjekt zuweisen
        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:

// MainFrame.h

class CMainFrame : public CMDIFrameWnd
{
    DECLARE_DYNAMIC(CMainFrame)

protected:
    //{{AFX_VIRTUAL(CMainFrame)
    BOOL LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
                   CWnd* pParentWnd, CCreateContext* pContext);
    BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* /*pContext*/);
    //}}AFX_VIRTUAL

protected:
    //{{AFX_MSG(CMainFrame)
    afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
    //}}AFX_MSG

    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)
{
    // Dokument soll geladen werden
    if(!archive.IsStoring())
    {
        // Unterliegende Datei ermitteln
        CFile* pFile = archive.GetFile();

        if(pFile)
        {
            // Länge der Datei ermitteln
            m_dwLength = pFile->GetLength();

            // Entsprechend Speicher allokieren
            m_pData = new BYTE[m_dwLength];

            if(m_pData)
            {
                // Komplette Datei in Speicher laden
                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)
{
    // Position of Scrollbalken
    m_dwOffset = (GetScrollPos(SB_VERT) & 0xfffffff0);
    // workaround for offset problem

    // Hole Zeiger auf Dokumentobjekt
    CHexDoc* pDoc = (CHexDoc*) GetDocument();
    ASSERT_VALID(pDoc);

    // Jede Zeile ausgeben
    for(DWORD dwLine = 0, dwOffset = m_dwOffset; 
        dwLine < m_dwPageLines; dwLine++, dwOffset += 16)
    {
        // Anzahl Zeichen in aktueller Zeile
        DWORD dwCount = 16 < (dwCount = pDoc->m_dwLength - 
                                 dwOffset) ? 16 : dwCount;

        CString strLeft, strRight, strFormat;

        for(register DWORD dwChar = 0; dwChar < dwCount; dwChar++)
        {
            // Einzelnes Zeichen hinzufügen
            strLeft  += " %02x";
            strRight += "%c";

            // Umwandlung in (hexadezimales) Zeichen
            strLeft.Format(strFormat = strLeft, 
                    BYTE(pDoc->m_pData[dwOffset + dwChar]));
            strRight.Format(strFormat = strRight, 
                     CHAR(pDoc->m_pData[dwOffset + dwChar]));

            // Offset einfügen
            strFormat.Format("%06x   ", dwOffset);

            // Ausgabezeile zusammenfügen
            strFormat += strLeft + CString(' ', 
                         49 - 3 * dwChar) + strRight;
        }

        // Schriftart zur Ausgabe wählen
        pDC->SelectObject(m_Font);

        // Zeile in Fenster ausgeben
        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:
    // MainFrame.cpp
    
    BOOL CMainFrame::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
            CWnd* pParentWnd, CCreateContext* pContext)
    {
        // Klasse CMDIFrameWnd überspringen
        return CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle,
                                    pParentWnd, pContext);
    }
    
    BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* p)
    {
        // Klasse CMDIFrameWnd überspringen
        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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

vl106

Germany Germany
No Biography provided

Comments and Discussions

 
GeneralMisleading and incorrect PinmemberChris Hills9-Feb-06 1:09 
GeneralRe: Misleading and incorrect Pinmembervl10612-Feb-06 3:07 
GeneralBeing a greedy person... PinmemberIain Clarke1-Feb-06 22:36 

...I'm wanting more!
 
This article is a good start, but being a beginners article, I'd include instructions for what to type into the New Project AppWizard.
 
From the nature of the screenshot, I'm guessing that CHexView inherits from CScrollView, rather than CView. You would need to explicitly say that.
 
If not, then there is a lot of scrolling code that a beginner would benefit from.
 
I've really benefitted from some of the beginner / introduction articles on codeproject, so please keep it up!
 
Iain.
GeneralBug, cosmetic change PinmemberRoger657-Jan-06 3:18 
GeneralRe: Bug, cosmetic change Pinmembervl10625-Jan-06 7:36 
AnswerRe: Bug, cosmetic change Pinmembercurtj at morpho dot com31-Jan-06 12:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 27 Jan 2006
Article Copyright 2006 by vl106
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid