Click here to Skip to main content
13,900,697 members
Click here to Skip to main content
Add your own
alternative version

Stats

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

MFC HEX Control 2.0

, 21 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 moment, 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 build and tested in Visual Studio 2017 under Windows 10.

Using the Control

The usage 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/HexCtrl.h" where you suppose to use the control.
  4. Declare CHexCtrl member variable: CHexCtrl myHex;
  5. Call myHex.Create method to create control instance.
  6. 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 to 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
{
	PHEXCOLORSTRUCT pstColor { };			//Pointer to HEXCOLORSTRUCT, if nullptr default colors are used.
	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.
	const LOGFONTW* pLogFont { };			//Font to be used, nullptr for default.
	CWnd*			pwndMsg { };			//Window ptr that is to recieve command messages, if nullptr parent window is used.
	bool			fFloat { false };		//Is float or child (incorporated into another window)?.
	bool			fCustomCtrl { false };	//It's a custom dialog control.
};

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.
};
using PHEXCOLORSTRUCT = HEXCOLORSTRUCT * ;

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

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 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 choise (IDC_MY_HEX in this example). Also, here you can set the control's Dynamic Layoutproperties, so that control behaves appropriately when dialog is being resized. 
  3. Declare CHexCtrl member varable within your dialog class: CHexCtrl m_myhex;
  4. Add the folowing code to the DoDataExchange method of your dialog class:
DDX_Control(pDX, IDC_MY_HEX, m_myhex);

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);
}
  1. Declare HEXCREATESTRUCT variable, set its fCustomCtrl field to true, and call m_myhex.Create method.

SetData

SetData method takes HEXDATASTRUCT reference as argument. This struct 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.
	PBYTE*			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 from the pwndMsg window, in the form of WM_NOTIFY message. This is pretty much the same as the standard MFC List Control works when created with LVS_OWNERDATA flag.
This pwndMsg window pointer can be set in either HEXCREATESTRUCT::pwndMsg — in control's Create method, or in HEXDATASTRUCT::pwndMsg — in SetData method. The difference is that in former case you set the pointer once for the whole control's lifetime, and in the latter you set its own notify handler windows for every SetData call.
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.
In pwndMsg 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)
    {
        switch (pHexNtfy->hdr.code)
        {
        case HEXCTRL_MSG_GETDATA:
			pHexNtfy->chByte = /*code for set the byte, if pHexNtfy->ullSize=1*/;
            pHexNtfy->pData =  /*or code to set the pointer to data*/;
            break;
        }
   }
}

lParam will hold a pointer to a 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.
	PBYTE			pData { };		//Pointer to a data to get/send.
	BYTE			chByte { };		//Single byte data - used for simplicity, when ullSize==1.
};
using PHEXNOTIFYSTRUCT = HEXNOTIFYSTRUCT * ;

Its first member is a standard Windows' NMHDR structure. It will have its code member equal to HEXCTRL_MSG_GETDATAindicating 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'm not a big fan of 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»

Licensing

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

https://github.com/jovibor/HexCtrl/blob/master/LICENSE

Support

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

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
  • 23rd March, 2019 - v2.2.3 Added - Paste methods, Undo, Redo.

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
Web01 | 2.8.190306.1 | Last Updated 22 Mar 2019
Article Copyright 2018 by Jovibor
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid