Click here to Skip to main content
14,976,689 members
Articles / Desktop Programming / MFC

Stats

119.4K views
8K downloads
106 bookmarked

Hex Control for C++/Win32 applications.

Rate me:
Please Sign up or sign in to vote.
4.96/5 (69 votes)
23 Nov 2020MIT14 min read
HexCtrl is a very featured Hex viewer/editor control written with C++/MFC library.
In this article we go over: Installation, creating HexControl instance, setting a data to display in the HexControl, bookmarked regions and how they can be assigned with individual background and text color and description, and an overview of the methods in HexControl.

Hex Control, C++/MFC

Image 1

Table of Contents

Introduction

HexCtrl is a very featured Hex viewer/editor control written with C++/MFC library.

It's implemented as a pure abstract interface and therefore can be used in your app even if you doesn't use MFC directly. It's written with /std:c++17 standart in Visual Studio 2019, under the Windows 10.

The main features of the HexCtrl:

  • View and edit data up to 16EB (exabyte)
  • Work in three different data modes: Memory, Message, Virtual
  • Fully featured Bookmarks Manager
  • Fully featured Search and Replace
  • Changeable encoding for the text area
  • Many options to Copy/Paste to/from clipboard
  • Undo/Redo
  • Modify data with Filling and many predefined Operations options
  • Ability to visually divide data into pages
  • Print whole document/pages range/selection
  • Set individual colors for the data chunks with IHexVirtColors interface
  • Cutomizable colors, look and appearance
  • Assignable keyboard shortcuts via external config file
  • Written with /std:c++17 standard conformance

Image 2

Installation

The HexCtrl can be used in two different ways:

  • Building from the sources as a part of your project
  • Using as a .dll.

Building From The Sources

The building process is quite simple:

  1. Copy HexCtrl folder into your project's directory.
  2. Add all files from the HexCtrl folder into your project, except for
    HexCtrl/dep/rapidjson/rapidjson-amalgam.h (header-only lib).
  3. Add #include "HexCtrl/HexCtrl.h" where you suppose to use the HexCtrl.
  4. Declare HexCtrl's namespace: using namespace HEXCTRL;
  5. Declare IHexCtrlPtr member variable: IHexCtrlPtr myHex { CreateHexCtrl() };
  6. Create control instance.

If you want to build HexCtrl from the sources in non MFC app you will have to:

  1. Add support for Use MFC in a Shared DLL in your project settings.
  2. Uncomment the line //#define HEXCTRL_MANUAL_MFC_INIT in HexCtrl.h header file.

To use HexCtrl as the .dll do the following:

  1. Copy HexCtrl.h file into your project's folder.
  2. Copy HexCtrl.lib file into your project's folder, so that linker can see it.
  3. Put HexCtrl.dll file next to your .exe file.
  4. Add the following line where you suppose to use the control:
C++
#define HEXCTRL_SHARED_DLL //You can alternatively uncomment this line in HexCtrl.h.
#include "HexCtrl.h"` 
  1. Declare IHexCtrlPtr member variable: IHexCtrlPtr myHex { CreateHexCtrl() };
  2. Create control instance.

To build HexCtrl.dll and HexCtrl.lib use the DLL Project/DLL Project.vcxproj Visual Studio project file.

Remarks:

HexCtrl's .dll is built with MFC Static Linking. So even if you are to use it in your own MFC project, even with different MFC version, there should not be any interferences

Building HexCtrl with MFC Shared DLL turned out to be a little tricky. Even with the help of AFX_MANAGE_STATE(AfxGetStaticModuleState()) macro there always were MFC debug assertions, which origins quite hard to comprehend.

IHexCtrlPtr

IHexCtrlPtr is, in fact, a pointer to a IHexCtrl pure abstract base class, wrapped either in std::unique_ptr or std::shared_ptr. You can choose whatever is best for your needs by define or undefine/comment-out the HEXCTRL_IHEXCTRLPTR_UNIQUEPTR macro in HexCtrl.h.
By default HEXCTRL_IHEXCTRLPTR_UNIQUEPTR is defined, thus IHexCtrlPtr is an alias for std::unique_ptr<IHexCtrl>.

This wrapper is used mainly for convenience, so you don't have to bother about object lifetime, it will be destroyed automatically. That's why there is a call to the factory function CreateHexCtrl() - to properly initialize a pointer.

If you, for some reason, need a raw interface pointer, you can directly call CreateRawHexCtrl function, which returns IHexCtrl interface pointer, but in this case you will need to call Destroy method manually afterwards, to destroy IHexCtrl object.

Namespace

HexCtrl uses its own namespace HEXCTRL.
So it's up to you, whether to use namespace prefix before declarations:

C++
HEXCTRL::

or to define namespace globally, in the source file's beginning:

C++
using namespace HEXCTRL;

Creating

Classic Approach

Create is the first method you call to create HexCtrl instance. It takes HEXCREATESTRUCT reference as an argument.

You can choose whether control will behave as a child or independent popup window, by setting enCreateMode member of this struct to EHexCreateMode::CREATE_CHILD or EHexCreateMode::CREATE_POPUP respectively.

C++
HEXCREATESTRUCT hcs;
hcs.enCreateMode = EHexCreateMode::CREATE_POPUP;
hcs.hwndParent = m_hWnd;
m_myHex->Create(hcs);

For all available options see HEXCREATESTRUCT description.

In Dialog

To use HexCtrl within Dialog you can, of course, create it with the Classic Approach, call Create method and provide all the necessary information.

But there is another option you can use:

  1. Put Custom Control from the Toolbox in Visual Studio dialog designer into your dialog template and make it desirable size.
    Image 3 Image 4
  2. Go to the Properties of that control and in the Class field, within the Misc section, type: HexCtrl.
    Give the control appropriate ID of your choise (IDC_MY_HEX in this example).
    Also, here you can set the control's Dynamic Layout properties, so that control behaves appropriately when dialog is being resized.
    Image 5
  3. Declare IHexCtrlPtr member varable within your dialog class:
C++
IHexCtrlPtr m_myHex { CreateHexCtrl() };
  1. Call CreateDialogCtrl method from your dialog's OnInitDialog method.
C++
BOOL CMyDialog::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    
    m_myHex->CreateDialogCtrl(IDC_MY_HEX, m_hWnd);
}

Set the Data

To set a data to display in the HexCtrl use SetData method. The code below shows how to construct IHexCtrlPtr object and display first 0x1FF bytes of the current app's memory:

C++
IHexCtrlPtr myHex { CreateHexCtrl() };

HEXCREATESTRUCT hcs;
hcs.hwndParent = m_hWnd;
hcs.rect = {0, 0, 600, 400}; //Window rect.

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 as hex:

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

myHex->SetData(hds);

Data Modes

Besides the standard classical mode, when HexCtrl just holds a pointer to some array of bytes in memory, it also has additional advanced modes it can be running in.
These modes 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.

These modes are ruled over through the enDataMode member of HEXDATASTRUCT.

Memory Data

It's the default data mode the control works in.
The enDataMode member of the HEXDATASTRUCT is set to DATA_MEMORY, and pData just points to bytes in memory.

Message Window

If enDataMode member of HEXDATASTRUCT is set to DATA_MSG, the control works in, so called, Message Window mode.

What it means is that when control is about to display data, it will first ask for this data from the HEXDATASTRUCT::hwndMsg window, in the form of WM_NOTIFY Windows' message. This is pretty much the same as the standard MFC List Control works when created with LVS_OWNERDATA flag.
By default the HEXDATASTRUCT::hwndMsg is equal to the control's parent window.

To properly handle this mode, you must process WM_NOTIFY messages in hwndMsg window as follows:

C++
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->stSpan at this moment shows offset and size of the data 
            * that HexCtrl requests. You have to provide pointer to it.
            ***************************************************************************
            
            pHexNtfy->pData =  /*Set this pointer to an actual data*/;
            break;
        }
   }
}

lParam will hold a pointer to the HEXNOTIFYSTRUCT structure.

The first member of this structure is a standard Windows' NMHDR struct, it will have its code member equal to HEXCTRL_MSG_GETDATA, indicating that HexCtrl's byte request has arrived.
The ullIndex member of the structure is an index of the byte to be displayed. And the pData is the pointer to an actual byte that you have to set in response.

Virtual Handler

If enDataMode member of HEXDATASTRUCT is set to DATA_VIRTUAL then all the data routine will be done through HEXDATASTRUCT::pHexVirtual pointer.

This pointer is of IHexVirtData class type, which is a pure abstract base class. You have to derive your own class from it and implement all its public methods:

C++
class IHexVirtData
{
public:
    [[nodiscard]] virtual std::byte* GetData(const HEXSPANSTRUCT&) = 0; //Data index and size to get.
    virtual void SetData(std::byte*, const HEXSPANSTRUCT&) = 0; //Routine to modify data, if HEXDATASTRUCT::fMutable == true.
};

Then provide a pointer to created object of this derived class prior to call to SetData method in form of HEXDATASTRUCT::pHexVirtData = &yourDerivedObject.

Virtual Bookmarks

HexCtrl has innate functional to work with any amount of bookmarked regions. These regions can be assigned with individual background and text color and description.

But if you have some big and complicated data logic and want to handle all these regions yourself, you can do it.
virtuvoid SetData(stdbyte*, const HEXSPANSTRUCT&) = 0; //Routine to modify data, if HEXDATASTRUCTfMutable == true.

To enable virtual bookmarks call the BkmSetVirtual method.

The main method of the IHexVirtBkm interface is HitTest. It takes byte's offset and returns pointer to HEXBKMSTRUCT if there is a bookmark withing this byte, or nullptr otherwise.

C++
class IHexVirtBkm
{
public:
    virtual ULONGLONG Add(const HEXBKMSTRUCT& stBookmark) = 0; //Add new bookmark, return new bookmark's ID.
    virtual void ClearAll() = 0; //Clear all bookmarks.
    [[nodiscard]] virtual ULONGLONG GetCount() = 0; //Get total bookmarks count.
    [[nodiscard]] virtual auto GetByID(ULONGLONG ullID)->HEXBKMSTRUCT* = 0; //Bookmark by ID.
    [[nodiscard]] virtual auto GetByIndex(ULONGLONG ullIndex)->HEXBKMSTRUCT* = 0; //Bookmark by index (in inner list).
    [[nodiscard]] virtual auto HitTest(ULONGLONG ullOffset)->HEXBKMSTRUCT* = 0; //Has given offset the bookmark?
    virtual void RemoveByID(ULONGLONG ullID) = 0;   //Remove bookmark by given ID (returned by Add()).
};

IHexVirtColors

This interface is used to set custom bk/text colors for the given data offset.
To provide the color a pointer to the valid HEXCOLOR structure must be returned from the IHexVirtColors::GetColor method. If nullptr is returned the default colors will be used.

In order to use this interface the HEXDATASTRUCT::pHexVirtColors member must be set to the valid class inherited from this interface, prior to calling SetData method.

C++
class IHexVirtColors
{
public:
    [[nodiscard]] virtual PHEXCOLOR GetColor(ULONGLONG ullOffset) = 0;
};

Methods

The HexCtrl has plenty of methods that you can use to customize its appearance, and to manage its behaviour.

BkmAdd

C++
ULONGLONG BkmAdd(const HEXBKMSTRUCT& hbs, bool fRedraw = false)

Adds new bookmark to the control. Uses HEXBKMSTRUCT as an argument. Returns created bookmark's id.

Example

C++
HEXBKMSTRUCT hbs;
hbs.vecSpan.emplace_back(HEXSPANSTRUCT { 0x1, 10 });
hbs.clrBk = RGB(0, 255, 0);
hbs.clrText = RGB(255, 255, 255);
hbs.wstrDesc = L"My first bookmark, with green bk and white text.";

myHex.BkmAdd(hbs);

BkmClearAll

C++
void BkmClearAll();

Clears all bookmarks.

BkmGetByID

C++
BkmGetByID(ULONGLONG ullID)->HEXBKMSTRUCT*;

Get bookmark by ID.

BkmGetByIndex

C++
auto BkmGetByIndex(ULONGLONG ullIndex)->HEXBKMSTRUCT*;

Get bookmark by Index.

BkmGetCount

C++
ULONGLONG BkmGetCount()const;

Get bookmarks' count.

BkmHitTest

C++
auto BkmHitTest(ULONGLONG ullOffset)->HEXBKMSTRUCT*;

Test given offset and retrives pointer to HEXBKMSTRUCT if it contains bookmark.

BkmRemoveByID

C++
void BkmRemoveByID(ULONGLONG ullID);

Removes bookmark by the given ID.

BkmSetVirtual

C++
void BkmSetVirtual(bool fEnable, IHexVirtBkm* pVirtual = nullptr);

Enables or disables bookmarks virtual mode.

ClearData

C++
void ClearData();

Clears data from the HexCtrl view, not touching data itself.

Create

C++
bool Create(const HEXCREATESTRUCT& hcs);

Main initialization method.
Takes HEXCREATESTRUCT as argument. Returns true if created successfully, false otherwise.

CreateDialogCtrl

C++
bool CreateDialogCtrl(UINT uCtrlID, HWND hwndDlg);

Creates HexCtrl from Custom Control dialog's template. Takes control's id, and dialog's window handle as arguments. See Creating section for more info.

Destroy

C++
void Destroy();

Destroys the control.
You only invoke this method if you use a raw IHexCtrl pointer obtained by the call to CreateRawHexCtrl function. Otherwise don't use it.

Remarks
You usually don't need to call this method unless you use HexCtrl through the raw pointer obtained by CreateRawHexCtrl factory function.
If you use HexCtrl in standard way, through the IHexCtrlPtr pointer, obtained by CreateHexCtrl function, this method will be called automatically.

ExecuteCmd

C++
void ExecuteCmd(EHexCmd enCmd)const;

Executes one of the predefined commands of EHexCmd enum. All these commands are basically replicating control's inner menu.

GetCapacity

C++
DWORD GetCapacity()const

Returns current capacity.

GetCaretPos

C++
ULONGLONG GetCaretPos()const;

Retrieves current caret position offset.

GetColors

C++
auto GetColors()const->HEXCOLORSSTRUCT

Returns current HEXCOLORSSTRUCT.

GetDataSize

C++
auto GetDataSize()const->ULONGLONG;

Returns currently set data size.

GetEncoding

C++
int GetEncoding()const;

Get code page that is currently in use.

GetGroupMode

C++
auto GetGroupMode()const->EHexGroupMode;

Retrieves current data grouping mode.

GetFontSize

C++
long GetFontSize()const;

Returns current font size.

GetMenuHandle

C++
HMENU GetMenuHandle()const;

Retrives the HMENU handle of the control's context menu. You can use this handle to customize menu for your needs.

Control's internal menu uses menu IDs in range starting from 0x8001. So if you wish to add your own new menu, assign menu ID starting from 0x9000 to not interfere.

When user clicks custom menu, control sends WM_NOTIFY message to its parent window with LPARAM pointing to HEXNOTIFYSTRUCT with its hdr.code member set to HEXCTRL_MSG_MENUCLICK. ullData field of the HEXNOTIFYSTRUCT will be holding ID of the menu clicked.

GetPagesCount

C++
DWORD GetPageSize()const;

Get current count of pages set by SetPageSize.

GetPagePos

C++
auto GetPagePos()->ULONGLONG const;

Get current page a cursor stays at.

GetPageSize

C++
DWORD GetPageSize()const;

Get current page size set by SetPageSize.

GetSelection

C++
auto GetSelection()const->std::vector<HEXSPANSTRUCT>&;

Returns std::vector of offsets and sizes of the current selection.

GetWindowHandle

C++
HWND GetWindowHandle(EHexWnd enWnd)const

Retrieves window handle for one of the HexCtrl's windows. Takes EHexWnd enum as an argument.

GoToOffset

C++
void GoToOffset(ULONGLONG ullOffset, int iRelPos = 0)

Go to a given offset. The second argument iRelPos may take-in three different values:

  • -1 - offset will appear at the top line.
  •   0 - offset will appear at the middle.
  •   1 - offset will appear at the bottom line.

HitTest

C++
auto HitTest(POINT pt, bool fScreen = true)const->std::optional<HEXHITTESTSTRUCT>

Hit testing of given point in screen fScreen = true, or client fScreen = false coordinates. In case of success returns HEXHITTESTSTRUCT structure.

IsCmdAvail

C++
bool IsCmdAvail(EHexCmd enCmd)const;

Returns true if given command can be executed at the moment, false otherwise.

IsCreated

C++
bool IsCreated()const;

Shows whether HexCtrl is created or not yet.

IsDataSet

C++
bool IsDataSet()const;

Shows whether a data was set to HexCtrl or not

IsMutable

C++
bool IsMutable()const;

Shows whether HexCtrl is currently in edit mode or not.

IsOffsetAsHex

C++
bool IsOffsetAsHex()const;

Is "Offset" currently represented (shown) as Hex or as Decimal. It can be changed by double clicking at offset area.

IsOffsetVisible

C++
HEXVISSTRUCT IsOffsetVisible(ULONGLONG ullOffset)const;

Checks for offset visibility and returns HEXVISSTRUCT as a result.

Redraw

C++
void Redraw();

Redraws the main window.

SetCapacity

C++
void SetCapacity(DWORD dwCapacity);

Sets the HexCtrl current capacity.

SetCaretPos

C++
void SetCaretPos(ULONGLONG ullOffset, bool fHighLow = true, bool fRedraw = true);

Set the caret to the given offset. The fHighLow flag shows which part of the hex chunk, low or high, a caret must be set to, it only makes sense in mutable mode.

SetColors

C++
void SetColors(const HEXCOLORSSTRUCT& clr);

Sets all the colors for the control. Takes HEXCOLORSSTRUCT as the argument.

SetConfig

C++
bool SetConfig(std::wstring_view wstrPath);

Set the path to a JSON config file with keybindings to use in HexCtrl, or L"" for default. This file is using EHexCmd enum values as keys and strings array as values:

JavaScript
{
    "CMD_DLG_SEARCH": [ "ctrl+f", "ctrl+h" ],
    "CMD_SEARCH_NEXT": [ "f3" ],
    "CMD_SEARCH_PREV": [ "shift+f3" ]
}

For default values see HexCtrl/res/keybind.json file from the project source folder.

SetData

C++
void SetData(const HEXDATASTRUCT& hds);

Main method to set data to display in read-only or edit modes. Takes HEXDATASTRUCT as an argument.

SetEncoding

C++
void SetEncoding(int iCodePage);

Sets the code page for the HexCtrl's text area. Takes code page identifier as an argument, or -1 for default ASCII-only characters.

Note: Code page identifier must represent Single-byte Character Set. Multi-byte character sets are not currently supported.

SetFont

C++
void SetFont(const LOGFONTW* pLogFontNew);

Sets a new font for the HexCtrl. This font has to be monospaced.

SetFontSize

C++
void SetFontSize(UINT uiSize);

Sets a new font size to the HexCtrl.

SetGroupMode

C++
void SetGroupMode(EHexGroupMode enGroupMode);

Sets current data grouping mode. See EHexGroupMode for more info.

SetMutable

C++
void SetMutable(bool fEnable);

Enables or disables mutable mode. In mutable mode all the data can be modified.

SetOffsetMode

C++
void SetOffsetMode(bool fHex);

Set offset area being shown as Hex (fHex=true) or as Decimal (fHex=false).

SetPageSize

C++
void SetPageSize(DWORD dwSize, const wchar_t* wstrName = L"Page");

Sets the size of the page to draw the divider line between. This size should be multiple to the current capacity size to take effect. The second argument sets the name to be displayed in the bottom info area of the HexCtrl ("Page", "Sector", etc...).
To remove the divider just set dwSize to 0.

SetSelection

C++
void SetSelection(const std::vector<HEXSPANSTRUCT>& vecSel, bool fRedraw = true);

Sets current selection.

SetWheelRatio

C++
void SetWheelRatio(double dbRatio)

Sets the ratio for how much to scroll with mouse-wheel.

Structures

Below are listed all HexCtrl's structures.

HEXBKMSTRUCT

Structure for bookmarks, used in BkmAdd method.

C++
struct HEXBKMSTRUCT
{
    std::vector<HEXSPANSTRUCT> vecSpan { };                //Vector of offsets and sizes.
    std::wstring               wstrDesc { };               //Bookmark description.
    ULONGLONG                  ullID { };                  //Bookmark ID, assigned internally by framework.
    ULONGLONG                  ullData { };                //User defined custom data.
    COLORREF                   clrBk { RGB(240, 240, 0) }; //Bk color.
    COLORREF                   clrText { RGB(0, 0, 0) };   //Text color.
};
using PHEXBKMSTRUCT = HEXBKMSTRUCT*;

The member vecSpan is of a std::vector<HEXSPANSTRUCT> type because a bookmark may have few non adjacent areas. For instance, when selection is made as a block, with Alt pressed.

HEXCOLOR

HexCtrl custom colors.

C++
struct HEXCOLOR
{
    COLORREF clrBk { };   //Bk color.
    COLORREF clrText { }; //Text color.
};
using PHEXCOLOR = HEXCOLOR*;

HEXCOLORSSTRUCT

This structure describes all control's colors. All these colors have their default values.

C++
struct HEXCOLORSSTRUCT
{
    COLORREF clrTextHex { GetSysColor(COLOR_WINDOWTEXT) };       //Hex chunks text color.
    COLORREF clrTextASCII { GetSysColor(COLOR_WINDOWTEXT) };     //ASCII text color.
    COLORREF clrTextSelect { GetSysColor(COLOR_HIGHLIGHTTEXT) }; //Selected text color.
    COLORREF clrTextDataInterp { RGB(250, 250, 250) };           //Data Interpreter text color.
    COLORREF clrTextCaption { RGB(0, 0, 180) };                  //Caption text color
    COLORREF clrTextInfoRect { GetSysColor(COLOR_WINDOWTEXT) };  //Text color of the bottom "Info" rect.
    COLORREF clrTextCaret { RGB(255, 255, 255) };                //Caret text color.
    COLORREF clrTextTooltip { GetSysColor(COLOR_INFOTEXT) };     //Tooltip text color.
    COLORREF clrBk { GetSysColor(COLOR_WINDOW) };                //Background color.
    COLORREF clrBkSelected { GetSysColor(COLOR_HIGHLIGHT) };     //Background color of the selected Hex/ASCII.
    COLORREF clrBkDataInterp { RGB(147, 58, 22) };               //Data Interpreter Bk color.
    COLORREF clrBkInfoRect { GetSysColor(COLOR_BTNFACE) };       //Background color of the bottom "Info" rect.
    COLORREF clrBkCaret { RGB(0, 0, 255) };                      //Caret background color.
    COLORREF clrBkCaretSelect { RGB(0, 0, 200) };                //Caret background color in selection.
    COLORREF clrBkTooltip { GetSysColor(COLOR_INFOBK) };         //Tooltip background color.
};

HEXCREATESTRUCT

The main initialization struct used for control creation.

C++
struct HEXCREATESTRUCT
{
    EHexCreateMode  enCreateMode { EHexCreateMode::CREATE_CHILD }; //Creation mode of the HexCtrl window.
    HEXCOLORSSTRUCT stColor { };          //All the control's colors.
    HWND            hwndParent { };       //Parent window pointer.
    const LOGFONTW* pLogFont { };         //Font to be used instead of default, it has to be monospaced.
    RECT            rect { };             //Initial rect. If null, the window is screen centered.
    UINT            uID { };              //Control ID.
    DWORD           dwStyle { };          //Window styles, 0 for default.
    DWORD           dwExStyle { };        //Extended window styles, 0 for default.
    double          dbWheelRatio { 1.0 }; //Ratio for how much to scroll with mouse-wheel.
};

HEXDATASTRUCT

Main struct to set a data to display in the control.

C++
struct HEXDATASTRUCT
{
    EHexDataMode    enDataMode { EHexDataMode::DATA_MEMORY }; //Working data mode.
    ULONGLONG       ullDataSize { };          //Size of the data to display, in bytes.
    HWND            hwndMsg { };              //Window for DATA_MSG mode. Parent is used by default.
    IHexVirtData*   pHexVirtData { };         //Pointer for DATA_VIRTUAL mode.
    IHexVirtColors* pHexVirtColors { };       //Pointer for Custom Colors class.
    std::byte*      pData { };                //Data pointer for DATA_MEMORY mode. Not used in other modes.
    DWORD           dwCacheSize { 0x800000 }; //In DATA_MSG and DATA_VIRTUAL max cached size of data to fetch.
    bool            fMutable { false };       //Is data mutable (editable) or read-only.
    bool            fHighLatency { false };   //Do not redraw window until scrolling completes.
};

HEXHITTESTSTRUCT

Structure is used in HitTest method.

C++
struct HEXHITTESTSTRUCT
{
    ULONGLONG ullOffset { };      //Offset.
    bool      fIsAscii { false }; //Is cursor at ASCII part or at Hex.
};

HEXNOTIFYSTRUCT

This struct is used in notification purposes, to notify parent window about HexCtrl's states.

C++
struct HEXNOTIFYSTRUCT
{
    NMHDR         hdr { };     //Standard Windows header. For hdr.code values see HEXCTRL_MSG_* messages.
    HEXSPANSTRUCT stSpan { };  //Offset and size of the bytes. 
    ULONGLONG     ullData { }; //Data depending on message (e.g. user defined custom menu id/cursor pos).
    std::byte*    pData { };   //Pointer to a data to get/send.
    POINT         point { };   //Mouse position for menu notifications.
};
using PHEXNOTIFYSTRUCT = HEXNOTIFYSTRUCT*;

HEXSPANSTRUCT

This struct is used mostly in selection and bookmarking routines. It holds offset and size of the data region.

C++
struct HEXSPANSTRUCT
{
    ULONGLONG ullOffset { };
    ULONGLONG ullSize { };
};

HEXVISSTRUCT

This struct is returned from IsOffsetVisible method. Two members i8Vert and i8Horz represent vertical and horizontal visibility respectively. These members can be in three different states:

  • -1 — offset is higher, or at the left, of the visible area.
  •   1 — offset is lower, or at the right.
  •   0 — offset is visible.
C++
struct HEXVISSTRUCT
{
    std::int8_t i8Vert { }; //Vertical offset.
    std::int8_t i8Horz { }; //Horizontal offset.
    operator bool() { return i8Vert == 0 && i8Horz == 0; }; //For test simplicity: if(IsOffsetVisible()).
};

EHexCmd

Enum of commands that can be executed within HexCtrl.

C++
enum class EHexCmd : WORD
{
    CMD_DLG_SEARCH = 0x01, CMD_SEARCH_NEXT, CMD_SEARCH_PREV,
    CMD_SHOWDATA_BYTE, CMD_SHOWDATA_WORD, CMD_SHOWDATA_DWORD, CMD_SHOWDATA_QWORD,
    CMD_BKM_ADD, CMD_BKM_REMOVE, CMD_BKM_NEXT, CMD_BKM_PREV, CMD_BKM_CLEARALL, CMD_DLG_BKM_MANAGER,
    CMD_CLIPBOARD_COPY_HEX, CMD_CLIPBOARD_COPY_HEXLE, CMD_CLIPBOARD_COPY_HEXFMT, CMD_CLIPBOARD_COPY_TEXT,
    CMD_CLIPBOARD_COPY_BASE64, CMD_CLIPBOARD_COPY_CARR, CMD_CLIPBOARD_COPY_GREPHEX, CMD_CLIPBOARD_COPY_PRNTSCRN,
    CMD_CLIPBOARD_PASTE_HEX, CMD_CLIPBOARD_PASTE_TEXT,
    CMD_DLG_MODIFY_OPERS, CMD_MODIFY_FILLZEROS, CMD_DLG_MODIFY_FILLDATA, CMD_MODIFY_UNDO, CMD_MODIFY_REDO,
    CMD_SEL_MARKSTART, CMD_SEL_MARKEND, CMD_SEL_ALL, CMD_SEL_ADDLEFT, CMD_SEL_ADDRIGHT, CMD_SEL_ADDUP, CMD_SEL_ADDDOWN,
    CMD_DLG_DATAINTERPRET, CMD_DLG_ENCODING,
    CMD_APPEARANCE_FONTINC, CMD_APPEARANCE_FONTDEC, CMD_APPEARANCE_CAPACINC, CMD_APPEARANCE_CAPACDEC,
    CMD_DLG_PRINT, CMD_DLG_ABOUT,
    CMD_CARET_LEFT, CMD_CARET_RIGHT, CMD_CARET_UP, CMD_CARET_DOWN,
    CMD_SCROLL_PAGEUP, CMD_SCROLL_PAGEDOWN, CMD_SCROLL_TOP, CMD_SCROLL_BOTTOM
};

EHexCreateMode

Enum that represents mode the HexCtrl's window will be created in.

C++
enum class EHexCreateMode : WORD
{
    CREATE_CHILD, CREATE_POPUP, CREATE_CUSTOMCTRL
};

EHexDataMode

Enum that represents current data mode HexCtrl works in. It's used as HEXDATASTRUCT member in SetData method.

C++
enum class EHexDataMode : WORD
{
    DATA_MEMORY, DATA_MSG, DATA_VIRTUAL
};

EHexGroupMode

Enum that represents available data grouping modes.

C++
enum class EHexGroupMode : WORD
{
    ASBYTE = 1, ASWORD = 2, ASDWORD = 4, ASQWORD = 8
};

EHexWnd

Enum of all HexCtrl's internal windows. This enum is used as an arg in GetWindowHandle method to retrieve window's handle.

C++
enum class EHexWnd : WORD
{
	WND_MAIN, DLG_BKMMANAGER, DLG_DATAINTERP, DLG_FILLDATA,
	DLG_OPERS, DLG_SEARCH, DLG_ENCODING, DLG_GOTO
};

Notification Messages

During its work HexCtrl sends notification messages through WM_NOTIFY mechanism to indicate its states. These messages are sent either to HEXCREATESTRUCT::hwndParent or to HEXDATASTRUCT::hwndMsg window, depending on whether the latter is set.
The LPARAM of the WM_NOTIFY message will hold pointer to the HEXNOTIFYSTRUCT.

HEXCTRL_MSG_BKMCLICK

Sent if bookmark is clicked. HEXNOTIFYSTRUCT::pData will contain HEXBKMSTRUCT pointer.

HEXCTRL_MSG_CARETCHANGE

Sent when caret position has changed. HEXNOTIFYSTRUCT::ullData will contain current caret position.

HEXCTRL_MSG_CONTEXTMENU

Sent when context menu is about to be displayed.

HEXCTRL_MSG_DESTROY

Sent to indicate that HexCtrl window is about to be destroyed.

HEXCTRL_MSG_GETDATA

Used in DATA_MSG mode to acquire the data range to display.

HEXCTRL_MSG_MENUCLICK

Sent when user defined custom menu has been clicked.
HEXNOTIFYSTRUCT ullData member contains menu ID, while point member contains position of the cursor, in screen coordinates, at the time of the mouse click.

HEXCTRL_MSG_SELECTION

Sent when selection has been made.

HEXCTRL_MSG_SETDATA

Sent to indicate that the data has changed.

HEXCTRL_MSG_VIEWCHANGE

Sent when HexCtrl's view has changed, whether on resizing or scrolling. HEXNOTIFYSTRUCT::stSpan will contain starting offset and size of the visible data.

Exported Functions

HexCtrl has few "C" interface functions which it exports when built as .dll.

CreateRawHexCtrl

C++
extern "C" HEXCTRLAPI IHexCtrl* __cdecl CreateRawHexCtrl();

Main function that creates raw IHexCtrl interface pointer. You barely need to use this function in your code.
See the IHexCtrlPtr section for more info.

GetHexCtrlInfo

C++
extern "C" HEXCTRLAPI HEXCTRLINFO* __cdecl GetHexCtrlInfo();

Returns pointer to HEXCTRLINFO, which is the HexCtrl's service information structure.

HEXCTRLINFO

Service structure for HexCtrl's version information.

C++
struct HEXCTRLINFO
{
    const wchar_t* pwszVersion { };        //WCHAR version string.
    union {
        unsigned long long ullVersion { }; //ULONGLONG version number.
        struct {
            short wMajor;
            short wMinor;
            short wMaintenance;
            short wRevision;
        }stVersion;
    };
};

Positioning and Sizing

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

C++
void CMyWnd::OnSize(UINT nType, int cx, int cy)
{
    //...
    ::SetWindowPos(m_myHex->GetWindowHandle(EHexWnd::WND_MAIN), this->m_hWnd, 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".
Briefly: It is free for any non commercial use.
https://github.com/jovibor/HexCtrl/blob/master/LICENSE

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

Comments and Discussions

 
QuestionMemory Map is a good addition Pin
Midnight48928-May-20 19:06
MemberMidnight48928-May-20 19:06 
PraiseNice work Pin
BrianCharles28-May-20 6:22
MemberBrianCharles28-May-20 6:22 
QuestionMissing information Pin
Member 1077679317-Apr-20 23:27
MemberMember 1077679317-Apr-20 23:27 
AnswerRe: Missing information Pin
Jovibor18-Apr-20 12:41
MemberJovibor18-Apr-20 12:41 
PraiseGreat article! Pin
koothkeeper17-Apr-20 10:19
professionalkoothkeeper17-Apr-20 10:19 
Praisenice work and I tested it with a memory map Pin
Midnight48920-Sep-19 17:41
MemberMidnight48920-Sep-19 17:41 
GeneralRe: nice work and I tested it with a memory map Pin
Jovibor20-Sep-19 18:51
MemberJovibor20-Sep-19 18:51 
GeneralRe: nice work and I tested it with a memory map Pin
Midnight48925-Sep-19 6:56
MemberMidnight48925-Sep-19 6:56 
QuestionHave you seen this one? Pin
Member 1019550519-Sep-19 1:51
professionalMember 1019550519-Sep-19 1:51 
QuestionNice work Pin
Nelek18-Sep-19 19:20
protectorNelek18-Sep-19 19:20 
AnswerRe: Nice work Pin
Jovibor18-Sep-19 19:29
MemberJovibor18-Sep-19 19:29 
GeneralRe: Nice work Pin
Nelek18-Sep-19 21:06
protectorNelek18-Sep-19 21:06 
PraiseMy vote of 6 Pin
User 26235214-Sep-19 1:32
MemberUser 26235214-Sep-19 1:32 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA30-Jul-19 1:44
professionalȘtefan-Mihai MOGA30-Jul-19 1:44 
This is a great inspiring article. I am pretty much pleased with your good work. You put really very helpful information. Keep it up once again.
GeneralRe: My vote of 5 Pin
Jovibor31-Jul-19 14:15
MemberJovibor31-Jul-19 14:15 
QuestionCongrats Pin
fioresoft15-Jul-19 12:56
Memberfioresoft15-Jul-19 12:56 
AnswerRe: Congrats Pin
Jovibor15-Jul-19 18:54
MemberJovibor15-Jul-19 18:54 
GeneralVery Old School Pin
Jerome Dubois13-Jun-19 2:03
MemberJerome Dubois13-Jun-19 2:03 
GeneralRe: Very Old School Pin
Rick York13-Jun-19 10:28
mveRick York13-Jun-19 10:28 
GeneralRe: Very Old School Pin
olivier gg11-Oct-19 4:23
Memberolivier gg11-Oct-19 4:23 
GeneralRe: Very Old School PinPopular
Jovibor13-Jun-19 13:15
MemberJovibor13-Jun-19 13:15 
GeneralRe: Very Old School Pin
CPallini26-Jul-19 1:58
mveCPallini26-Jul-19 1:58 
GeneralRe: Very Old School Pin
jung-kreidler6-Oct-19 21:40
Memberjung-kreidler6-Oct-19 21:40 
GeneralRe: Very Old School Pin
User 26235214-Sep-19 1:31
MemberUser 26235214-Sep-19 1:31 
GeneralRe: Very Old School Pin
Nelek18-Sep-19 19:08
protectorNelek18-Sep-19 19:08 

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.