📄 hexeditbase.cpp
字号:
///////////////////////////////////////////////////////////////////////////
// Implementation
//-------------------------------------------------------------------------
// file........................hexeditbase.cpp
//-------------------------------------------------------------------------
// for more information check the definition file hexeditbase.h
///////////////////////////////////////////////////////////////////////////
// history:
//
// date | signature | descritpion of modification
//-----------+-----------+-------------------------------------------------
// 11.01.01 | kuendig | version 0.0.0.1
// | | - first test version
//-----------+-----------+-------------------------------------------------
// 13.01.01 | kuendig | version 0.0.0.2
// | | - context menue
// | | use OnExtendContextMenu to extend the
// | | context menue in a derived class
// | | - paste methode
// | | - Windows-Class registering
// | | - CHexEditBase: for use with DDX / Edit-Control
// | | - CHexEditBase_SC: when not using DDX
// | | - several small changes
//-----------+-----------+-------------------------------------------------
// 19.01.01 | kuendig | version 0.0.0.3
// | | - bug in CreateHighlightingPolygons
// | | (when scrolling highlighting out of window on
// | | top, sometimes the address got overpainted
// | | by some parts of the highlighting section)
//-----------+-----------+-------------------------------------------------
// 04.02.01 | kuendig | version 1.0.0.0 (official release)
// | | - MakeVisible is now smarter
// | | - SetFont, GetFont WM_SETFONT, WM_GETFONT works now
//-----------+-----------+-------------------------------------------------
// 24.05.01 | kuendig | version 1.1.0.0
// | | - Fixed the 16Bit Scrollrange limitation when
// | | thumbtracking (see OnVScroll)
// | | - Modified SetFont to only accept fixed-pitched
// | | fonts
// | | - Replaced some GetSafeHwnd() with
// | | ::IsWindow(m_hWnd), since it's rather what's
// | | beeing checked. (Even when GetSafeHwnd worked
// | | in most of the cases)
// | | - Call DestroyWnd from the Destructor, to get
// | | rid of the TRACE from "CWnd::~CWnd ..."
//-----------+-----------+-------------------------------------------------
// --.--.-- | |
//-----------+-----------+-------------------------------------------------
// --.--.-- | |
//-----------+-----------+-------------------------------------------------
// --.--.-- | |
//-----------+-----------+-------------------------------------------------
// --.--.-- | |
//-----------+-----------+-------------------------------------------------
// --.--.-- | |
//-----------+-----------+-------------------------------------------------
// --.--.-- | |
//-----------+-----------+-------------------------------------------------
///////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// includes
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <memory>
#include <afxole.h>
#include "HexEditBase.h"
/////////////////////////////////////////////////////////////////////////////
// defines
/////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// control-layout customization (low-level)
#define ADR_DATA_SPACE 5
#define DATA_ASCII_SPACE 5
#define CONTROL_BORDER_SPACE 5
// boundaries and special values
#define MAX_HIGHLIGHT_POLYPOINTS 8
#define UM_SETSCROLRANGE (WM_USER + 0x5000)
#define MOUSEREP_TIMER_TID 0x400
#define MOUSEREP_TIMER_ELAPSE 0x5
// clipboard format
#define CF_BINDATA_HEXCTRL _T("BinaryData")
// windows-class-name
#define HEXEDITBASECTRL_CLASSNAME _T("CHexEditBase")
#define HEXEDITBASECTRL_CLSNAME_SC _T("CHexEditBase_SC") //self creating
// macros
#define NORMALIZE_SELECTION(beg, end) if(beg>end){UINT tmp = end; end=beg; beg=tmp; }
/////////////////////////////////////////////////////////////////////////////
// global data
/////////////////////////////////////////////////////////////////////////////
const char tabHexCharacters[16] = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// class CHexEditBase
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CHexEditBase, CWnd)
BEGIN_MESSAGE_MAP(CHexEditBase, CWnd)
//{{AFX_MSG_MAP(CHexEditBase)
ON_MESSAGE(UM_SETSCROLRANGE, OnUmSetScrollRange)
ON_MESSAGE(WM_CHAR, OnWMChar)
ON_MESSAGE(WM_SETFONT, OnWMSetFont)
ON_MESSAGE(WM_GETFONT, OnWMGetFont)
ON_WM_DESTROY()
ON_WM_TIMER()
ON_WM_KILLFOCUS()
ON_WM_PAINT()
ON_WM_SETFOCUS()
ON_WM_SIZE()
ON_WM_VSCROLL()
ON_WM_HSCROLL()
ON_WM_GETDLGCODE()
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONDBLCLK()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_KEYDOWN()
ON_WM_MOUSEWHEEL()
ON_WM_CONTEXTMENU()
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
CHexEditBase::CHexEditBase() :
m_bSelfCleanup(false),
m_bDeleteData(true),
m_pData(NULL),
m_nLength(0),
m_nAdrSize(8),
m_nBytesPerRow(16),
m_nCurCaretWidth(0),
m_nCurCaretHeight(0),
m_bHasCaret(false),
m_bHighBits(true),
m_bReadOnly(false),
m_nHighlightedBegin(NOSECTION_VAL),
m_nHighlightedEnd(NOSECTION_VAL),
m_nSelectingBeg(NOSECTION_VAL),
m_nSelectingEnd(NOSECTION_VAL),
m_nSelectionBegin(NOSECTION_VAL),
m_nSelectionEnd(NOSECTION_VAL),
m_tAdrBkgCol(RGB(90,0,0)),
m_tAdrTxtCol(RGB(255,0,0)),
m_tAsciiBkgCol(RGB(0,20,0)),
m_tAsciiTxtCol(RGB(0,255,0)),
m_tHighlightBkgCol(RGB(0,90,210)),
m_tHighlightTxtCol(RGB(0,200,0)),
m_tHighlightFrameCol(RGB(0,255,255)),
m_tHexTxtCol(RGB(0,0,255)),
m_tHexBkgCol(RGB(180,210,190)),
m_tNotUsedBkCol(RGB(210,210,210)),
m_nCurrentAddress(0),
m_bAutoBytesPerRow(false),
m_bRecalc(true),
m_nScrollPostionX(0),
m_nScrollRangeX(0),
m_nScrollPostionY(0),
m_nScrollRangeY(0),
m_bShowAscii(false),
m_bInputAscii(false),
m_bShowAddress(false),
m_bShowCategory(false),
m_nMouseRepSpeed(0),
m_iMouseRepDelta(0),
m_nMouseRepCounter(0),
m_bIsMouseRepActive(false),
m_cDragRect(0,0,0,0),
m_cContextCopy("Copy"),
m_cContextPaste("Paste")
{
memset(&m_tPaintDetails, 0, sizeof(PAINTINGDETAILS));
m_tSelectedNoFocusTxtCol = GetSysColor(COLOR_WINDOWTEXT);
m_tSelectedNoFocusBkgCol = GetSysColor(COLOR_BTNFACE);
m_tSelectedFousTxtCol = GetSysColor(COLOR_HIGHLIGHTTEXT);
m_tSelectedFousBkgCol = GetSysColor(COLOR_HIGHLIGHT);
if(!m_cFont.CreateStockObject(ANSI_FIXED_FONT)) {
AfxThrowResourceException();
}
// register clipboard format
m_nBinDataClipboardFormat = RegisterClipboardFormat(CF_BINDATA_HEXCTRL);
ASSERT(m_nBinDataClipboardFormat != 0);
// try to load strings from the resources
#ifdef IDS_CONTROL_COPY
if(!m_cContextCopy.LoadString(IDS_CONTROL_COPY)) {
cString = _T("Copy");
}
#endif
#ifdef IDS_CONTROL_PASTE
if(!m_cContextPaste.LoadString(IDS_CONTROL_PASTE)) {
cString = _T("Paste");
}
#endif
// register windows-class
RegisterClass();
}
CHexEditBase::~CHexEditBase()
{
if(m_bDeleteData) {
delete []m_pData;
}
if(m_cFont.m_hObject != NULL) {
m_cFont.DeleteObject();
}
if(::IsWindow(m_hWnd)) {
DestroyWindow();
}
}
BOOL CHexEditBase::Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
return CWnd::Create(HEXEDITBASECTRL_CLASSNAME, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}
BOOL CHexEditBase::CreateEx(DWORD dwExStyle, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hwndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
return CWnd::CreateEx(dwExStyle, HEXEDITBASECTRL_CLASSNAME, lpszWindowName, dwStyle, x, y, nWidth, nHeight, hwndParent, nIDorHMenu, lpParam);
}
BOOL CHexEditBase::CreateEx(DWORD dwExStyle, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, LPVOID lpParam)
{
return CWnd::CreateEx(dwExStyle, HEXEDITBASECTRL_CLASSNAME, lpszWindowName, dwStyle, rect, pParentWnd, nID, lpParam);
}
void CHexEditBase::RegisterClass()
{
// register windowsclass
WNDCLASS tWndClass;
if(!::GetClassInfo(AfxGetInstanceHandle(), HEXEDITBASECTRL_CLASSNAME, &tWndClass))
{
memset(&tWndClass, 0, sizeof(WNDCLASS));
tWndClass.style = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
tWndClass.lpfnWndProc = ::DefWindowProc;
tWndClass.hInstance = AfxGetInstanceHandle();
tWndClass.hCursor = ::LoadCursor(NULL, IDC_IBEAM);
tWndClass.lpszClassName = HEXEDITBASECTRL_CLASSNAME;
if(!AfxRegisterClass(&tWndClass)) {
AfxThrowResourceException();
}
}
if(!::GetClassInfo(AfxGetInstanceHandle(), HEXEDITBASECTRL_CLSNAME_SC, &tWndClass))
{
memset(&tWndClass, 0, sizeof(WNDCLASS));
tWndClass.style = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
tWndClass.lpfnWndProc = CHexEditBase::WndProc;
tWndClass.hInstance = AfxGetInstanceHandle();
tWndClass.hCursor = ::LoadCursor(NULL, IDC_IBEAM);
tWndClass.lpszClassName = HEXEDITBASECTRL_CLSNAME_SC;
if(!AfxRegisterClass(&tWndClass)) {
AfxThrowResourceException();
}
}
}
LRESULT CALLBACK CHexEditBase::WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
if(nMsg == WM_NCCREATE) {
ASSERT(FromHandlePermanent(hWnd) == NULL );
CHexEditBase* pControl = NULL;
try {
pControl = new CHexEditBase();
pControl->m_bSelfCleanup = true;
} catch(...) {
return FALSE;
}
if(pControl == NULL) {
return FALSE;
}
if(!pControl->SubclassWindow(hWnd)) {
TRACE("CHexEditBase::WndProc: ERROR: couldn't subclass window (WM_NCCREATE)\n");
delete pControl;
return FALSE;
}
return TRUE;
}
return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
}
void CHexEditBase::NotifyParent(WORD wNBotifictionCode)
{
CWnd *pWnd = GetParent();
if(pWnd != NULL) {
pWnd->SendMessage(WM_COMMAND, MAKEWPARAM((WORD)GetDlgCtrlID(), wNBotifictionCode), (LPARAM)m_hWnd);
}
}
void CHexEditBase::PostNcDestroy()
{
if(m_bSelfCleanup) {
m_bSelfCleanup = false;
delete this;
}
}
void CHexEditBase::OnDestroy()
{
CWnd::OnDestroy();
}
void CHexEditBase::CalculatePaintingDetails(CDC& cDC)
{
ASSERT(m_nScrollPostionY >= 0);
CFont *pOldFont;
m_bRecalc = false;
// Get size information
int iWidth;
pOldFont = cDC.SelectObject(&m_cFont);
cDC.GetCharWidth('0', '0', &iWidth);
ASSERT(iWidth > 0);
m_tPaintDetails.nCharacterWidth = iWidth;
CSize cSize = cDC.GetTextExtent("0", 1);
ASSERT(cSize.cy > 0);
m_tPaintDetails.nLineHeight = cSize.cy;
// count of visible lines
GetClientRect(m_tPaintDetails.cPaintingRect);
if(GetStyle() & ES_MULTILINE) {
m_tPaintDetails.cPaintingRect.InflateRect(-CONTROL_BORDER_SPACE, -CONTROL_BORDER_SPACE,
-CONTROL_BORDER_SPACE, -CONTROL_BORDER_SPACE);
if(m_tPaintDetails.cPaintingRect.right < m_tPaintDetails.cPaintingRect.left) {
m_tPaintDetails.cPaintingRect.right = m_tPaintDetails.cPaintingRect.left;
}
if(m_tPaintDetails.cPaintingRect.bottom < m_tPaintDetails.cPaintingRect.top) {
m_tPaintDetails.cPaintingRect.bottom = m_tPaintDetails.cPaintingRect.top;
}
}
m_tPaintDetails.nVisibleLines = m_tPaintDetails.cPaintingRect.Height() / m_tPaintDetails.nLineHeight;
m_tPaintDetails.nLastLineHeight = m_tPaintDetails.cPaintingRect.Height() % m_tPaintDetails.nLineHeight;
if(m_tPaintDetails.nLastLineHeight > 0) {
m_tPaintDetails.nFullVisibleLines = m_tPaintDetails.nVisibleLines;
m_tPaintDetails.nVisibleLines++;
} else {
m_tPaintDetails.nFullVisibleLines = m_tPaintDetails.nVisibleLines;
m_tPaintDetails.nLastLineHeight = m_tPaintDetails.nLineHeight;
}
// position & size of the address
if(m_bShowAddress) {
m_tPaintDetails.nAddressPos = 0;
m_tPaintDetails.nAddressLen = ADR_DATA_SPACE + m_tPaintDetails.nCharacterWidth*m_nAdrSize;
} else {
m_tPaintDetails.nAddressPos = 0;
m_tPaintDetails.nAddressLen = 0;
}
// Calculate how many bytes per line we can display, when this is automatically calculated
if(m_bAutoBytesPerRow && GetStyle() & ES_MULTILINE) {
int iFreeSpace = m_tPaintDetails.cPaintingRect.Width() - m_tPaintDetails.nAddressLen;
if(m_bShowAscii) {
iFreeSpace -= DATA_ASCII_SPACE;
if(iFreeSpace < 0) {
m_tPaintDetails.nBytesPerRow = 1;
} else {
m_tPaintDetails.nBytesPerRow = iFreeSpace / (4*m_tPaintDetails.nCharacterWidth) ; // 2(HEXDATA)+1(Space)+1(Ascii) = 4
if( (iFreeSpace%(4*m_tPaintDetails.nCharacterWidth)) >= (3*m_tPaintDetails.nCharacterWidth) ) {
m_tPaintDetails.nBytesPerRow++; // we actually only need n-1 spaces not n (n = nBytesPerRow)
}
}
} else {
if(iFreeSpace < 0) {
m_tPaintDetails.nBytesPerRow = 1;
} else {
m_tPaintDetails.nBytesPerRow = iFreeSpace / (3*m_tPaintDetails.nCharacterWidth) ; // 2(HEXDATA)+1(Space) = 3
if( (iFreeSpace%(3*m_tPaintDetails.nCharacterWidth)) >= (2*m_tPaintDetails.nCharacterWidth) ) {
m_tPaintDetails.nBytesPerRow++; // we actually only need n-1 spaces not n (n = nBytesPerRow)
}
}
}
//remark: m_nBytesPerRow=0 is a valid thing... (not very lucky thing, but valid)
} else {
m_tPaintDetails.nBytesPerRow = m_nBytesPerRow;
}
if(!(GetStyle() & ES_MULTILINE)) {
m_tPaintDetails.nBytesPerRow = m_nLength;
}
if(m_tPaintDetails.nBytesPerRow == 0) {
m_tPaintDetails.nBytesPerRow = 1;
}
// position & size of the hex-data
m_tPaintDetails.nHexPos = m_tPaintDetails.nAddressPos + m_tPaintDetails.nAddressLen;
m_tPaintDetails.nHexLen = (m_tPaintDetails.nBytesPerRow*2 + m_tPaintDetails.nBytesPerRow-1)*m_tPaintDetails.nCharacterWidth;
//2(HEXData) + 1(Space) (only n-1 spaces needed)
iWidth = m_tPaintDetails.nHexPos + m_tPaintDetails.nHexLen;
m_tPaintDetails.nHexLen += DATA_ASCII_SPACE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -