rlm@1: // MemoryViewer.cpp : implementation file rlm@1: // rlm@1: rlm@1: #include "stdafx.h" rlm@1: #include "resource.h" rlm@1: #include "MemoryViewer.h" rlm@1: rlm@1: extern int emulating; rlm@1: rlm@1: ///////////////////////////////////////////////////////////////////////////// rlm@1: // MemoryViewer rlm@1: rlm@1: bool MemoryViewer::isRegistered = false; rlm@1: rlm@1: MemoryViewer::MemoryViewer() rlm@1: { rlm@1: address = 0; rlm@1: addressSize = 0; rlm@1: dataSize = 0; rlm@1: editAddress = 0; rlm@1: editNibble = 0; rlm@1: displayedLines = 0; rlm@1: hasCaret = false; rlm@1: maxNibble = 0; rlm@1: font = (HFONT)GetStockObject(SYSTEM_FIXED_FONT); rlm@1: fontSize.cx = fontSize.cy = 0; rlm@1: beginAscii = 0; rlm@1: beginHex = 0; rlm@1: dlg = NULL; rlm@1: registerClass(); rlm@1: } rlm@1: rlm@1: MemoryViewer::~MemoryViewer() rlm@1: {} rlm@1: rlm@1: BEGIN_MESSAGE_MAP(MemoryViewer, CWnd) rlm@1: //{{AFX_MSG_MAP(MemoryViewer) rlm@1: ON_WM_ERASEBKGND() rlm@1: ON_WM_PAINT() rlm@1: ON_WM_VSCROLL() rlm@1: ON_WM_GETDLGCODE() rlm@1: ON_WM_LBUTTONDOWN() rlm@1: ON_WM_SETFOCUS() rlm@1: ON_WM_KILLFOCUS() rlm@1: ON_WM_KEYDOWN() rlm@1: //}}AFX_MSG_MAP rlm@1: ON_MESSAGE(WM_CHAR, OnWMChar) rlm@1: END_MESSAGE_MAP() rlm@1: rlm@1: ///////////////////////////////////////////////////////////////////////////// rlm@1: // MemoryViewer message handlers rlm@1: rlm@1: void MemoryViewer::setDialog(IMemoryViewerDlg *d) rlm@1: { rlm@1: dlg = d; rlm@1: } rlm@1: rlm@1: void MemoryViewer::setAddress(u32 a) rlm@1: { rlm@1: address = a; rlm@1: if (displayedLines) rlm@1: { rlm@1: if (addressSize) rlm@1: { rlm@1: u16 addr = address; rlm@1: if ((u16)((addr+(displayedLines<<4)) & 0xFFFF) < addr) rlm@1: { rlm@1: address = 0xffff - (displayedLines<<4) + 1; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if ((address+(displayedLines<<4)) < address) rlm@1: { rlm@1: address = 0xffffffff - (displayedLines<<4) + 1; rlm@1: } rlm@1: } rlm@1: } rlm@1: if (addressSize) rlm@1: address &= 0xffff; rlm@1: setCaretPos(); rlm@1: InvalidateRect(NULL, TRUE); rlm@1: } rlm@1: rlm@1: void MemoryViewer::setSize(int s) rlm@1: { rlm@1: dataSize = s; rlm@1: if (s == 0) rlm@1: maxNibble = 1; rlm@1: else if (s == 1) rlm@1: maxNibble = 3; rlm@1: else rlm@1: maxNibble = 7; rlm@1: rlm@1: InvalidateRect(NULL, TRUE); rlm@1: } rlm@1: rlm@1: void MemoryViewer::setDecimal(bool decimalDisplayMode) rlm@1: { rlm@1: decimalDisplay = decimalDisplayMode; rlm@1: InvalidateRect(NULL, TRUE); rlm@1: } rlm@1: rlm@1: BOOL MemoryViewer::OnEraseBkgnd(CDC*pDC) rlm@1: { rlm@1: return TRUE; rlm@1: } rlm@1: rlm@1: void MemoryViewer::updateScrollInfo(int lines) rlm@1: { rlm@1: int page = lines * 16; rlm@1: SCROLLINFO si; rlm@1: ZeroMemory(&si, sizeof(si)); rlm@1: si.cbSize = sizeof(si); rlm@1: si.fMask = SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL | SIF_POS; rlm@1: si.nMin = 0; rlm@1: if (addressSize) rlm@1: { rlm@1: si.nMax = 0x10000/page; rlm@1: si.nPage = 1; rlm@1: } rlm@1: else rlm@1: { rlm@1: si.nMax = 0xa000000 / page; rlm@1: si.nPage = page; rlm@1: } rlm@1: rlm@1: si.nPos = address / page; rlm@1: SetScrollInfo(SB_VERT, rlm@1: &si, rlm@1: TRUE); rlm@1: } rlm@1: rlm@1: void MemoryViewer::OnPaint() rlm@1: { rlm@1: CPaintDC dc(this); // device context for painting rlm@1: rlm@1: RECT rect; rlm@1: GetClientRect(&rect); rlm@1: int w = rect.right - rect.left; rlm@1: int h = rect.bottom - rect.top - 6; rlm@1: rlm@1: CDC memDC; rlm@1: memDC.CreateCompatibleDC(&dc); rlm@1: CBitmap bitmap, *pOldBitmap; rlm@1: bitmap.CreateCompatibleBitmap(&dc, w, rect.bottom - rect.top); rlm@1: pOldBitmap = memDC.SelectObject(&bitmap); rlm@1: rlm@1: memDC.FillRect(&rect, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH))); rlm@1: memDC.DrawEdge(&rect, EDGE_ETCHED, BF_RECT); rlm@1: rlm@1: CFont *oldFont = memDC.SelectObject(CFont::FromHandle(font)); rlm@1: rlm@1: fontSize = memDC.GetTextExtent("0", 1); rlm@1: rlm@1: int lines = h / fontSize.cy; rlm@1: rlm@1: displayedLines = lines; rlm@1: rlm@1: updateScrollInfo(lines); rlm@1: rlm@1: u32 addr = address; rlm@1: rlm@1: memDC.SetTextColor(RGB(0, 0, 0)); rlm@1: rlm@1: u8 data[32]; rlm@1: rlm@1: RECT r; rlm@1: r.top = 3; rlm@1: r.left = 3; rlm@1: r.bottom = r.top+fontSize.cy; rlm@1: r.right = rect.right-3; rlm@1: rlm@1: int line = 0; rlm@1: rlm@1: for (int i = 0; i < lines; i++) rlm@1: { rlm@1: CString buffer; rlm@1: if (addressSize) rlm@1: buffer.Format("%04X", addr); rlm@1: else rlm@1: buffer.Format("%08X", addr); rlm@1: memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX); rlm@1: r.left += 10*fontSize.cx; rlm@1: beginHex = r.left; rlm@1: readData(addr, 16, data); rlm@1: rlm@1: int j; rlm@1: rlm@1: if (dataSize == 0) rlm@1: { rlm@1: for (j = 0; j < 16; j++) rlm@1: { rlm@1: const int nextRLeft = r.left + 3*fontSize.cx; rlm@1: if (!decimalDisplay) rlm@1: buffer.Format("%02X", data[j]); rlm@1: else rlm@1: { rlm@1: const signed char num = data[j]; rlm@1: if (num < -9 || num > 99) rlm@1: r.left -= fontSize.cx; rlm@1: if (num >= -99 && num <= 99) rlm@1: buffer.Format("%2d", num); rlm@1: else rlm@1: buffer.Format(""); rlm@1: } rlm@1: memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX); rlm@1: r.left = nextRLeft; rlm@1: } rlm@1: } rlm@1: if (dataSize == 1) rlm@1: { rlm@1: for (j = 0; j < 16; j += 2) rlm@1: { rlm@1: const int nextRLeft = r.left + 5*fontSize.cx; rlm@1: if (!decimalDisplay) rlm@1: buffer.Format("%04X", data[j] | data[j+1]<<8); rlm@1: else rlm@1: { rlm@1: const signed short num = data[j] | data[j+1]<<8; rlm@1: if (num < -999 || num > 9999) rlm@1: r.left -= fontSize.cx; rlm@1: if (num >= -9999 && num <= 9999) rlm@1: buffer.Format("%4d", num); rlm@1: else rlm@1: buffer.Format(""); rlm@1: } rlm@1: memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX); rlm@1: r.left = nextRLeft; rlm@1: } rlm@1: } rlm@1: if (dataSize == 2) rlm@1: { rlm@1: for (j = 0; j < 16; j += 4) rlm@1: { rlm@1: if (!decimalDisplay) rlm@1: buffer.Format("%08X", data[j] | data[j+1]<<8 | data[j+2] << 16 | data[j+3] << 24); rlm@1: else rlm@1: { rlm@1: const signed long num = data[j] | data[j+1]<<8 | data[j+2] << 16 | data[j+3] << 24; rlm@1: if (num >= -9999999 && num <= 99999999) rlm@1: buffer.Format("%8d", num); rlm@1: else rlm@1: buffer.Format(""); rlm@1: } rlm@1: memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX); rlm@1: r.left += 9*fontSize.cx; rlm@1: } rlm@1: } rlm@1: rlm@1: line = r.left; rlm@1: rlm@1: r.left += fontSize.cx; rlm@1: beginAscii = r.left; rlm@1: buffer.Empty(); rlm@1: for (j = 0; j < 16; j++) rlm@1: { rlm@1: char c = data[j]; rlm@1: if (c >= 32 && c <= 127) rlm@1: { rlm@1: buffer += c; rlm@1: } rlm@1: else rlm@1: buffer += '.'; rlm@1: } rlm@1: rlm@1: memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX); rlm@1: addr += 16; rlm@1: if (addressSize) rlm@1: addr &= 0xffff; rlm@1: r.top += fontSize.cy; rlm@1: r.bottom += fontSize.cy; rlm@1: r.left = 3; rlm@1: } rlm@1: CPen pen; rlm@1: pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); rlm@1: CPen *old = memDC.SelectObject(&pen); rlm@1: rlm@1: memDC.MoveTo(3+fontSize.cx*9, 3); rlm@1: memDC.LineTo(3+fontSize.cx*9, 3+displayedLines*fontSize.cy); rlm@1: rlm@1: memDC.MoveTo(line, 3); rlm@1: memDC.LineTo(line, 3+displayedLines*fontSize.cy); rlm@1: rlm@1: memDC.SelectObject(old); rlm@1: pen.DeleteObject(); rlm@1: rlm@1: memDC.SelectObject(oldFont); rlm@1: rlm@1: dc.BitBlt(0, 0, w, rect.bottom - rect.top, &memDC, 0, 0, SRCCOPY); rlm@1: rlm@1: memDC.SelectObject(pOldBitmap); rlm@1: memDC.DeleteDC(); rlm@1: bitmap.DeleteObject(); rlm@1: } rlm@1: rlm@1: void MemoryViewer::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*pScrollBar) rlm@1: { rlm@1: int address = this->address; rlm@1: switch (nSBCode) rlm@1: { rlm@1: case SB_BOTTOM: rlm@1: address = 0xffffff00; rlm@1: break; rlm@1: case SB_LINEDOWN: rlm@1: address += 0x10; rlm@1: break; rlm@1: case SB_LINEUP: rlm@1: address -= 0x10; rlm@1: break; rlm@1: case SB_PAGEDOWN: rlm@1: address += (displayedLines<<4); rlm@1: break; rlm@1: case SB_PAGEUP: rlm@1: address -= (displayedLines<<4); rlm@1: break; rlm@1: case SB_TOP: rlm@1: address = 0; rlm@1: break; rlm@1: case SB_THUMBTRACK: rlm@1: { rlm@1: int page = displayedLines * 16; rlm@1: SCROLLINFO si; rlm@1: ZeroMemory(&si, sizeof(si)); rlm@1: si.cbSize = sizeof(si); rlm@1: si.fMask = SIF_TRACKPOS; rlm@1: GetScrollInfo(SB_VERT, &si); rlm@1: address = page * si.nTrackPos; rlm@1: break; rlm@1: } rlm@1: } rlm@1: setAddress(address); rlm@1: } rlm@1: rlm@1: UINT MemoryViewer::OnGetDlgCode() rlm@1: { rlm@1: return DLGC_WANTALLKEYS; rlm@1: } rlm@1: rlm@1: void MemoryViewer::createEditCaret(int w, int h) rlm@1: { rlm@1: if (!hasCaret || caretWidth != w || caretHeight != h) rlm@1: { rlm@1: hasCaret = true; rlm@1: caretWidth = w; rlm@1: caretHeight = h; rlm@1: ::CreateCaret(m_hWnd, (HBITMAP)0, w, h); rlm@1: } rlm@1: } rlm@1: rlm@1: void MemoryViewer::destroyEditCaret() rlm@1: { rlm@1: hasCaret = false; rlm@1: DestroyCaret(); rlm@1: } rlm@1: rlm@1: void MemoryViewer::setCaretPos() rlm@1: { rlm@1: if (GetFocus() != this) rlm@1: { rlm@1: destroyEditCaret(); rlm@1: return; rlm@1: } rlm@1: rlm@1: if (dlg) rlm@1: dlg->setCurrentAddress(editAddress); rlm@1: rlm@1: if (editAddress < address || editAddress > (address -1 + (displayedLines<<4))) rlm@1: { rlm@1: destroyEditCaret(); rlm@1: return; rlm@1: } rlm@1: rlm@1: int subAddress = (editAddress - address); rlm@1: rlm@1: int x = 3+10*fontSize.cx+editNibble*fontSize.cx; rlm@1: int y = 3+fontSize.cy*((editAddress-address)>>4); rlm@1: rlm@1: if (editAscii) rlm@1: { rlm@1: x = beginAscii + fontSize.cx*(subAddress&15); rlm@1: } rlm@1: else rlm@1: { rlm@1: switch (dataSize) rlm@1: { rlm@1: case 0: rlm@1: x += 3*fontSize.cx*(subAddress & 15); rlm@1: break; rlm@1: case 1: rlm@1: x += 5*fontSize.cx*((subAddress>>1) & 7); rlm@1: break; rlm@1: case 2: rlm@1: x += 9*fontSize.cx*((subAddress>>2) & 3); rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: RECT r; rlm@1: GetClientRect(&r); rlm@1: r.right -= 3; rlm@1: if (x >= r.right) rlm@1: { rlm@1: destroyEditCaret(); rlm@1: return; rlm@1: } rlm@1: int w = fontSize.cx; rlm@1: if ((x+fontSize.cx) >= r.right) rlm@1: w = r.right - x; rlm@1: createEditCaret(w, fontSize.cy); rlm@1: ::SetCaretPos(x, y); rlm@1: ShowCaret(); rlm@1: } rlm@1: rlm@1: void MemoryViewer::OnLButtonDown(UINT nFlags, CPoint point) rlm@1: { rlm@1: int x = point.x; rlm@1: int y = point.y; rlm@1: int line = (y-3)/fontSize.cy; rlm@1: int beforeAscii = beginHex; rlm@1: int inc = 1; rlm@1: int sub = 3*fontSize.cx; rlm@1: switch (dataSize) rlm@1: { rlm@1: case 0: rlm@1: beforeAscii += 47*fontSize.cx; rlm@1: break; rlm@1: case 1: rlm@1: beforeAscii += 39*fontSize.cx; rlm@1: inc = 2; rlm@1: sub = 5*fontSize.cx; rlm@1: break; rlm@1: case 2: rlm@1: beforeAscii += 35*fontSize.cx; rlm@1: inc = 4; rlm@1: sub = 9*fontSize.cx; rlm@1: break; rlm@1: } rlm@1: rlm@1: editAddress = address + (line<<4); rlm@1: if (x >= beginHex && x < beforeAscii) rlm@1: { rlm@1: x -= beginHex; rlm@1: editNibble = 0; rlm@1: while (x > 0) rlm@1: { rlm@1: x -= sub; rlm@1: if (x >= 0) rlm@1: editAddress += inc; rlm@1: else rlm@1: { rlm@1: editNibble = (x + sub)/fontSize.cx; rlm@1: } rlm@1: } rlm@1: editAscii = false; rlm@1: } rlm@1: else if (x >= beginAscii) rlm@1: { rlm@1: int afterAscii = beginAscii+16*fontSize.cx; rlm@1: if (x >= afterAscii) rlm@1: x = afterAscii-1; rlm@1: editAddress += (x-beginAscii)/fontSize.cx; rlm@1: editNibble = 0; rlm@1: editAscii = true; rlm@1: } rlm@1: else rlm@1: { rlm@1: return; rlm@1: } rlm@1: rlm@1: if (editNibble > maxNibble) rlm@1: editNibble = maxNibble; rlm@1: SetFocus(); rlm@1: setCaretPos(); rlm@1: } rlm@1: rlm@1: void MemoryViewer::OnSetFocus(CWnd*pOldWnd) rlm@1: { rlm@1: setCaretPos(); rlm@1: InvalidateRect(NULL, TRUE); rlm@1: } rlm@1: rlm@1: void MemoryViewer::OnKillFocus(CWnd*pNewWnd) rlm@1: { rlm@1: destroyEditCaret(); rlm@1: InvalidateRect(NULL, TRUE); rlm@1: } rlm@1: rlm@1: void MemoryViewer::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) rlm@1: { rlm@1: bool isShift = (GetKeyState(VK_SHIFT) & 0x80000000) == 0x80000000; rlm@1: rlm@1: switch (nChar) rlm@1: { rlm@1: case VK_RIGHT: rlm@1: if (editAscii) rlm@1: moveAddress(1, 0); rlm@1: else if (isShift) rlm@1: moveAddress((maxNibble+1)>>1, 0); rlm@1: else rlm@1: moveAddress(0, 1); rlm@1: break; rlm@1: case VK_LEFT: rlm@1: if (editAscii) rlm@1: moveAddress(-1, 0); rlm@1: else if (isShift) rlm@1: moveAddress(-((maxNibble+1)>>1), 0); rlm@1: else rlm@1: moveAddress(0, -1); rlm@1: break; rlm@1: case VK_DOWN: rlm@1: moveAddress(16, 0); rlm@1: break; rlm@1: case VK_UP: rlm@1: moveAddress(-16, 0); rlm@1: break; rlm@1: case VK_TAB: rlm@1: GetNextDlgTabItem(GetParent(), isShift)->SetFocus(); rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: void MemoryViewer::moveAddress(s32 offset, int nibbleOff) rlm@1: { rlm@1: if (offset == 0) rlm@1: { rlm@1: if (nibbleOff == -1) rlm@1: { rlm@1: editNibble--; rlm@1: if (editNibble == -1) rlm@1: { rlm@1: editAddress -= (maxNibble + 1) >> 1; rlm@1: editNibble = maxNibble; rlm@1: } rlm@1: if (address == 0 && (editAddress >= (u32)(displayedLines<<4))) rlm@1: { rlm@1: editAddress = 0; rlm@1: editNibble = 0; rlm@1: beep(); rlm@1: } rlm@1: if (editAddress < address) rlm@1: setAddress(address - 16); rlm@1: } rlm@1: else rlm@1: { rlm@1: editNibble++; rlm@1: if (editNibble > maxNibble) rlm@1: { rlm@1: editNibble = 0; rlm@1: editAddress += (maxNibble + 1) >> 1; rlm@1: } rlm@1: if (editAddress < address) rlm@1: { rlm@1: editAddress -= (maxNibble + 1) >> 1; rlm@1: editNibble = maxNibble; rlm@1: beep(); rlm@1: } rlm@1: if (editAddress >= (address+(displayedLines<<4))) rlm@1: setAddress(address+16); rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: editAddress += offset; rlm@1: if (offset < 0 && editAddress > (address-1+(displayedLines<<4))) rlm@1: { rlm@1: editAddress -= offset; rlm@1: beep(); rlm@1: return; rlm@1: } rlm@1: if (offset > 0 && (editAddress < address)) rlm@1: { rlm@1: editAddress -= offset; rlm@1: beep(); rlm@1: return; rlm@1: } rlm@1: if (editAddress < address) rlm@1: { rlm@1: if (offset & 15) rlm@1: setAddress((address+offset-16) & ~15); rlm@1: else rlm@1: setAddress(address+offset); rlm@1: } rlm@1: else if (editAddress > (address - 1 + (displayedLines<<4))) rlm@1: { rlm@1: if (offset & 15) rlm@1: setAddress((address+offset+16) & ~15); rlm@1: else rlm@1: setAddress(address+offset); rlm@1: } rlm@1: } rlm@1: rlm@1: setCaretPos(); rlm@1: } rlm@1: rlm@1: LRESULT MemoryViewer::OnWMChar(WPARAM wParam, LPARAM LPARAM) rlm@1: { rlm@1: if (OnEditInput(wParam)) rlm@1: return 0; rlm@1: return 1; rlm@1: } rlm@1: rlm@1: bool MemoryViewer::OnEditInput(UINT c) rlm@1: { rlm@1: if (c > 255 || !emulating) rlm@1: { rlm@1: beep(); rlm@1: return false; rlm@1: } rlm@1: rlm@1: if (!editAscii) rlm@1: c = tolower(c); rlm@1: rlm@1: u32 value = 256; rlm@1: rlm@1: if (c >= 'a' && c <= 'f') rlm@1: value = 10 + (c - 'a'); rlm@1: else if (c >= '0' && c <= '9') rlm@1: value = (c - '0'); rlm@1: if (editAscii) rlm@1: { rlm@1: editData(editAddress, 8, 0, c); rlm@1: moveAddress(1, 0); rlm@1: InvalidateRect(NULL, TRUE); rlm@1: } rlm@1: else rlm@1: { rlm@1: if (value != 256) rlm@1: { rlm@1: value <<= 4*(maxNibble-editNibble); rlm@1: u32 mask = ~(15 << 4*(maxNibble - editNibble)); rlm@1: switch (dataSize) rlm@1: { rlm@1: case 0: rlm@1: editData(editAddress, 8, mask, value); rlm@1: break; rlm@1: case 1: rlm@1: editData(editAddress, 16, mask, value); rlm@1: break; rlm@1: case 2: rlm@1: editData(editAddress, 32, mask, value); rlm@1: break; rlm@1: } rlm@1: moveAddress(0, 1); rlm@1: InvalidateRect(NULL, TRUE); rlm@1: } rlm@1: } rlm@1: return true; rlm@1: } rlm@1: rlm@1: void MemoryViewer::beep() rlm@1: { rlm@1: MessageBeep((UINT)-1); rlm@1: } rlm@1: rlm@1: void MemoryViewer::registerClass() rlm@1: { rlm@1: if (!isRegistered) rlm@1: { rlm@1: WNDCLASS wc; rlm@1: ZeroMemory(&wc, sizeof(wc)); rlm@1: wc.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS; rlm@1: wc.lpfnWndProc = (WNDPROC) ::DefWindowProc; rlm@1: wc.hInstance = AfxGetInstanceHandle(); rlm@1: wc.hCursor = LoadCursor(NULL, IDC_ARROW); rlm@1: wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); rlm@1: wc.lpszMenuName = NULL; rlm@1: wc.lpszClassName = "VbaMemoryViewer"; rlm@1: AfxRegisterClass(&wc); rlm@1: isRegistered = true; rlm@1: } rlm@1: } rlm@1: rlm@1: void MemoryViewer::setAddressSize(int s) rlm@1: { rlm@1: addressSize = s; rlm@1: } rlm@1: rlm@1: u32 MemoryViewer::getCurrentAddress() rlm@1: { rlm@1: return editAddress; rlm@1: } rlm@1: rlm@1: int MemoryViewer::getSize() rlm@1: { rlm@1: return dataSize; rlm@1: } rlm@1: