Click here to Skip to main content
13,898,462 members
Click here to Skip to main content
Add your own
alternative version

Stats

35.1K views
1.1K downloads
46 bookmarked
Posted 9 Dec 2018
Licenced MIT

MFC HEX Control 2.0

, 17 Mar 2019
Rate this:
Please Sign up or sign in to vote.
HEX control for MFC apps

Table of Contents

Introduction

Being good low level wrapper library for Windows API in general, MFC was always lacking a good native controls support.

This always forced people to implement their own common stuff for everyday needs.

This HEX control is a tiny attempt to expand standard MFC functionality, because at the time of writing this article, MFC doesn't have native support for such feature.

Implementation

This HEX control is implemented as CWnd derived class, and can be used as a child or float window in any place of your existing MFC application. Control was built and tested in Visual Studio 2017 under Windows 10.

Using the Code

The usage of this control is quite simple:

  1. Copy HexCtrl folder into your project subfolder.
  2. Add all files from HexCtrl folder into your project.
  3. Add #include "HexCtrl.h" where you are supposed to use control.
  4. Add additional include path to HexCtrl folder into your project settings.
  5. Declare CHexCtrl member variable - CHexCtrl myHex;.
  6. Call myHex.Create function to create control instance.
  7. Call myHex.SetData method to set the actual data to display as hex.

Control uses its own namespace — HEXCTRL. So it's up to you, to use namespace prefix - HEXCTRL::, or define namespace in the file's beginning - using namespace HEXCTRL;.

Create

CHexCtrl::Create method - the first method you call - takes HEXCREATESTRUCT as its argument. This is the main initialization struct which fields are described below:

struct HEXCREATESTRUCT
{
    CWnd*           pwndParent { };         //Parent window's pointer.
    UINT            uId { };                //Hex control Id.
    DWORD           dwExStyles { };         //Extended window styles.
    CRect           rect { };               //Initial rect.
                                            //If null, the window is screen centered.
    bool            fFloat { false };       //Is float or child
                                            //(incorporated into another window)?.
    const           LOGFONTW* pLogFont { }; //Font to be used, nullptr for default.
    CWnd*           pwndMsg { };            //Window ptr that is to receive command messages,
                                            //if nullptr parent window is used.
    PHEXCOLORSTRUCT pstColor { };           //Pointer to HEXCOLORSTRUCT,
                                            //if nullptr default colors are used.
};

You can choose whether control will behave as a child or independent floating window by setting fFloat member of this struct.

HEXCREATESTRUCT hcs;
hcs.fFloat = true;
bool Create(hcs);

PHEXCOLORSTRUCT pstColor member of HEXCREATESTRUCT points to the HEXCOLORSTRUCT struct which fields are described below:

struct HEXCOLORSTRUCT {
        COLORREF clrTextHex { GetSysColor(COLOR_WINDOWTEXT) };      //Hex chunks color.
        COLORREF clrTextAscii { GetSysColor(COLOR_WINDOWTEXT) };    //ASCII text color.
        COLORREF clrTextSelected { GetSysColor(COLOR_WINDOWTEXT) }; //Selected text color.
        COLORREF clrTextCaption { RGB(0, 0, 180) };                 //Caption color
        COLORREF clrTextInfoRect { GetSysColor(COLOR_WINDOWTEXT) }; //Text color of the bottom 
                                                                    //"Info" rect.
        COLORREF clrTextCursor { RGB(255, 255, 255) };              //Cursor text color.
        COLORREF clrBk { GetSysColor(COLOR_WINDOW) };               //Background color.
        COLORREF clrBkSelected { RGB(200, 200, 255) };              //Background color 
                                                                    //of the selected Hex/Ascii.
        COLORREF clrBkInfoRect { RGB(250, 250, 250) };              //Background color 
                                                                    //of the bottom "Info" rect.
        COLORREF clrBkCursor { RGB(0, 0, 250) };                    //Cursor background color.
    };

This struct is also used in CHexCtrl::SetColor method.

Control In Dialog

To use HexCtrl within Dialog, you can create it with the standard routine: call Create method and provide all the necessary information. But there is another approach you can use:

  1. Put Custom Control control from the Toolbox in Visual Studio dialog designer into your dialog template and make it the desired size.

  2. Then go to the Properties of that control, and in the Class field, within the Misc section, write HexCtrl. Give the control appropriate ID of your choice (IDC_MY_HEX in this example). Also, here you can set the control's Dynamic Layout properties, so that the control behaves appropriately when dialog is being resized.

  3. Declare CHexCtrl member variable within your dialog class: CHexCtrl m_myhex;
  4. Add the following code to the DoDataExchange method of your dialog class: DDX_Control(pDX, IDC_MY_HEX, m_myhex);
  5. So that it looks like in the example below:
    void CMyDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialogEx::DoDataExchange(pDX);
    	DDX_Control(pDX, IDC_MY_HEX, m_myhex);
    }
  6. Last but not the least, declare HEXCREATESTRUCT object and set its fCustomCtrl member to true, and uId to IDC_MY_HEX (Id of your control). Finally, call m_myhex.Create method.

SetData

SetData method takes HEXDATASTRUCT reference as argument. This struct's fields are described below:

struct HEXDATASTRUCT {
    ULONGLONG ullDataSize { };       //Size of the data to display, in bytes.
    ULONGLONG ullSelectionStart { }; //Set selection at this position.
                                     //Works only if ullSelectionSize > 0.
    ULONGLONG ullSelectionSize { };  //How many bytes to set as selected.
    CWnd* pwndMsg { };               //Window to send the control messages to.
                                     //If nullptr then the parent window is used.
    unsigned char* pData { };        //Pointer to the data. Not used if it's virtual control.
    bool fMutable { false };         //Will data be mutable (editable) or just read mode.
    bool fVirtual { false };         //Is Virtual data mode?.
};

Virtual Mode

The fVirtual member of HEXDATASTRUCT shows whether HexControl works in Virtual Mode.

What it means is that when control is about to display next byte, it will first ask for this byte's value from HEXDATASTRUCT::pwndMsg window, in the form of WM_NOTIFY message. This is pretty much the same as the standard MFC List Control works when it's created with LVS_OWNERDATA flag. This mode can be quite useful, for instance, in cases where you need to display a very large amount of data, that can't fit in memory all at once.

void SetData(const HEXDATASTRUCT& hds);

In control's parent window, process WM_NOTIFY message as follows:

BOOL CMyWnd::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
    PHEXNOTIFYSTRUCT pHexNtfy = (PHEXNOTIFYSTRUCT)lParam;

    if (pHexNtfy->hdr.idFrom == IDC_MY_HEX_CTRL)
    {
        switch (pHexNtfy->hdr.code)
        {
        case HEXCTRL_MSG_GETDATA:
            pHexNtfy->chByte = /*code for set given byte data*/;
            break;
        }
   }
}

lParam will hold a pointer to HEXNOTIFYSTRUCT structure, which is described below:

struct HEXNOTIFYSTRUCT
{
	NMHDR			hdr;			//Standard Windows header. 
                                    //For hdr.code values see HEXCTRL_MSG_* messages.
	ULONGLONG		ullByteIndex;	//Index of the start byte to get/send.
	ULONGLONG		ullSize;		//Size of the bytes to send.
	unsigned char	chByte;			//Value of the byte to get/send.
};
using PHEXNOTIFYSTRUCT = HEXNOTIFYSTRUCT * ;

Its first member is a standard Windows' NMHDR structure. It will have its code member equal to HEXCTRL_MSG_GETDATA, indicating that HexControl's byte request has arrived.

The second member is the index of the byte be displayed. And the third is the actual byte, that you have to set in response.

OnDestroy

When HexControl window, floating or child, is destroyed, it sends WM_NOTIFY message to its parent window with NMHDR::code equal to HEXCTRL_MSG_DESTROY. So, it basically indicates to its parent that the user clicked close button, or closed window in some other way.

Scroll Bars

When I started to work with very big files, I immediately faced one very nasty inconvenience:

The standard Windows scrollbars can hold only signed integer value, which is too little to scroll through many gigabytes of data. It could be some workarounds and crutches involved to overcome this, but frankly saying, I hate this kind of approach.

That's why HexControl uses its own scrollbars. They work with unsigned long long values, which is way bigger than standard signed ints. These scrollbars behave as normal Windows scrollbars, and even reside in the non client area, as the latter do.

Methods

CHexCtrl class has a set of methods, that you can use to customize your control's appearance. These methods' usage is pretty straightforward and clean from their naming.

void SetData(const HEXDATASTRUCT& hds); //Main method for setting data to display (and edit).
void ClearData();           //Clears all data from HexCtrl's view (not touching data itself).
void SetCapacity(DWORD dwCapacity);
void SetFont(const LOGFONT* pLogFontNew);
void SetFontSize(UINT nSize);
void SetColor(const HEXCOLORSTRUCT& clr);
void ShowOffset(ULONGLONG ullOffset, ULONGLONG ullSize = 1);

Example

The function you use to set a data to display as hex is CHexCtrl::SetData.

The code below constructs CHexCtrl object and displays first 0x1FF bytes of your app's memory:

CHexCtrl myHex.
HEXCREATESTRUCT hcs;
hcs.pwndParent = this;
myHex.Create(hcs);

HEXDATASTRUCT hds;
hds.pData = (unsigned char*)GetModuleHandle(0);
hds.ullDataSize = 0x1FF;
myHex.SetData(hds);

The next example displays std::string's text string as hex:

std::string str = "My string";
HEXDATASTRUCT hds;
hds.pData = (unsigned char*)str.data();
hds.ullDataSize = str.size();
myHex.SetData(hds);

Positioning and Sizing

To properly resize and position your HexControl's window, you may have to handle WM_SIZE message in its parent window, in something like this way:

void CMyWnd::OnSize(UINT nType, int cx, int cy)
{
    .
    .
    myHex.SetWindowPos(this, 0, 0, cx, cy, SWP_NOACTIVATE | SWP_NOZORDER);
}

Appearance

  • To change control's font size - «Ctrl+MouseWheel»
  • To change control's capacity - «Ctrl+Shift+MouseWheel»

Support

If you have any useful feature to suggest, or if you found a bug — please let me know in the comments section below.

Licensing

This software is available under the "MIT License modified with The Commons Clause".

History

  • 8th December, 2018 - First version
  • 21st December, 2018 - v1.1 Some tweaks and fixes
  • 23rd December, 2018 - v1.2 C++17 obligation has been alleviated
  • 25th December, 2018 - v1.3 Added Bottom info bar, Ability to change capacity. Fixes: Some selection related bugs fixed.
  • 28th December, 2018 - v1.4 Added About box, Selection offset into info bar, Search support. Fixed some minor bugs.
  • 4th January, 2019 - v1.5 Further improvements and fixes
  • 7th January, 2019 - v1.5.1 Small fix
  • 12th February, 2019 - v1.7 Lots of reworks, improvements and fixes
  • 19th February, 2019 - v1.7.5 Fixed some regressions. HEXCTRLCREATE added
  • 26th February, 2019 - v1.8 Speed improvements in drawing routine. Other fixes
  • 3rd March, 2019 - v1.8.1 Minor fixes. Added sample project
  • 12th March, 2019 - v2.0 Edit mode added. Show data as BYTE, WORD,.. etc. Many improvements
  • 15th March, 2019 - v2.1 Fixed regressions. Code reworks and cleaning
  • 17th March, 2019 - v2.2.1 Added dialog Custom Control support

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

Jovibor
Russian Federation Russian Federation
No Biography provided

You may also be interested in...

Pro

Comments and Discussions

 
QuestionOld School! Pin
Member 1417684313-Mar-19 12:32
memberMember 1417684313-Mar-19 12:32 
GeneralStyle Pin
Rick York12-Mar-19 10:28
mveRick York12-Mar-19 10:28 
GeneralRe: Style Pin
Jovibor12-Mar-19 14:02
memberJovibor12-Mar-19 14:02 
GeneralRe: Style Pin
Rick York12-Mar-19 16:26
mveRick York12-Mar-19 16:26 
GeneralRe: Style Pin
Jovibor12-Mar-19 17:16
memberJovibor12-Mar-19 17:16 
GeneralRe: Style Pin
Rick York12-Mar-19 20:19
mveRick York12-Mar-19 20:19 
GeneralRe: Style Pin
Jovibor12-Mar-19 21:24
memberJovibor12-Mar-19 21:24 
GeneralRe: Style Pin
Rick York13-Mar-19 4:43
mveRick York13-Mar-19 4:43 
GeneralRe: Style Pin
Rick York13-Mar-19 11:40
mveRick York13-Mar-19 11:40 
GeneralRe: Style Pin
Rick York14-Mar-19 7:11
mveRick York14-Mar-19 7:11 
GeneralRe: Style Pin
Jovibor14-Mar-19 13:54
memberJovibor14-Mar-19 13:54 
GeneralRe: Style Pin
Jovibor12-Mar-19 22:22
memberJovibor12-Mar-19 22:22 
GeneralRe: Style Pin
Rick York13-Mar-19 4:45
mveRick York13-Mar-19 4:45 
GeneralRe: Style Pin
Jovibor13-Mar-19 12:40
memberJovibor13-Mar-19 12:40 
GeneralRe: Style Pin
Rick York13-Mar-19 13:01
mveRick York13-Mar-19 13:01 
GeneralRe: Style Pin
Rick York13-Mar-19 14:27
mveRick York13-Mar-19 14:27 
GeneralRe: Style Pin
Rick York13-Mar-19 16:40
mveRick York13-Mar-19 16:40 
GeneralRe: Style Pin
Jovibor13-Mar-19 19:18
memberJovibor13-Mar-19 19:18 
GeneralRe: Style Pin
Rick York13-Mar-19 20:30
mveRick York13-Mar-19 20:30 
GeneralRe: Style Pin
Jovibor13-Mar-19 20:54
memberJovibor13-Mar-19 20:54 
GeneralRe: Style Pin
Rick York14-Mar-19 4:30
mveRick York14-Mar-19 4:30 
GeneralRe: Style Pin
Jovibor15-Mar-19 3:05
memberJovibor15-Mar-19 3:05 
GeneralRe: Style Pin
Rick York15-Mar-19 4:48
mveRick York15-Mar-19 4:48 
GeneralRe: Style Pin
Jovibor15-Mar-19 13:39
memberJovibor15-Mar-19 13:39 
GeneralRe: Style Pin
Rick York15-Mar-19 16:41
mveRick York15-Mar-19 16:41 

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

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

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web06 | 2.8.190306.1 | Last Updated 17 Mar 2019
Article Copyright 2018 by Jovibor
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid