📄 hexedit.cpp
字号:
// HexEdit.cpp : implementation file
//
#include "stdafx.h"
//#include "CommWizard.h"
#include "HexEdit.h"
#include <ctype.h>
#include <afxole.h>
#include <afxdisp.h>
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
char hextable[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
#define TOHEX(a, b) {*b++ = hextable[a >> 4];*b++ = hextable[a&0xf];}
/////////////////////////////////////////////////////////////////////////////
// CHexEdit
CHexEdit::CHexEdit()
{
#if !defined(DEMO)
m_pData = NULL; // pointer to data
m_length = 0; // length of data
#else
m_pData = (LPBYTE)malloc(0x40);
for(int i = 0; i < 0x40; i++)
m_pData[i] = i;
m_length = 0x40;
#endif
m_topindex = 0;
m_bpr = 8; // byte per row
m_lpp = 1;
m_bShowHex = TRUE;
m_bShowAscii = TRUE;
m_bShowAddress = TRUE;
m_bAddressIsWide= TRUE; // 4/8 byte address
m_offAddress = 0;
m_offHex = 0;
m_offAscii = 0;
m_bUpdate = TRUE; // update font info
m_bNoAddressChange = FALSE;
m_currentMode = EDIT_NONE;
m_editPos.x = m_editPos.y = 0;
m_currentAddress = 0;
m_bHalfPage = TRUE;
m_selStart = 0xffffffff;
m_selEnd = 0xffffffff;
m_Font.CreateFont(-12, 0,0,0,0,0,0,0,0,0,0,0,0, "Courier New");
AfxOleInit();
}
CHexEdit::~CHexEdit()
{
}
BEGIN_MESSAGE_MAP(CHexEdit, CEdit)
ON_WM_CONTEXTMENU()
//{{AFX_MSG_MAP(CHexEdit)
ON_WM_CHAR()
ON_WM_KILLFOCUS()
ON_WM_PAINT()
ON_WM_SETFOCUS()
ON_WM_VSCROLL()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_KEYDOWN()
ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
ON_COMMAND(ID_EDIT_CUT, OnEditCut)
ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDBLCLK()
ON_WM_HSCROLL()
ON_WM_CONTEXTMENU()
ON_WM_SIZE()
ON_WM_GETDLGCODE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CHexEdit message handlers
void CHexEdit::OnPaint()
{
CPaintDC pdc(this); // device context for painting
CRect rc;
GetClientRect(rc);
CDC dc;
dc.CreateCompatibleDC(CDC::FromHandle(pdc.m_ps.hdc));
CBitmap bm;
bm.CreateCompatibleBitmap(CDC::FromHandle(pdc.m_ps.hdc), rc.Width(), rc.Height());
dc.SelectObject(bm);
CBrush b;
b.CreateSolidBrush(RGB(0xff,0xff,0xff));
dc.FillRect(rc, &b);
ASSERT(m_currentAddress >= 0);
ASSERT(m_topindex >= 0);
dc.SelectObject(m_Font);
int height = 0;
int x,y;
char buf[256];
x = rc.TopLeft().x;
y = rc.TopLeft().y;
dc.SetBoundsRect(&rc, DCB_DISABLE);
if(m_pData)
{
//
// get char dimensions
//
if(m_bUpdate)
{
dc.GetCharWidth('0', '0', &m_nullWidth);
CSize sz = dc.GetTextExtent("0", 1);
m_lineHeight = sz.cy;
m_offHex = m_bShowAddress ? (m_bAddressIsWide ? m_nullWidth * 9 : m_nullWidth * 5) : 0;
m_offAscii = m_bShowAddress ? (m_bAddressIsWide ? m_nullWidth * 9 : m_nullWidth * 5) : 0;
m_offAscii += m_bShowHex ? (m_bpr * 3 * m_nullWidth) : 0;
m_lpp = rc.Height() / m_lineHeight;
m_bHalfPage = FALSE;
if(m_lpp * m_bpr > m_length)
{
m_lpp = (m_length + (m_bpr/2)) / m_bpr ;
if(m_length % m_bpr != 0)
{
m_bHalfPage = TRUE;
m_lpp++;
}
}
m_bUpdate = FALSE;
UpdateScrollbars();
}
TRACE("%i %i\n", m_topindex, m_selStart);
height = rc.Height() / m_lineHeight;
height *= m_lineHeight;
if(m_bShowAddress)
{
char fmt[8] = {'%','0','8','l','X'};
fmt[2] = m_bAddressIsWide ? '8' : '4';
int w = m_bAddressIsWide ? 8 : 4;
y = 0;
CRect rcd = rc;
rcd.TopLeft().x = m_offAddress;
for(int i = m_topindex; (i < m_length) && (rcd.TopLeft().y < height); i+= m_bpr)
{
sprintf(buf, fmt, i);
dc.DrawText(buf, w, rcd, DT_LEFT|DT_TOP|DT_SINGLELINE|DT_NOPREFIX);
rcd.TopLeft().y += m_lineHeight;
}
}
if(m_bShowHex)
{
y = 0;
CRect rcd = rc;
rcd.TopLeft().x = x = m_offHex;
if(m_selStart != 0xffffffff && (m_currentMode == EDIT_HIGH || m_currentMode == EDIT_LOW))
{
int i;
int n = 0;
int selStart = m_selStart, selEnd = m_selEnd;
if(selStart > selEnd)
selStart ^= selEnd ^= selStart ^= selEnd;
for(i = m_topindex; (i < selStart) && (y < height); i++)
{
char* p = &buf[0];
TOHEX(m_pData[i], p);
*p++ = ' ';
dc.TextOut(x, y, buf, 3);
x += m_nullWidth * 3;
n++;
if(n == m_bpr)
{
n = 0;
x = m_offHex;
y += m_lineHeight;
}
}
dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
dc.SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
for(; (i < selEnd) && (i < m_length) && (y < height); i++)
{
char* p = &buf[0];
TOHEX(m_pData[i], p);
*p++ = ' ';
dc.TextOut(x, y, buf, 3);
x += m_nullWidth * 3;
n++;
if(n == m_bpr)
{
n = 0;
x = m_offHex;
y += m_lineHeight;
}
}
dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
dc.SetBkColor(GetSysColor(COLOR_WINDOW));
for(; (i < m_length) && (y < height); i++)
{
char* p = &buf[0];
TOHEX(m_pData[i], p);
*p++ = ' ';
dc.TextOut(x, y, buf, 3);
x += m_nullWidth * 3;
n++;
if(n == m_bpr)
{
n = 0;
x = m_offHex;
y += m_lineHeight;
}
}
}
else
{
for(int i = m_topindex; (i < m_length) && (rcd.TopLeft().y < height);)
{
char* p = &buf[0];
for(int n = 0; (n < m_bpr) && (i < m_length); n++)
{
TOHEX(m_pData[i], p);
*p++ = ' ';
i++;
}
while(n < m_bpr)
{
*p++ = ' '; *p++ = ' '; *p++ = ' ';
n++;
}
dc.DrawText(buf, m_bpr*3, rcd, DT_LEFT|DT_TOP|DT_SINGLELINE|DT_NOPREFIX);
rcd.TopLeft().y += m_lineHeight;
}
}
}
if(m_bShowAscii)
{
y = 0;
CRect rcd = rc;
rcd.TopLeft().x = x = m_offAscii;
if(m_selStart != 0xffffffff && m_currentMode == EDIT_ASCII)
{
int i;
int n = 0;
int selStart = m_selStart, selEnd = m_selEnd;
if(selStart > selEnd)
selStart ^= selEnd ^= selStart ^= selEnd;
for(i = m_topindex; (i < selStart) && (y < height); i++)
{
buf[0] = isprint(m_pData[i]) ? m_pData[i] : '.';
dc.TextOut(x, y, buf, 1);
x += m_nullWidth;
n++;
if(n == m_bpr)
{
n = 0;
x = m_offAscii;
y += m_lineHeight;
}
}
dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
dc.SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
for(; (i < selEnd) && (y < height); i++)
{
buf[0] = isprint(m_pData[i]) ? m_pData[i] : '.';
dc.TextOut(x, y, buf, 1);
x += m_nullWidth;
n++;
if(n == m_bpr)
{
n = 0;
x = m_offAscii;
y += m_lineHeight;
}
}
dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
dc.SetBkColor(GetSysColor(COLOR_WINDOW));
for(; (i < m_length) && y < height; i++)
{
buf[0] = isprint(m_pData[i]) ? m_pData[i] : '.';
dc.TextOut(x, y, buf, 1);
x += m_nullWidth;
n++;
if(n == m_bpr)
{
n = 0;
x = m_offAscii;
y += m_lineHeight;
}
}
}
else
{
for(int i = m_topindex; (i < m_length) && (rcd.TopLeft().y < height);)
{
char* p = &buf[0];
for(int n = 0; (n < m_bpr) && (i < m_length); n++)
{
*p++ = isprint(m_pData[i]) ? m_pData[i] : '.';
i++;
}
dc.DrawText(buf, n, rcd, DT_LEFT|DT_TOP|DT_SINGLELINE|DT_NOPREFIX);
rcd.TopLeft().y += m_lineHeight;
}
}
}
}
pdc.BitBlt(0, 0, rc.Width(), rc.Height(), &dc, 0, 0, SRCCOPY);
}
void CHexEdit::OnSetFocus(CWnd* pOldWnd)
{
if(m_pData && !IsSelected())
{
if(m_editPos.x == 0 && m_bShowAddress)
CreateAddressCaret();
else
CreateEditCaret();
SetCaretPos(m_editPos);
ShowCaret();
}
CWnd::OnSetFocus(pOldWnd);
}
void CHexEdit::OnKillFocus(CWnd* pNewWnd)
{
DestroyCaret();
CWnd::OnKillFocus(pNewWnd);
}
//DEL void CHexEdit::OnSize(UINT nType, int cx, int cy)
//DEL {
//DEL CEdit::OnSize(nType, cx, cy);
//DEL }
void CHexEdit::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
pScrollBar;
if(!m_pData)
return;
int oa = m_topindex;
switch(nSBCode)
{
case SB_LINEDOWN:
if(m_topindex < m_length - m_lpp*m_bpr)
{
//ScrollWindow(0, -m_lineHeight, rc);
m_topindex += m_bpr;
RedrawWindow();
}
break;
case SB_LINEUP:
if(m_topindex > 0)
{
//ScrollWindow(0, m_lineHeight, rc);
m_topindex -= m_bpr;
RedrawWindow();
}
break;
case SB_PAGEDOWN:
if(m_topindex < m_length - m_lpp*m_bpr)
{
m_topindex += m_bpr * m_lpp;
if(m_topindex > m_length - m_lpp*m_bpr)
m_topindex = m_length - m_lpp*m_bpr;
RedrawWindow();
}
break;
case SB_PAGEUP:
if(m_topindex > 0)
{
m_topindex -= m_bpr * m_lpp;
if(m_topindex < 0)
m_topindex = 0;
RedrawWindow();
}
break;
case SB_THUMBTRACK:
m_topindex = nPos * m_bpr;
RedrawWindow();
break;
}
::SetScrollPos(this->m_hWnd, SB_VERT, m_topindex / m_bpr, TRUE);
if(!m_bNoAddressChange)
m_currentAddress += (m_topindex - oa);
RepositionCaret(m_currentAddress);
}
UINT CHexEdit::OnGetDlgCode()
{
return DLGC_WANTALLKEYS;
}
BOOL CHexEdit::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= WS_HSCROLL|WS_VSCROLL;
return CEdit::PreCreateWindow(cs);
}
BOOL CHexEdit::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
dwStyle |= WS_HSCROLL|WS_VSCROLL;
BOOL bRet = CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
if(bRet)
SetFont(&m_Font);
return bRet;
}
void CHexEdit::SetOptions(BOOL a, BOOL h, BOOL c, BOOL w)
{
m_bShowHex = h;
m_bShowAscii = c;
m_bShowAddress = a;
m_bAddressIsWide= w; // 4/8 byte address
m_bUpdate = TRUE;
}
void CHexEdit::SetBPR(int bpr)
{
m_bpr = bpr;
m_bUpdate = TRUE;
}
void CHexEdit::OnLButtonDown(UINT nFlags, CPoint point)
{
SetFocus();
if(!m_pData)
return;
if(nFlags & MK_SHIFT)
{
m_selStart = m_currentAddress;
}
CPoint pt = CalcPos(point.x, point.y);
if(pt.x > -1)
{
m_editPos = pt;
pt.x *= m_nullWidth;
pt.y *= m_lineHeight;
if(pt.x == 0 && m_bShowAddress)
CreateAddressCaret();
else
CreateEditCaret();
SetCaretPos(pt);
if(nFlags & MK_SHIFT)
{
m_selEnd = m_currentAddress;
if(m_currentMode == EDIT_HIGH || m_currentMode == EDIT_LOW)
m_selEnd++;
RedrawWindow();
}
}
if(!(nFlags & MK_SHIFT))
{
if(DragDetect(this->m_hWnd, point))
{
m_selStart = m_currentAddress;
m_selEnd = m_selStart;
SetCapture();
}
else
{
BOOL bsel = m_selStart != 0xffffffff;
m_selStart = 0xffffffff;
m_selEnd = 0xffffffff;
if(bsel)
RedrawWindow();
}
}
if(!IsSelected())
{
ShowCaret();
}
}
CPoint CHexEdit::CalcPos(int x, int y)
{
y /= m_lineHeight;
if(y < 0 || y > m_lpp)
return CPoint(-1, -1);
if(y * m_bpr > m_length)
return CPoint(-1, -1);
x += m_nullWidth;
x /= m_nullWidth;
int xp;
if(m_bShowAddress && x <= (m_bAddressIsWide ? 8 : 4))
{
m_currentAddress = m_topindex + (m_bpr * y);
m_currentMode = EDIT_NONE;
return CPoint(0, y);
}
xp = (m_offHex / m_nullWidth) + m_bpr * 3;
if(m_bShowHex && x < xp)
{
if(x%3)
x--;
m_currentAddress = m_topindex + (m_bpr * y) + (x - (m_offHex / m_nullWidth)) / 3;
m_currentMode = ((x%3) & 0x01) ? EDIT_LOW : EDIT_HIGH;
return CPoint(x, y);
}
xp = (m_offAscii / m_nullWidth) + m_bpr;
if(m_bShowAscii && x <= xp)
{
m_currentAddress = m_topindex + (m_bpr * y) + (x - (m_offAscii / m_nullWidth));
m_currentMode = EDIT_ASCII;
return CPoint(x, y);
}
return CPoint(-1,-1);
}
void CHexEdit::CreateAddressCaret()
{
DestroyCaret();
CreateSolidCaret(m_nullWidth * (m_bAddressIsWide ? 8 : 4), m_lineHeight);
}
void CHexEdit::CreateEditCaret()
{
DestroyCaret();
CreateSolidCaret(m_nullWidth, m_lineHeight);
}
void CHexEdit::OnMouseMove(UINT nFlags, CPoint point)
{
if(!m_pData)
return;
if(nFlags & MK_LBUTTON && m_selStart != 0xffffffff)
{
CRect rc;
GetClientRect(&rc);
if(!rc.PtInRect(point))
{
if(point.y < 0)
{
OnVScroll(SB_LINEUP, 0, NULL);
point.y = 0;
}
else if(point.y > rc.Height())
{
OnVScroll(SB_LINEDOWN, 0, NULL);
point.y = rc.Height() -1;
}
}
//
// we are selecting
//
int seo = m_selEnd;
CPoint pt = CalcPos(point.x, point.y);
if(pt.x > -1)
{
m_selEnd = m_currentAddress;
if(m_currentMode == EDIT_HIGH || m_currentMode == EDIT_LOW)
m_selEnd++;
}
if(IsSelected())
DestroyCaret();
if(seo != m_selEnd)
RedrawWindow();
}
}
void CHexEdit::UpdateScrollbars()
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL;
si.nMin = 0;
si.nMax = (m_length / m_bpr) - 1;
si.nPage = m_lpp;
si.nPos = m_topindex / m_bpr;
::SetScrollInfo(this->m_hWnd, SB_VERT, &si, TRUE);
if(si.nMax > (int)si.nPage)
::EnableScrollBar(this->m_hWnd, SB_VERT, ESB_ENABLE_BOTH);
CRect rc;
GetClientRect(&rc);
si.nMin = 0;
si.nMax =((m_bShowAddress ? (m_bAddressIsWide ? 8 : 4) : 0) +
(m_bShowHex ? m_bpr * 3 : 0) +
(m_bShowAscii ? m_bpr : 0) ) * m_nullWidth;
si.nPage = 1;
si.nPos = 0;
::SetScrollInfo(this->m_hWnd, SB_HORZ, &si, TRUE);
}
inline BOOL CHexEdit::IsSelected()
{
return m_selStart != 0xffffffff;
}
void CHexEdit::OnLButtonUp(UINT nFlags, CPoint point)
{
if(IsSelected())
ReleaseCapture();
CWnd::OnLButtonUp(nFlags, point);
}
void CHexEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
nFlags;nRepCnt;
if(!m_pData)
return;
if(nChar == '\t')
return;
if(GetKeyState(VK_CONTROL) & 0x80000000)
{
switch(nChar)
{
case 0x03:
if(IsSelected())
OnEditCopy();
return;
case 0x16:
OnEditPaste();
return;
case 0x18:
if(IsSelected())
OnEditCut();
return;
case 0x1a:
OnEditUndo();
return;
}
}
if(nChar == 0x08)
{
if(m_currentAddress > 0)
{
m_currentAddress--;
SelDelete(m_currentAddress, m_currentAddress+1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -