Bochs/bochs/gui/win32_enh_dbg_osdep.cc

1936 lines
79 KiB
C++

/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// BOCHS ENHANCED DEBUGGER Ver 1.2
// (C) Chourdakis Michael, 2008
// http://www.turboirc.com
//
// Modified by Bruce Ewing
//
// Copyright (C) 2008-2014 The Bochs Project
#include "config.h"
#if BX_DEBUGGER && BX_DEBUGGER_GUI
#include "bochs.h"
#include "win32dialog.h"
#include "enh_dbg.h"
// Important Note! All the string manipulation functions assume one byte chars -- ie. "ascii",
// instead of "wide" chars. If there exists a compiler that automatically assumes wide chars
// (ie. 2 byte), then all the function names in here need to be changed to FORCE the compiler
// to use the "A" functions instead of the "W" functions. That is, strcpyA(), sprintfA(), etc.
// This will require setting macros for the non-os-specific code, too.
#include <commctrl.h>
#include <commdlg.h>
#ifdef _WIN64
#define DWL_MSGRESULT DWLP_MSGRESULT
#endif
// User Customizable initial settings:
// the Register color table
COLORREF ColorList[16] = { // background "register type" colors indexed by RegColor value
RGB(255,255,255), // white
RGB(200,255,255), // blue (aqua)
RGB(230,230,230), // gray
RGB(248,255,200), // yellow
RGB(216,216,255), // purple
RGB(200,255,200), // green
RGB(255,230,200), // orange
RGB(255,255,255), // user definable
RGB(255,255,255),
RGB(255,255,255),
RGB(255,255,255),
RGB(255,255,255),
RGB(255,255,255),
RGB(255,255,255),
RGB(255,255,255),
RGB(255,255,255)
};
#define STATUS_WIN_OVERLAP 4 // # of "extra" pixels at the top of a Status window
// END of User Customizable settings
COLORREF AsmColors[4] = {
RGB(0,0,0), // text foreground color is normally black
RGB(0,100,0), // current opcode is dark green and bold
RGB(150,0,0), // a breakpoint is red and italic
RGB(0,0,200) // both = blue, bold, AND italic
};
#ifndef LVIF_GROUPID
#define IS_WIN98
// this define may not exist in some compilers
#define LVIF_GROUPID 0
#endif
#ifndef IS_WIN98
// workaround broken code if IS_WIN98 not defined
#define IS_WIN98
#endif
// The wordsize popup is the 15th entry in the Opt menu -- COUNTING SEPARATORS
// Index = (entry number - 1) -- if the Opt menu is modified, then update this value
// -- or else the popup checkmarks won't work
#define WS_POPUP_IDX 14
void DockResize (int j, Bit32u x); // need some function prototypes
void SetHorzLimits(void);
void ParseIDText(const char *x);
void ShowData();
void UpdateStatus();
void doUpdate();
void RefreshDataWin();
void OnBreak();
void ParseBkpt();
void SetBreak(int i);
void ChangeReg();
int HotKey (int ww, int Alt, int Shift, int Control);
void ActivateMenuItem (int LW);
void SetMemLine (int L);
void MakeBL(HTREEITEM *h_P, bx_param_c *p);
static unsigned LstTop = 0;
static Bit32u CurTimeStamp = 0; // last mousedown time
// Handles to Windows and global stuff
HWND hY = NULL; // complete parent window
HWND hL[3]; // 0=registers, 1=Asm, 2=MemDump
HWND hE_I; // command input window
HWND hS_S; // "status" window at bottom
HWND hE_O; // debugger text output
HWND hT; // param_tree window
HWND hBTN[5]; // button row
HWND hCPUt[BX_MAX_SMP_THREADS_SUPPORTED]; // "tabs" for the individual CPUs
HFONT CustomFont[4];
HFONT DefFont;
LOGFONT mylf;
UINT fontInit = 0;
RECT rY = {0};
BOOL windowInit = FALSE;
HMENU hOptMenu; // "Options" popup menu (needed to set check marks)
HMENU hViewMenu; // "View" popup menu (needed to gray entries)
HMENU hCmdMenu; // "Command" popup menu (needed to gray entries)
// one "defualtProc" for each edit window (Input and Output)
WNDPROC wEdit[2];
WNDPROC wBtn; // all the buttons have the same Proc
WNDPROC wTreeView;
WNDPROC wListView; // all the lists use the same Proc
//HANDLE hTCevent[BX_MAX_SMP_THREADS_SUPPORTED]; // Start/Sleep Control for cpu_loop threads
// window resizing/docking variables
unsigned CurXSize = 0; // last known size of main client window
unsigned CurYSize = 0;
HCURSOR hCursResize;
HCURSOR hCursDock;
HCURSOR hCursArrow;
int SelectedEntry; // keeps track of "clicks" on list entries
// base window "styles" for the 3 listviews.
long LVStyle[3] = {
LVS_REPORT | WS_CHILD,
LVS_SHOWSELALWAYS | LVS_REPORT | WS_CHILD,
LVS_SHOWSELALWAYS | LVS_REPORT | WS_CHILD | WS_VISIBLE
};
TVINSERTSTRUCT tvis; // tree-view generic item
Bit32u SelectedBID;
#define BTN_BASE 1024
#define MULTICPU_BTN_BASE 1030
bx_bool UpdInProgress[3]; // flag -- list update incomplete (not OK to paint)
INT_PTR CALLBACK A_DP(HWND hh,UINT mm,WPARAM ww,LPARAM ll)
{
switch(mm)
{
case WM_INITDIALOG:
SetWindowText(hh,ask_str.title);
SetWindowText(GetDlgItem(hh,101),ask_str.prompt);
SetWindowText(GetDlgItem(hh,102),ask_str.reply);
return TRUE;
case WM_COMMAND:
if (LOWORD(ww) == IDOK)
{
GetWindowText(GetDlgItem(hh,102),ask_str.reply,100);
EndDialog(hh,IDOK);
return 0;
}
if (LOWORD(ww) == IDCANCEL)
{
EndDialog(hh,IDCANCEL);
return 0;
}
}
return 0;
}
bx_bool ShowAskDialog()
{
bx_bool ret = FALSE;
// The dialog box needs a caret, and will destroy the one in hE_I.
// So destroy it myself, cleanly, and let it be recreated cleanly.
CallWindowProc(*wEdit, hE_I,WM_KILLFOCUS,(WPARAM) 0,0);
if (DialogBoxParam(GetModuleHandle(0),"DIALOG_AT",hY,A_DP,(LPARAM) 0) == IDOK)
ret = TRUE;
// recreate the caret in the Input window -- KILL and SET focus only work in pairs!
CallWindowProc(*wEdit, hE_I,WM_SETFOCUS,(WPARAM) 0,0);
return ret;
}
// Subclass the edit controls
LRESULT CALLBACK ThisEditProc(HWND hh, UINT mm, WPARAM ww, LPARAM ll)
{
int i = 0;
if (hh == hE_O) i = 1; // easy way to detect which edit window
switch (mm)
{
case WM_MOUSEMOVE:
// turn off any sizing operation if the cursor strays off the listviews
Sizing = 0;
// also turn off any half-completed mouseclicks
xClick = -1;
break;
case WM_KILLFOCUS:
case WM_SETFOCUS: // force the Input window to always have the caret
return 0; // SETFOCUS/KILLFOCUS commands should be sent directly to the hE_I defProc
case WM_CHAR:
case WM_SYSCHAR:
// throw away all Enter keys (bell problems)
if (ww == VK_RETURN)
return 0;
// force all typed input to the Input window (wEdit[0] = Input)
CallWindowProc(*wEdit, hE_I, mm, ww, ll);
return 0;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
// simply let parent know about all keydowns in these edit boxes
SendMessage(GetParent(hh),mm,ww,ll);
// the following keys cause annoying "bells" if sent on to the Original proc
// -- so throw them away (return 0)
if (ww == VK_RETURN || ww == VK_DOWN || ww == VK_UP)
return 0;
}
return (CallWindowProc(wEdit[i], hh, mm, ww, ll));
}
// Subclass all the button controls together
LRESULT CALLBACK BtnProc(HWND hh, UINT mm, WPARAM ww, LPARAM ll)
{
switch (mm)
{
case WM_MOUSEMOVE:
// turn off any sizing operation if the cursor strays off the listviews
Sizing = 0;
// also turn off any half-completed mouseclicks
xClick = -1;
break;
case WM_CHAR:
// throw away any Enter keys (potential bell problems?)
if (ww == VK_RETURN)
return 0;
// force any typed input to the Input window
CallWindowProc((WNDPROC) *wEdit, hE_I, mm, ww, ll);
return 0;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
// pass to parent any keys
SendMessage(GetParent(hh),mm,ww,ll);
if (ww == ' ') // space chars cause buttons to activate
return 0;
}
return (CallWindowProc(wBtn, hh, mm, ww, ll));
}
// the subclassed tree-view uses the same handler that the listview does
// subclass all the listviews at once
// Note: the Sizing varaible keeps track of whether the program is in resize or dock mode, and
// which windows are involved. It's complicated. If you don't like how I use the variable, tough.
LRESULT CALLBACK LVProc(HWND hh, UINT mm, WPARAM ww, LPARAM ll)
{
int i;
POINT pt;
pt.y = HIWORD(ll);
pt.x = LOWORD(ll); // get coordinates of the mouse (assume a mouse message)
// some compilers generate buggy code if this 'if' is put inside the switch!
if (mm == WM_PAINT)
{
i = 2;
if (hh == hL[ASM_WND]) i=1;
else if (hh == hL[REG_WND]) i=0;
if (UpdInProgress[i] != FALSE) // if list is not complete, don't paint it
{
PAINTSTRUCT ps;
BeginPaint (hh, &ps);
EndPaint (hh, &ps);
return 0;
}
}
switch (mm)
{
case WM_CHAR:
// throw away all Enter keys (or use them for something)
if (ww != VK_RETURN && *wEdit != NULL)
// force all typed input to the Input window
CallWindowProc(*wEdit, hE_I, mm, ww, ll);
return 0;
case WM_MOUSEMOVE: // need to play with the cursor during resize/dock operations
// mouse position is in listview client's coordinates
if (xClick >= 0) // saw a lbutton mousedown recently? (pre-dock mode)
{
// cancel an impending "click" and go to dock (drag) mode if mouse is moving too much
i= (OneCharWide >> 1);
if (pt.x > xClick + i || pt.x < xClick - i)
xClick = -1;
else if (pt.y > yClick + i || pt.y < yClick - i)
xClick = -1;
// go into dock mode (without canceling the click) on a .5s time delay
i = CurTimeStamp + 500;
if (xClick < 0 || GetMessageTime() > i) // Start a "dock" operation?
Sizing = SizeList; // Sizing tells which ListView is being moved
// if "drag" did not turn off, then I will get only one mousemove, with VK_LBUTTON showing UP
i = GetKeyState(VK_LBUTTON);
if (i >= 0 && Sizing != 0) // this could be EITHER a dock or resize
{
int j = 2;
if (hh == hL[REG_WND])
j = 0; // j = ListView destination index
else if (hh == hL[ASM_WND])
j = 1;
ClientToScreen(hh,&pt);
ScreenToClient(hY,&pt); // convert to parent's coordinates
DockResize (j, (Bit32u)pt.x);
Sizing = 0;
}
}
if (Sizing != 0)
{
ClientToScreen(hh,&pt);
ScreenToClient(hY,&pt); // convert to parent's coordinates
i = GetKeyState(VK_LBUTTON);
// verify horizontal limits of the current resize or dock operation
if (pt.x > Resize_HiX || pt.x < Resize_LoX)
Sizing = 0;
else if (i >= 0 && Sizing > 0)
{
int j = DUMP_WND;
if (hh == hL[REG_WND])
j = REG_WND; // j = ListView destination index
else if (hh == hL[ASM_WND])
j = ASM_WND;
DockResize (j, (Bit32u)pt.x);
Sizing = 0;
}
else if (Sizing > 5)
SetCursor(hCursDock);
else
SetCursor(hCursResize);
}
break;
case WM_NCMOUSEMOVE: // more cursor games
ScreenToClient(hY,&pt); // convert to parent's coordinates
if (Sizing == 0)
{
if (ww == HTBORDER) // mouse is hovering over a resize bar or border
{
if (pt.x < BarClix[0] + 10) // is it the left or right bar?
{
Sizing = -2;
Resize_LoX = BarClix[0] - OneCharWide; // set horizontal limits
Resize_HiX = BarClix[0] + OneCharWide;
}
else if (pt.x > BarClix[1] - 10)
{
Sizing = -1;
Resize_LoX = BarClix[1] - OneCharWide; // set horizontal limits
Resize_HiX = BarClix[1] + OneCharWide;
}
}
}
else if (Sizing >= 10) // continuing docking operation?
SetCursor(hCursDock);
else
{
// verify horizontal limits of the current resize operation
if (pt.x > Resize_HiX || pt.x < Resize_LoX)
Sizing = 0;
else
SetCursor(hCursResize);
}
break;
case WM_NCLBUTTONDOWN: // NC messages are in Screen coordinates
ScreenToClient(hY,&pt); // convert to parent's coordinates
if (Sizing < 0) // doing a presize? -- enter full resize mode
{
SetHorzLimits();
SetCursor(hCursResize);
return 0; // important to eat the mousedown (for scrollbars)
}
break;
case WM_NCLBUTTONUP:
i = Sizing;
Sizing = 0; // a mouseup on a border can't be interpreted -- cancel everything
xClick = -1;
if (i > 0)
return 0; // eat the mouseup if a sizing op is ending (for scrollbars)
case WM_LBUTTONDOWN:
if (Sizing < 0) // doing a presize?
{
SetHorzLimits();
SetCursor(hCursResize);
}
else // set "pre-dock" mode
{
if (hh == hL[REG_WND])
SizeList = 10; // remember which list to dock
else if (hh == hL[ASM_WND])
SizeList = 11;
else
SizeList = 12;
Resize_LoX = OneCharWide << 2; // set horizontal limits
i = ListWidthPix[0] + ListWidthPix[1] + ListWidthPix[2];
Resize_HiX = i - (OneCharWide << 2);
CurTimeStamp = GetMessageTime();
xClick = pt.x;
yClick = pt.y;
}
// prevent default drag operations by returning 0
// unfortunately, this also prevents clicks from happening automatically
return 0;
case WM_LBUTTONUP:
// the mouseup COMPLETES a "click" or drag
if (Sizing > 0)
{
int j = DUMP_WND;
if (hh == hL[REG_WND])
j = REG_WND; // j = ListView destination index
else if (hh == hL[ASM_WND])
j = ASM_WND;
GetCursorPos(&pt); // Screen coordinates
ScreenToClient(hY,&pt); // convert to parent's coordinates
DockResize (j, (Bit32u) pt.x);
Sizing = 0;
}
else if (xClick >= 0)
{
// verify the mouseup was within a tight circle of the mousedown
i= (OneCharWide >> 1) +1;
if (pt.x < xClick + i && pt.x > xClick - i && pt.y < yClick + i && pt.y > yClick - i)
{
LV_ITEM lvi;
lvi.stateMask = LVIS_SELECTED;
lvi.state = 0;
// emulate a regular click, for Trees or Lists
if (hh == hT)
{
TV_HITTESTINFO TreeHT;
TreeHT.pt.x = pt.x; // find out which tree button got clicked
TreeHT.pt.y = pt.y;
HTREEITEM hTreeEnt;
hTreeEnt = (HTREEITEM) CallWindowProc(wTreeView,hT,TVM_HITTEST,(WPARAM) 0,(LPARAM) &TreeHT);
// then simulate a click on that button
if (hTreeEnt != NULL) // make sure the click is actually on an entry
CallWindowProc(wTreeView,hT,TVM_EXPAND,(WPARAM) TVE_TOGGLE,(LPARAM) hTreeEnt);
xClick = -1;
Sizing = 0;
return 0; // eat all the Tree mouseups
}
i = REG_WND; // deal with List Focus
DumpHasFocus = FALSE;
if (hh == hL[ASM_WND])
i = ASM_WND;
else if (hh != hL[REG_WND])
{
DumpHasFocus = TRUE;
i = DUMP_WND;
EnableMenuItem (hCmdMenu, CMD_BRKPT, MF_GRAYED);
if (LinearDump == FALSE)
{
EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_ENABLED);
EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_ENABLED);
}
else
{
EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_GRAYED);
EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_GRAYED);
}
}
if (DumpHasFocus == FALSE)
{
EnableMenuItem (hCmdMenu, CMD_BRKPT, MF_ENABLED);
EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_GRAYED);
EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_GRAYED);
}
if (GetFocus() != hh)
{
CallWindowProc(wListView, hh, WM_SETFOCUS, (WPARAM) 0, (LPARAM) 0);
if (i != REG_WND)
CallWindowProc(wListView, hL[REG_WND], WM_KILLFOCUS, (WPARAM) 0, (LPARAM) 0);
if (i != ASM_WND)
CallWindowProc(wListView, hL[ASM_WND], WM_KILLFOCUS, (WPARAM) 0, (LPARAM) 0);
if (i != DUMP_WND)
CallWindowProc(wListView, hL[DUMP_WND], WM_KILLFOCUS, (WPARAM) 0, (LPARAM) 0);
}
LVHITTESTINFO lvht; // do a hit test to get the iItem to select
lvht.pt.y = HIWORD(ll);
lvht.pt.x = LOWORD(ll); // make sure to do any subitem test on the RIGHT point!
SelectedEntry = CallWindowProc(wListView, hh, LVM_SUBITEMHITTEST, (WPARAM) 0, (LPARAM) &lvht);
// SelectedEntry is a copy of the iItem number -- ignore anything <= 0
int Control = GetKeyState(VK_CONTROL); // key is down if val is negative
if (Control >= 0)
{
// if no control key, deselect anyything that's selected
int j = CallWindowProc(wListView, hh, LVM_GETNEXTITEM, (WPARAM) -1, MAKELPARAM(LVNI_SELECTED, 0));
while (j >= 0)
{
// cancel the item's "selection"
CallWindowProc(wListView, hh, LVM_SETITEMSTATE, (WPARAM)j, (LPARAM)&lvi);
// and get the next one
j = CallWindowProc(wListView, hh, LVM_GETNEXTITEM, (WPARAM) -1, MAKELPARAM(LVNI_SELECTED, 0));
}
}
if (SelectedEntry >= 0) // then select the one that got clicked
{
lvi.state = LVIS_SELECTED;
CallWindowProc(wListView, hh, LVM_SETITEMSTATE, (WPARAM)SelectedEntry, (LPARAM)&lvi);
if (hh == hL[DUMP_WND] && DViewMode == VIEW_MEMDUMP && LinearDump == FALSE)
{
// if this was a PhysDump click -- need to get the "Selected Address"
SA_valid = TRUE;
SelectedDataAddress = DumpStart + (SelectedEntry<<4);
// Clicked a Subitem? column numbers = byte offsets + 1
if (lvht.iSubItem > 0)
SelectedDataAddress += lvht.iSubItem - 1;
}
else if (hh == hL[DUMP_WND] && DViewMode == VIEW_BREAK)
{
// breakpoint or watchpoint click -- figure out WHICH breakpoint!
// SelectedBID is the breakpoint ID, if a breakpoint was clicked
if (SelectedEntry < WWP_BaseEntry && SelectedEntry < 256)
{
i = 0;
if (SelectedEntry > EndPhyEntry)
i = 0x10000; // bit flag for Virtual Brk
else if (SelectedEntry > EndLinEntry)
i = 0x20000; // bit flag for Phy Brkpt
SelectedBID = BrkpIDMap[SelectedEntry] | i;
}
else if (SelectedEntry >= WWP_BaseEntry && SelectedEntry < WWP_BaseEntry + WWPSnapCount)
{
// if a watchpoint was clicked, get its index (0 to 15)
// and save the address for later verification
i = SelectedEntry - WWP_BaseEntry;
SelectedBID = 0x40000 | i;
}
else if (SelectedEntry >= RWP_BaseEntry && SelectedEntry < RWP_BaseEntry + RWPSnapCount)
{
i = SelectedEntry - RWP_BaseEntry;
SelectedBID = 0x80000 | i;
}
}
}
}
}
xClick = -1; // all drags/clicks have been processed, so reset
Sizing = 0;
return 0; // eat all the mouseups
} // end the switch
if (hh == hT) // if this is a param_tree message, use the proper windowProc
return (CallWindowProc(wTreeView, hh, mm, ww, ll));
else
return (CallWindowProc(wListView, hh, mm, ww, ll));
}
bx_bool SpListView() // Superclasses a ListView control
{
WNDCLASS wClass;
GetClassInfo(GetModuleHandle(0), WC_LISTVIEW, &wClass);
wListView = wClass.lpfnWndProc;
wClass.hInstance = GetModuleHandle(0);
wClass.lpszClassName = "sLV";
wClass.lpfnWndProc = LVProc;
if (RegisterClass(&wClass) == 0)
return FALSE;
return TRUE;
}
bx_bool SpBtn() // Superclasses a button control
{
WNDCLASS wClass;
GetClassInfo(GetModuleHandle(0), "button", &wClass);
wBtn = wClass.lpfnWndProc;
wClass.hInstance = GetModuleHandle(0);
wClass.lpszClassName = "sBtn";
wClass.lpfnWndProc = BtnProc;
if (RegisterClass(&wClass) == 0)
return FALSE;
return TRUE;
}
// set all TRUE flags to checked in the Options menu, gray out unsupported features
void SpecialInit()
{
int i = 8;
doSimuInit = FALSE;
EnableMenuItem (hOptMenu, CMD_EREG, MF_GRAYED);
EnableMenuItem (hCmdMenu, CMD_WPTWR, MF_GRAYED);
EnableMenuItem (hCmdMenu, CMD_WPTRD, MF_GRAYED);
EnableMenuItem (hOptMenu, CMD_XCEPT, MF_GRAYED);
// 32bit registers are always displayed until longmode is active
while (--i >= 0)
{
if (SeeReg[i] != FALSE)
CheckMenuItem (hOptMenu, i + CMD_EREG, MF_CHECKED);
}
if (SingleCPU != FALSE)
CheckMenuItem (hOptMenu, CMD_ONECPU, MF_CHECKED);
if (BX_SMP_PROCESSORS == 1)
EnableMenuItem (hOptMenu, CMD_ONECPU, MF_GRAYED);
if (ShowButtons != FALSE)
CheckMenuItem (hOptMenu, CMD_SBTN, MF_CHECKED);
if (UprCase != 0)
CheckMenuItem (hOptMenu, CMD_UCASE, MF_CHECKED);
if (isLittleEndian != FALSE)
CheckMenuItem (hOptMenu, CMD_LEND, MF_CHECKED);
if (ignSSDisasm != FALSE)
CheckMenuItem (hOptMenu, CMD_IGNSA, MF_CHECKED);
if (ignoreNxtT != FALSE)
CheckMenuItem (hOptMenu, CMD_IGNNT, MF_CHECKED);
if (SeeRegColors != FALSE)
CheckMenuItem (hOptMenu, CMD_RCLR, MF_CHECKED);
if (DumpInAsciiMode == 0) // prevent an illegal value
DumpInAsciiMode = 3;
if ((DumpInAsciiMode & 2) != 0)
CheckMenuItem (hOptMenu, CMD_MHEX, MF_CHECKED);
else // one or the other MemDump mode must always be left on! (unchangeable)
EnableMenuItem (hOptMenu, CMD_MASCII, MF_GRAYED);
if ((DumpInAsciiMode & 1) != 0)
CheckMenuItem (hOptMenu, CMD_MASCII, MF_CHECKED);
else
EnableMenuItem (hOptMenu, CMD_MHEX, MF_GRAYED);
if (ShowIOWindows != FALSE)
CheckMenuItem (hOptMenu, CMD_IOWIN, MF_CHECKED);
HMENU wsMenu = GetSubMenu (hOptMenu, WS_POPUP_IDX);
CheckMenuItem (wsMenu, CMD_WS_1+DumpWSIndex, MF_CHECKED);
EnableMenuItem (hOptMenu, CMD_TREG, MF_GRAYED); // not currently supported by bochs
EnableMenuItem (hViewMenu, CMD_PAGEV, MF_GRAYED);
#if BX_SUPPORT_FPU == 0
EnableMenuItem (hOptMenu, CMD_FPUR, MF_GRAYED);
#endif
if (! CpuSupportSSE)
EnableMenuItem (hOptMenu, CMD_XMMR, MF_GRAYED);
}
// append a whole row of text into a ListView, all at once
// Note: LineCount should start at 0
void InsertListRow(char *ColumnText[], int ColumnCount, int listnum, int LineCount, int grouping)
{
LV_ITEM lvi = {LVIF_TEXT,LineCount,0,0,0,(LPSTR) *ColumnText,80,0,0};
//#ifndef IS_WIN98
// lvi.iGroupId = grouping;
//#endif
// insert data for the first column
CallWindowProc(wListView,hL[listnum],LVM_INSERTITEM,(WPARAM) 0,(LPARAM) &lvi);
// loop over, and insert data for all additional columns
lvi.mask = LVIF_TEXT;
int i = 0;
while (++i < ColumnCount)
{
lvi.iSubItem = i;
lvi.pszText = ColumnText[i];
CallWindowProc(wListView,hL[listnum],LVM_SETITEMTEXT,(WPARAM) LineCount,(LPARAM) &lvi);
}
}
void SetSizeIOS(int WinSizeX, int WinSizeY)
{
int i, j;
TEXTMETRIC tm;
// calculate the height/width of typical "glyphs" in the font
HDC hdc = GetDC (hS_S);
GetTextMetrics (hdc, &tm);
ReleaseDC (hS_S, hdc);
OneCharWide = tm.tmAveCharWidth;
j= tm.tmAveCharWidth * 72; // status bar contains about 72 char positions (without eflags)
if (j > WinSizeX/2) // leave half the status bar for the eflags
j = WinSizeX/2;
i = j*5 / 12; // predefined proportions of Status "subwindows" = 2:5:5
int modepos = j/6;
int ptimepos = modepos + i;
int eflpos = ptimepos + i;
int p[4] = {modepos,ptimepos,eflpos,-1};
// then set the dimensions of the I, O, and S child windows
j = tm.tmHeight + tm.tmExternalLeading; // input window is the height of a char
i = j >> 1;
int sY = j + i; // status window and buttons are 50% taller
LstTop = 0;
if (ShowButtons != FALSE)
{
// position the 5 command buttons
LstTop = sY;
i = WinSizeX / 5;
SetWindowPos(hBTN[0],0,0,0,i,LstTop,SWP_SHOWWINDOW);
SetWindowPos(hBTN[1],0,i,0,i,LstTop,SWP_SHOWWINDOW);
SetWindowPos(hBTN[2],0,i*2,0,i,LstTop,SWP_SHOWWINDOW);
SetWindowPos(hBTN[3],0,i*3,0,i,LstTop,SWP_SHOWWINDOW);
SetWindowPos(hBTN[4],0,i*4,0,WinSizeX - 4*i,LstTop,SWP_SHOWWINDOW);
}
else
{
ShowWindow(hBTN[0],SW_HIDE);
ShowWindow(hBTN[1],SW_HIDE);
ShowWindow(hBTN[2],SW_HIDE);
ShowWindow(hBTN[3],SW_HIDE);
ShowWindow(hBTN[4],SW_HIDE);
}
if (TotCPUs > 1)
{
// MultiCPU simulation -- need CPU button row, too.
int HorPos = 0;
unsigned int CPUn = 0;
i = WinSizeX / TotCPUs;
while (CPUn < TotCPUs - 1)
{
SetWindowPos(hCPUt[CPUn],0,HorPos,LstTop,i,sY,SWP_SHOWWINDOW);
++CPUn;
HorPos += i;
}
// use up any extra pixels on the last button
SetWindowPos(hCPUt[CPUn],0,HorPos,LstTop,WinSizeX-HorPos,sY,SWP_SHOWWINDOW);
LstTop += sY;
}
else if (BX_SMP_PROCESSORS > 1) // only showing CPU0 on a SMP simulation
{
i = BX_SMP_PROCESSORS; // so hide all the other CPU buttons
while (--i >= 0)
ShowWindow(hCPUt[i],SW_HIDE);
}
// The status win may not use all of its space: overlap lists or Input by STATUS_WIN_OVERLAP pixels
i = WinSizeY - sY - j;
if (ShowIOWindows == FALSE)
{
// caret functions will be ignored if sent multiple times (which is what is desired)
CallWindowProc(*wEdit, hE_I,WM_KILLFOCUS,(WPARAM) 0,0); // destroy Input caret
ShowWindow(hE_I,SW_HIDE);
ShowWindow(hE_O,SW_HIDE);
ListVerticalPix = WinSizeY - sY - LstTop + STATUS_WIN_OVERLAP;
}
else
{
CallWindowProc(*wEdit, hE_I,WM_SETFOCUS,(WPARAM) 0,0); // create Input caret
ListVerticalPix = (WinSizeY * 3) >> 2; // 3/4 height
SetWindowPos(hE_I,0,2,i + STATUS_WIN_OVERLAP,WinSizeX,j,SWP_SHOWWINDOW);
SetWindowPos(hE_O,0,0,ListVerticalPix + LstTop,WinSizeX,
i - ListVerticalPix - LstTop + (STATUS_WIN_OVERLAP/2),SWP_SHOWWINDOW);
}
SetWindowPos(hS_S,0,0,WinSizeY - sY,WinSizeX,sY,SWP_SHOWWINDOW);
SendMessage(hS_S,SB_SETPARTS,4,(LPARAM)p);
}
void MoveLists()
{
int i, j, k;
unsigned int StrtCol[3] = {0,0,0};
// use DockOrder to figure out the start columns of each list
// starting column of 2nd list = width of first list
i = ListWidthPix[(DockOrder >> 8) -1];
j = ((DockOrder>>4)& 3) -1; // index of 2nd list
StrtCol[j] = i;
BarClix[0] = i;
k = i + ListWidthPix[j]; // width of first + second
StrtCol[(DockOrder & 3) -1] = k;
BarClix[1] = k;
// the center listview must be the only one with a border
if (CurCenterList != j)
{
// remove the border on the previous center list, and put it on the new one
SetWindowLong ( hL[CurCenterList], GWL_STYLE, LVStyle[CurCenterList]);
SetWindowLong ( hL[j], GWL_STYLE, LVStyle[j] | WS_BORDER );
CurCenterList = j;
// the tree window should have the same border as the data window --
// but unfortunately, SetWindowLong does not work properly on a treeview!
// if (j == 2)
// k=SetWindowLong ( hT, GWL_STYLE, TVS_DISABLEDRAGDROP | TVS_HASLINES | TVS_HASBUTTONS | WS_CHILD | WS_BORDER );
// else
// k=SetWindowLong ( hT, GWL_STYLE, TVS_DISABLEDRAGDROP | TVS_HASLINES | TVS_HASBUTTONS | WS_CHILD );
}
// On at least some versions of Win, you cannot mess with the positions
// of subclassed ListView controls that still HAVE DATA IN THEM.
// Therefore, delete all ListView data --
// then refresh the 3 main ListView windows afterward
CallWindowProc(wListView,hL[DUMP_WND],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
CallWindowProc(wListView,hL[ASM_WND],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
CallWindowProc(wListView,hL[REG_WND],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
SetWindowPos(hL[REG_WND],0,StrtCol[0],LstTop,ListWidthPix[0],ListVerticalPix,SWP_HIDEWINDOW);
SetWindowPos(hL[ASM_WND],0,StrtCol[1],LstTop,ListWidthPix[1],ListVerticalPix,SWP_HIDEWINDOW);
SetWindowPos(hL[DUMP_WND],0,StrtCol[2],LstTop,ListWidthPix[2],ListVerticalPix,SWP_HIDEWINDOW);
// tree window = same size/position as dump window
SetWindowPos(hT,0,StrtCol[2],LstTop,ListWidthPix[2],ListVerticalPix,SWP_HIDEWINDOW);
// size the last column of each list = total width of that list
CallWindowProc(wListView, hL[REG_WND], LVM_SETCOLUMNWIDTH, 2, ListWidthPix[0]);
CallWindowProc(wListView, hL[ASM_WND], LVM_SETCOLUMNWIDTH, 2, ListWidthPix[1]);
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, 17, ListWidthPix[2]);
BottomAsmLA = ~0; // force an ASM autoload next time, to resize it
doDumpRefresh = TRUE; // force a data window refresh on a break
if (AtBreak != FALSE) // can't refresh the windows until a break!
{
doUpdate(); // refresh the ASM and Register windows
RefreshDataWin(); // and whichever data window is up
}
}
// redraw/recalculate everything if the vertical window sizes are invalid
void VSizeChange()
{
RECT rc;
GetClientRect(hY,&rc);
SetSizeIOS((int)rc.right,(int)rc.bottom); // window sizes are font-dependent
MoveLists();
}
// kludgy function to remove column header/autosizing from Fill routines
void RedrawColumns(int listnum)
{
static bx_bool DumpCResize = FALSE; // flag to force column resize/autosize
static int PrevDV = -1; // type of previous Dump window that was displayed
// ResizeColmns says whether font or 64bit mode has changed,
// but the Dump windows need to "remember" seeing the flag
if (ResizeColmns != FALSE)
DumpCResize = TRUE;
if (listnum == REG_WND)
{
if (ResizeColmns != FALSE)
CallWindowProc(wListView, hL[REG_WND], LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE);
}
else if (listnum == ASM_WND)
{
// recalculate # of list items per page for all list windows
AsmPgSize = CallWindowProc(wListView,hL[ASM_WND],LVM_GETCOUNTPERPAGE,(WPARAM) 0,(LPARAM) 0);
if (AsmPgSize != 0)
ListLineRatio = ListVerticalPix / AsmPgSize;
CallWindowProc(wListView, hL[ASM_WND], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
}
else
{
char tmpc[32];
int i = 17;
// MemDump resizes/uses ALL columns -- there ARE no unused ones
if (DViewMode != VIEW_MEMDUMP && PrevDV != DViewMode)
{
// force the widths of unused columns to 0, by squishing ALL the columns to 0 width
while (--i > 0)
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, i, 0);
}
LV_COLUMN lvgc = {LVCF_TEXT,0,0,tmpc};
switch (DViewMode)
{
case VIEW_MEMDUMP:
if (DumpInitted == FALSE)
{
CallWindowProc(wListView,hL[DUMP_WND],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
strcpy (tmpc,"Address"); // "generic" header for col 0
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
while (--i >= 0) // (i always equals 17)
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, i, LVSCW_AUTOSIZE_USEHEADER);
}
else
{
if (DumpCResize != FALSE || PrevDV != DViewMode)
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
if (PrevDAD != DumpAlign || PrevDV != DViewMode)
{
PrevDAD = DumpAlign;
for(i = 1 ; i < 17 ; i++)
{
// if dumping ONLY in ascii, 0 out ALL the other columns
if (((i - 1) & (DumpAlign - 1)) == 0 && (DumpInAsciiMode & 2) != 0)
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, i, LVSCW_AUTOSIZE);
else // force the width of unused columns to 0
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, i, 0);
}
}
}
break;
case VIEW_GDT:
// 2 of the GDT columns are too narrow with a regular Autosize
if (PrevDV == DViewMode && DumpCResize == FALSE)
return;
strcpy (tmpc,"Index"); // header for col 0
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
strcpy (tmpc,"Base Address"); // header for col 1
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 1,(LPARAM) &lvgc);
strcpy (tmpc,"Size"); // header for col 2
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 2,(LPARAM) &lvgc);
strcpy (tmpc,"DPL"); // header for col 3
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 3,(LPARAM) &lvgc);
strcpy (tmpc,"Info"); // header for col 4 (17)
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 17,(LPARAM) &lvgc);
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE_USEHEADER);
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, 3, LVSCW_AUTOSIZE_USEHEADER);
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, 2, LVSCW_AUTOSIZE);
break;
case VIEW_IDT:
if (PrevDV == DViewMode && DumpCResize == FALSE)
return;
strcpy (tmpc,"Interrupt"); // header for col 0
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
strcpy (tmpc,"L.Address"); // header for col 1 (17)
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 17,(LPARAM) &lvgc);
// redo col0 to handle the wide header
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE_USEHEADER);
break;
case VIEW_PAGING:
if (PrevDV == DViewMode && DumpCResize == FALSE)
return;
strcpy (tmpc,"L.Address"); // header for col 0
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
strcpy (tmpc,"is mapped to P.Address"); // header for col 1 (17)
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 17,(LPARAM) &lvgc);
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
break;
case VIEW_STACK:
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE);
if (PrevDV == DViewMode && DumpCResize == FALSE)
return;
strcpy (tmpc,"L.Address"); // header for col 0
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
strcpy (tmpc,"Value"); // header for col 1
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 1,(LPARAM) &lvgc);
strcpy (tmpc,"(dec.)"); // header for col 2 (17)
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 17,(LPARAM) &lvgc);
break;
case VIEW_BREAK:
if (PrevDV == DViewMode && DumpCResize == FALSE)
return;
strcpy (tmpc,"Address"); // header for col 0
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
strcpy (tmpc,"Enabled"); // header for col 1
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 1,(LPARAM) &lvgc);
strcpy (tmpc,"ID"); // header for col 2 (17)
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 17,(LPARAM) &lvgc);
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE_USEHEADER);
}
DumpCResize = FALSE;
PrevDV = DViewMode;
}
}
// hide/clear param_tree window when showing a different MemDump window (GDT, IDT, etc.)
void HideTree()
{
ShowWindow(hT,SW_HIDE);
CallWindowProc(wTreeView,hT,TVM_DELETEITEM,(WPARAM) 0,(LPARAM) TVI_ROOT);
}
void ShowFW()
{
FWflag = TRUE;
MessageBox(hY,"With more than 1000 lines in the ASM window, be careful not to minimize the app.\r\nIt will be very slow to reopen.",
"Friendly warning:",MB_ICONINFORMATION);
}
void Invalidate(int i)
{
InvalidateRect(hL[i],0,TRUE);
}
void SetStatusText(int column, const char *buf)
{
SendMessage(hS_S,SB_SETTEXT, column,(LPARAM) buf);
}
void GetLIText(int listnum, int itemnum, int column, char *buf)
{
LV_ITEM lvi = {LVIF_TEXT,itemnum,column,0,0,(LPSTR) buf,100,0,0};
CallWindowProc(wListView, hL[listnum], LVM_GETITEMTEXT,(WPARAM) itemnum,(LPARAM) &lvi);
}
void TakeInputFocus()
{
SetFocus(hY); // get the focus back from the VGA window
}
void GetInputEntry(char *buf)
{
GetWindowText(hE_I,buf,200);
}
void SetLIState(int listnum, int itemnum, bx_bool Select)
{
// assume selected
LV_ITEM lvi = {LVIF_STATE,itemnum,2,LVIS_SELECTED,LVIS_SELECTED,(LPSTR) 0,0,0,0};
if (Select == FALSE)
lvi.state = 0;
CallWindowProc(wListView,hL[listnum],LVM_SETITEMSTATE,(WPARAM) itemnum,(LPARAM) &lvi);
}
int GetNextSelectedLI(int listnum, int StartPt)
{
int L = (int) CallWindowProc(wListView, hL[listnum], LVM_GETNEXTITEM,
(WPARAM) StartPt, MAKELPARAM(LVNI_SELECTED, 0));
return L;
}
int GetASMTopIdx()
{
int i = (int) CallWindowProc(wListView,hL[ASM_WND],LVM_GETTOPINDEX,(WPARAM) 0,(LPARAM) 0);
return i;
}
void ScrollASM(int pixels)
{
CallWindowProc(wListView,hL[ASM_WND],LVM_SCROLL,(WPARAM) 0,(LPARAM) pixels);
}
void ToggleWSchecks(int newWS, int oldWS)
{
// the wordsize popup is the WS_POPUP_IDXth entry in the Opt menu -- COUNTING SEPARATORS
HMENU wsMenu = GetSubMenu (hOptMenu, WS_POPUP_IDX);
CheckMenuItem (wsMenu, oldWS, MF_UNCHECKED | MF_BYPOSITION);
CheckMenuItem (wsMenu, newWS, MF_CHECKED | MF_BYPOSITION);
}
void MakeListsGray()
{
COLORREF c = RGB(255,255,255);
if (AtBreak == FALSE)
{
SetStatusText(0, "Running");
c = RGB(210,210,210); // emulation running -> gui inactive
}
else
SetStatusText(0, "Break");
// this sets the background color OUTSIDE the area of the list, for A, D, R
CallWindowProc(wListView, hL[DUMP_WND],LVM_SETBKCOLOR,0,c);
CallWindowProc(wListView, hL[ASM_WND],LVM_SETBKCOLOR,0,c);
CallWindowProc(wListView, hL[REG_WND],LVM_SETBKCOLOR,0,c);
InvalidateRect(hL[REG_WND],0,TRUE); // Invalidate all 3 of the ListViews --
InvalidateRect(hL[ASM_WND],0,TRUE); // to force a redraw with the new background
InvalidateRect(hL[DUMP_WND],0,TRUE);
}
// the following routine needs to replace the entire window's text,
// and then scroll the window to the end of the text
void SetOutWinTxt()
{
SetWindowText(hE_O,OutWindow); // replace all text with modified buffer
// SendMessage(hE_O,EM_SETSEL,0,-1); // invisibly selects all, sets caret to end
CallWindowProc(wEdit[1], hE_O,EM_SETSEL,OutWinSIZE,OutWinSIZE+1); // sets caret to end only
CallWindowProc(wEdit[1], hE_O,EM_SCROLLCARET,0,0); // scrolls window vertically to caret
// Note: the caret is never actually visible in the Output window
}
// as it stands, the caret is placed at the beginning of each selected history line,
// but the exact functionality is not important -- just do what is easy
void SelectHistory(int UpDown)
{
// the History buffer is circular, so wrap 64 to 0, and -1 to 63
CommandHistoryIdx = (CommandHistoryIdx + UpDown) & 63;
SetWindowText(hE_I,CmdHistory[(CmdHInsert + CommandHistoryIdx) & 63]);
CallWindowProc(*wEdit, hE_I, EM_SETSEL,(WPARAM) -1,(LPARAM) -1);
}
void ClearInputWindow()
{
SetWindowText(hE_I,"");
}
void SetMenuCheckmark (int flag, int CmdIndex)
{
// only the OptMenu has checkmarks, so don't need to "calculate" the hMenu
if (flag != 0)
CheckMenuItem (hOptMenu, CmdIndex, MF_CHECKED);
else
CheckMenuItem (hOptMenu, CmdIndex, MF_UNCHECKED);
}
// do a quickie job of converting a menu Command Index into its "parent" menu handle
// -- this doesn't handle the Help menu (nothing there should ever need to be grayed or checked)
HMENU MenuFromIdx (int CmdIndex)
{
if (CmdIndex < MI_FIRST_VIEWITEM)
return hCmdMenu;
if (CmdIndex < MI_FIRST_OPTITEM)
return hViewMenu;
// if (CmdIndex >= CMD_WS_1 && CmdIndex <= CMD_WS16) HIHI currently the submenu DOES NOT HAVE a global HMENU
// return h???Menu;
return hOptMenu;
}
// pass in FALSE or 0 to gray out a menu item
void GrayMenuItem (int flag, int CmdIndex)
{
HMENU hm = MenuFromIdx (CmdIndex);
if (flag != 0)
EnableMenuItem (hm, CmdIndex, MF_ENABLED);
else
EnableMenuItem (hm, CmdIndex, MF_GRAYED);
}
// kludgy thing to remove OS-dependent code from the front of Fill routines
void StartListUpdate(int listnum)
{
// ShowWindow(hL[listnum],SW_HIDE); // Hiding the windows causes way too much flicker
UpdInProgress[listnum] = TRUE;
CallWindowProc(wListView,hL[listnum],LVM_DELETEALLITEMS,(WPARAM) 0,(LPARAM) 0);
// then set a flag that list[listnum] is being updated -- prevent paint messages, cpu_loop calls, duplicate calls
}
void EndListUpdate(int listnum)
{
UpdInProgress[listnum] = FALSE; // It's OK to paint the listview now
Invalidate(listnum); // -- but the window needs one last paint message
ShowWindow(hL[listnum],SW_SHOW);
}
void DispMessage(const char *msg, const char *title)
{
MessageBox (hY, msg, title, MB_OK);
}
// exit GDT/IDT/Paging/Stack/Tree -- back to the MemDump window
void ShowMemData(bx_bool initting)
{
int i = 1;
if (LinearDump == FALSE)
i = 0;
LV_COLUMN lvgc = {LVCF_TEXT,0,0,(LPSTR)DC0txt[i]};
if (initting != FALSE)
{
GrayMenuItem (0, CMD_WPTWR);
GrayMenuItem (0, CMD_WPTRD);
// update column 0 to say whether its physmem or linear
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
}
lvgc.pszText = tmpcb;
HideTree();
ShowWindow(hL[DUMP_WND],SW_SHOW);
DViewMode = VIEW_MEMDUMP; // returning to MemDump mode
// need to fix the MemDump column "names"
strcpy (tmpcb,"0"); // rebuild header for col 1
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 1,(LPARAM) &lvgc);
// headers for cols 1 to 3, are just numbers 0 to 2
*tmpcb = '1';
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 2,(LPARAM) &lvgc);
*tmpcb = '2';
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 3,(LPARAM) &lvgc);
strcpy (tmpcb,"Ascii"); // rebuild header for col 17
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 17,(LPARAM) &lvgc);
if (DumpInitted == FALSE)
RedrawColumns(DUMP_WND);
else
{
strcpy (tmpcb,DC0txt[i]); // "real" header for col 0
CallWindowProc(wListView,hL[DUMP_WND],LVM_SETCOLUMN,(WPARAM) 0,(LPARAM) &lvgc);
PrevDAD = 0; // force a column resize HIHI getting rid of this line?
if (AtBreak == FALSE)
doDumpRefresh = TRUE;
else
ShowData(); // repopulates & resizes all columns
}
}
// create the top layer of a parameter tree TreeView
void FillPTree()
{
HTREEITEM h_PTroot;
extern bx_list_c *root_param;
// Note: don't multithread this display -- the user expects it to complete
doDumpRefresh = FALSE;
ShowWindow(hL[DUMP_WND],SW_HIDE);
TreeView_DeleteAllItems(hT);
// Note: all tree strings are hardcoded to be in tmpcb -- don't change!
strcpy (tmpcb, "bochs parameter tree");
tvis.hParent = NULL; // create the root node
tvis.item.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_STATE;
tvis.hInsertAfter = (HTREEITEM)TVI_FIRST;
tvis.item.pszText = tmpcb;
tvis.item.cchTextMax = 250;
tvis.item.cChildren = 1;
tvis.item.state = TVIS_EXPANDED; // it must be expanded to show the first layer
tvis.item.stateMask = TVIS_EXPANDED;
h_PTroot = TreeView_InsertItem(hT,&tvis);
tvis.item.mask = TVIF_TEXT | TVIF_CHILDREN; // don't expand any other layers
int i = root_param->get_size();
while (--i >= 0)
MakeBL(&h_PTroot, root_param->get(i));
ShowWindow(hT,SW_SHOW);
}
void MakeTreeChild (HTREEITEM *h_P, int ChildCount, HTREEITEM *h_TC)
{
tvis.item.cChildren = 0;
if (ChildCount > 0)
tvis.item.cChildren = 1;
tvis.hParent = *h_P; // create leaves/recurse branches
*h_TC = (HTREEITEM) CallWindowProc(wTreeView,hT,TVM_INSERTITEM,(WPARAM) 0,(LPARAM) &tvis);
}
bx_bool NewFont()
{
if (AtBreak == FALSE)
return FALSE;
CHOOSEFONT cF = {0};
cF.lStructSize = sizeof(cF);
cF.hwndOwner = hY;
cF.lpLogFont = &mylf;
cF.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT;
mylf.lfItalic = 0;
if (ChooseFont(&cF) == FALSE)
return FALSE;
ShowWindow(hL[REG_WND],SW_HIDE); // font is changed before MoveLists is called
ShowWindow(hL[ASM_WND],SW_HIDE);
ShowWindow(hL[DUMP_WND],SW_HIDE);
ShowWindow(hS_S,SW_HIDE);
ShowWindow(hE_I,SW_HIDE);
if (*CustomFont != DefFont) // destroy all variations of the prev. font
DeleteObject(*CustomFont);
DeleteObject(CustomFont[1]);
DeleteObject(CustomFont[2]);
DeleteObject(CustomFont[3]);
*CustomFont = CreateFontIndirect(&mylf);
// create a bold version of the deffont
mylf.lfWeight = FW_BOLD;
CustomFont[1] = CreateFontIndirect(&mylf);
// create a bold + italic version of the deffont
mylf.lfItalic = 1;
CustomFont[3] = CreateFontIndirect(&mylf);
// create an italic version of the deffont (turn off bold)
mylf.lfWeight = FW_NORMAL;
CustomFont[2] = CreateFontIndirect(&mylf);
CallWindowProc(wListView,hL[REG_WND],WM_SETFONT,(WPARAM)*CustomFont,MAKELPARAM(TRUE,0));
CallWindowProc(wListView,hL[ASM_WND],WM_SETFONT,(WPARAM)*CustomFont,MAKELPARAM(TRUE,0));
CallWindowProc(wListView,hL[DUMP_WND],WM_SETFONT,(WPARAM)*CustomFont,MAKELPARAM(TRUE,0));
CallWindowProc(*wEdit,hE_I,WM_SETFONT,(WPARAM)*CustomFont,MAKELPARAM(TRUE,0));
SendMessage(hS_S,WM_SETFONT,(WPARAM)*CustomFont,MAKELPARAM(TRUE,0));
return TRUE;
}
// Main Window Proc for our Dialog
LRESULT CALLBACK B_WP(HWND hh,UINT mm,WPARAM ww,LPARAM ll)
{
unsigned i;
extern bx_bool vgaw_refresh;
switch(mm)
{
case WM_CREATE:
{
HFONT hF = (HFONT)GetStockObject(OEM_FIXED_FONT);
DefFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
// Register Window
const char* txt0[] = {"Reg Name","Hex Value","Decimal"};
LV_COLUMN lvc = {LVCF_SUBITEM | LVCF_TEXT,LVCFMT_LEFT,0, (char*)txt0[0]};
hL[REG_WND] = CreateWindowEx(0,"sLV","",LVStyle[0],0,0,100,100,hh,(HMENU)1001,GetModuleHandle(0),0);
// Note; WM_CREATE only happens once, so don't bother eliminating these SendMessage macros
ListView_InsertColumn(hL[REG_WND],0,&lvc);
lvc.pszText = (char*)txt0[1];
ListView_InsertColumn(hL[REG_WND],1,&lvc);
lvc.pszText = (char*)txt0[2];
ListView_InsertColumn(hL[REG_WND],2,&lvc);
// Enable the groupID's for the register window
#ifndef IS_WIN98
// GroupID's are only supported on XP or higher -- verify Win Version
// the group stuff may COMPILE correctly, but still may fail at runtime
Bit8u MajWinVer, MinWinVer;
Bit32u PackedVer = GetVersion();
bx_bool Group_OK = TRUE;
MajWinVer = (Bit8u)(PackedVer & 0xff); // Major version # is in the LOW byte
MinWinVer = (Bit8u)((PackedVer>>8) & 0xff);
if (MajWinVer > 5 || (MajWinVer == 5 && MinWinVer >= 1)) // is it XP or higher?
{
wchar_t* txt[] = {L"General Purpose",L"Segment",L"Control",L"MMX",L"SSE",L"Debug",L"Test",L"Other"};
ListView_EnableGroupView(hL[REG_WND],TRUE);
for(i = 0 ; i < 8 ; i++)
{
LVGROUP group1 = {0};
group1.cbSize = sizeof(LVGROUP);
group1.mask = LVGF_HEADER | LVGF_GROUPID;
group1.pszHeader = txt[i];
group1.iGroupId = i;
ListView_InsertGroup(hL[REG_WND], -1, &group1);
}
}
else
Group_OK = FALSE;
#endif
SendMessage(hL[REG_WND], LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
// Asm Window
hL[ASM_WND] = CreateWindowEx(0,"sLV","",LVStyle[1] | WS_BORDER,0,0,1,1,hh,(HMENU)1000,GetModuleHandle(0),0);
CurCenterList = 1; // ASM window starts with the border
const char* txt3[] = {"L.Address","Bytes","Mnemonic"};
lvc.pszText = (char*)txt3[0];
ListView_InsertColumn(hL[ASM_WND],0,&lvc);
lvc.pszText = (char*)txt3[1];
ListView_InsertColumn(hL[ASM_WND],1,&lvc);
lvc.pszText = (char*)txt3[2];
ListView_InsertColumn(hL[ASM_WND],2,&lvc);
// SendMessage(hL[ASM_WND], LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER,
// LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER);
// Input / Output
hE_I = CreateWindowEx(0,"edit","",WS_CHILD | WS_VISIBLE,0,0,1,1,hh,(HMENU)1004,GetModuleHandle(0),0);
// without AUTOHSCROLL, output window text is always supposed to wordwrap
hE_O = CreateWindowEx(0,"edit","",WS_VSCROLL | WS_BORDER | WS_CHILD | WS_VISIBLE | ES_MULTILINE,0,0,1,1,hh,(HMENU)1003,GetModuleHandle(0),0);
SendMessage(hE_I,WM_SETFONT,(WPARAM)DefFont, MAKELPARAM(TRUE,0));
SendMessage(hE_O,WM_SETFONT,(WPARAM)hF,MAKELPARAM(TRUE,0));
// subclass both the edit windows together
*wEdit = (WNDPROC)SetWindowLongPtr(hE_I, GWLP_WNDPROC, (LONG_PTR)ThisEditProc);
wEdit[1] = (WNDPROC)SetWindowLongPtr(hE_O, GWLP_WNDPROC, (LONG_PTR)ThisEditProc);
// Status
hS_S = CreateWindowEx(0,STATUSCLASSNAME,"",WS_CHILD | WS_VISIBLE,0,0,1,1,hh,(HMENU)1006,GetModuleHandle(0),0);
SendMessage(hS_S,WM_SETFONT,(WPARAM)DefFont,MAKELPARAM(TRUE,0));
int p[4] = {100,250,400,-1};
SendMessage(hS_S,SB_SETPARTS,4,(LPARAM)p);
// Dump Window
hL[DUMP_WND] = CreateWindowEx(0,"sLV","",LVStyle[2],0,0,100,100,hh,(HMENU)1002,GetModuleHandle(0),0);
//SendMessage(hL[DUMP_WND],WM_SETFONT,(WPARAM)DefFont,MAKELPARAM(TRUE,0));
strcpy (bigbuf, "Address");
lvc.pszText = bigbuf;
ListView_InsertColumn(hL[DUMP_WND],0,&lvc);
bigbuf[1] = 0; // use bigbuf to create 1 byte "strings"
for(i = 1 ; i < 17 ; i++)
{
if (i < 11)
*bigbuf = i - 1 + '0';
else
*bigbuf = i - 11 + 'A';
ListView_InsertColumn(hL[DUMP_WND],i,&lvc);
}
strcpy (bigbuf, "Ascii");
ListView_InsertColumn(hL[DUMP_WND],17,&lvc);
// SendMessage(hL[DUMP_WND], LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER, HIHI
// LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER);
#ifndef IS_WIN98
if (Group_OK)
{
wchar_t* txt5[] = {L"16-bit code",L"64-bit code",L"32-bit code",L"16-bit data",L"64-bit data",L"32-bit data",L"Illegal"};
ListView_EnableGroupView(hL[DUMP_WND],TRUE);
LVGROUP group1 = {0};
group1.cbSize = sizeof(LVGROUP);
group1.mask = LVGF_HEADER | LVGF_GROUPID;
for(int i = 0 ; i < 9 ; i++)
{
group1.pszHeader = txt5[i];
group1.iGroupId = i;
ListView_InsertGroup(hL[DUMP_WND], -1, &group1);
}
}
#endif
hT = CreateWindowEx(0,WC_TREEVIEW,"",TVS_DISABLEDRAGDROP | TVS_HASLINES | TVS_HASBUTTONS | WS_CHILD | WS_BORDER,
0,0,1,1,hh,(HMENU)1010,GetModuleHandle(0),0);
//SendMessage(hT,WM_SETFONT,(WPARAM)DefFont,MAKELPARAM(TRUE,0));
// Use the same messagehandler for the tree window as for ListViews
wTreeView = (WNDPROC)SetWindowLongPtr(hT, GWLP_WNDPROC, (LONG_PTR)LVProc);
// create button rows
int j = BX_SMP_PROCESSORS;
Bit32u WStyle = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;
if (j > 1)
{
while (--j > 0)
{
sprintf (bigbuf, "cpu%d",j); // number all the CPU buttons
hCPUt[j] = CreateWindowEx(0,"sBtn",bigbuf,WStyle,0,0,1,1,hh,(HMENU)(1030+j),GetModuleHandle(0),0);
}
strcpy (bigbuf, "CPU0"); // Handle CPU0 specially -- it is "selected"
hCPUt[0] = CreateWindowEx(0,"sBtn",bigbuf,WStyle,0,0,1,1,hh,(HMENU)MULTICPU_BTN_BASE,GetModuleHandle(0),0);
}
j = 5;
while (--j >= 0)
hBTN[j] = CreateWindowEx(0,"sBtn",BTxt[j],WStyle,0,0,1,1,hh,(HMENU)(BTN_BASE+j),GetModuleHandle(0),0);
// any other OS-specific GUI initialization goes here:
// Autosize a few columns once
// RegName column
CallWindowProc(wListView, hL[REG_WND], LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE_USEHEADER);
// "bytes" column
CallWindowProc(wListView, hL[ASM_WND], LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE_USEHEADER);
// and the empty MemDump columns
for (int i = 0; i < 17; i++)
CallWindowProc(wListView, hL[DUMP_WND], LVM_SETCOLUMNWIDTH, i, LVSCW_AUTOSIZE_USEHEADER);
// load the extra resizing/docking cursors
hCursResize = LoadCursor (NULL,IDC_SIZEWE);
hCursDock = LoadCursor (NULL,IDC_CROSS);
SetTimer(hh,2,500,NULL); // request timer ticks every half a second (to update VGAW)
UpdInProgress[0] = FALSE;
UpdInProgress[1] = FALSE;
UpdInProgress[2] = FALSE;
ResizeColmns = TRUE; // do the initial resize on hex, address columns
// Input window caret is created in SetSizeIOS, when the WM_SIZE message arrives
break;
}
case WM_SIZE:
{
RECT rc;
int i, j, k;
bx_bool unchanged = FALSE;
if (hY == NULL) // sometimes WM_SIZE is called before OSInit completes!
hY = hh;
// Mapping mode is MM_TEXT (Def), so Yvalues increase DOWN, all values are in pixels.
GetClientRect(hY,&rc);
// don't "resize" on minimize, if window is too small, or "unchanged"
if (CurYSize == (unsigned int)rc.bottom && CurXSize == (unsigned int)rc.right)
unchanged = TRUE;
if (rc.bottom > 100 && rc.right > 150 && unchanged == FALSE)
{
// set up the Input/Output/Status windows
CurYSize = rc.bottom;
CurXSize = rc.right;
SetSizeIOS(CurXSize,CurYSize);
// need to recalculate List widths, with the same proportions as before
i = ListWidthPix[0] + ListWidthPix[1] + ListWidthPix[2];
if (i == 0)
i = 1;
j = (ListWidthPix[2] * CurXSize) / i;
k = (ListWidthPix[1] * CurXSize) / i;
ListWidthPix[0] = CurXSize - k - j; // Register list
ListWidthPix[1] = k; // Asm
ListWidthPix[2] = j; // MemDump
MoveLists();
}
break;
}
case WM_CHAR:
{
if (ww != VK_RETURN)
CallWindowProc(*wEdit, hE_I, WM_CHAR, (WPARAM) ww, (LPARAM) ll);
break;
}
case WM_SYSKEYDOWN: // ww == key + ALT
{
HotKey ((int)ww, -1, 0, 0); // currently, no hotkeys have both Alt and something else
break;
}
case WM_KEYDOWN:
{
int Control = GetKeyState(VK_CONTROL); // key is down if val is negative
int Shift = GetKeyState(VK_SHIFT);
if (HotKey ((int)ww, 0, Shift, Control) < 0)
CallWindowProc (*wEdit, hE_I, WM_KEYDOWN, (LPARAM) ww, (LPARAM) ll);
return 0;
}
case WM_COMMAND:
{
int LW = LOWORD(ww);
if (LW >= BTN_BASE && LW <= BTN_BASE +4) // convert button IDs to command IDs
LW = BtnLkup [LW - BTN_BASE];
else if (LW >= MULTICPU_BTN_BASE && LW < MULTICPU_BTN_BASE + BX_MAX_SMP_THREADS_SUPPORTED)
{
unsigned int newCPU = LW - MULTICPU_BTN_BASE;
if (CurrentCPU != newCPU)
{
// change text on CurrentCPU button to lowercase
strcpy (tmpcb, "cpu0");
tmpcb[3] = CurrentCPU + '0';
SendMessage (hCPUt[CurrentCPU],WM_SETTEXT,(WPARAM) 0 ,(LPARAM) tmpcb);
// change text on newCPU button to UPPERCASE
strcpy (tmpcb, "CPU0");
tmpcb[3] = newCPU + '0';
SendMessage (hCPUt[newCPU],WM_SETTEXT,(WPARAM) 0 ,(LPARAM) tmpcb);
CurrentCPU = newCPU;
BottomAsmLA = ~0; // force an ASM autoload, to repaint
if (AtBreak != FALSE) // if at a break, pretend it just happened
OnBreak(); // refresh the ASM and Register windows
}
return 0;
}
if (LW >= CMD_BREAK && LW < CMD_MODEB) // Does not include "Step"s or Options
{
if (AtBreak == FALSE)
{
SIM->debug_break(); // On a menu click always break (with some exceptions)
}
}
ActivateMenuItem (LW); // run the code to perform the selected menu task
return 0;
}
case WM_NOTIFY:
{
// key down
NMHDR* n = (NMHDR*)ll;
if (n->code == LVN_KEYDOWN)
{
NMLVKEYDOWN* key = (NMLVKEYDOWN*)ll; // pass any keystrokes from listview up to parent
SendMessage(hh,WM_KEYDOWN,key->wVKey,0);
}
if (n->code == (UINT)NM_CUSTOMDRAW && n->hwndFrom == hL[ASM_WND]) // custom drawing of ASM window
{
// highlight the breakpoints, and current opcode, if any
NMLVCUSTOMDRAW *d = (NMLVCUSTOMDRAW *) ll;
if (d->nmcd.dwDrawStage == CDDS_PREPAINT)
return CDRF_NOTIFYITEMDRAW;
if (d->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) // select the "active" ASM line
{
unsigned int fgclr = 0; // normal text color is black
d->clrTextBk = RGB(255,255,255); // background is white
if (!AtBreak)
d->clrTextBk = RGB(210,210,210); // unless sim is "running"
bx_address h = (bx_address) AsmLA[d->nmcd.dwItemSpec];
if (h == CurrentAsmLA)
fgclr = 1; // current opcode is colored dark green
int j= BreakCount;
while (--j >= 0) // loop over all breakpoints
{
// brk list is sorted -- if the value goes too low, end the loop
// And I know for a fact that some complers are soooo stupid that they
// will repeat the following test twice, unless you force them not to.
bx_address i = BrkLAddr[j] - h;
// if (BrkLAddr[j] < h)
if (i < 0)
j = 0; // force the loop to end if it goes too far
// else if (BrkLAddr[j] == h)
else if (i == 0)
fgclr |= 2; // change color if on a breakpoint
}
d->clrText = AsmColors[fgclr];
if (fgclr != 0) // if this row has color, process its subitems further
{
SetWindowLong(hh, DWL_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW);
return CDRF_NOTIFYSUBITEMDRAW;
}
}
else if (d->nmcd.dwDrawStage == (CDDS_SUBITEM | CDDS_ITEMPREPAINT) && d->iSubItem == 2)
{
// add extra visual feedback to a "colored" ASM mnemonic cell
// -- but don't try to recalculate breakpoints! Just "guess" from the color.
int fontattrib = 3;
if (d->clrText == AsmColors[1]) // green = current RIP = bold
fontattrib = 1;
else if (d->clrText == AsmColors[2]) // red = brkpt = italic
fontattrib = 2;
SelectObject (d->nmcd.hdc, CustomFont[fontattrib]);
return CDRF_NEWFONT | CDRF_DODEFAULT;
}
break;
}
if (n->code == (UINT)NM_CUSTOMDRAW && n->hwndFrom == hL[DUMP_WND]) // custom drawing of data window
{
NMLVCUSTOMDRAW *d = (NMLVCUSTOMDRAW *) ll;
if (d->nmcd.dwDrawStage == CDDS_PREPAINT)
return CDRF_NOTIFYITEMDRAW;
d->clrTextBk = RGB(255,255,255); // background is white
if (!AtBreak)
d->clrTextBk = RGB(210,210,210); // unless sim is "running"
else if (DViewMode == VIEW_STACK && d->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
{
// highlight changed lines in stack
int j = d->nmcd.dwItemSpec;
if (j < 0 || j >= STACK_ENTRIES) // make sure the line # is legal
;
else if (StackEntChg[j] != FALSE)
d->clrText = RGB(255,0,0); // changed entry = red
}
if (DumpAlign != 1 || LinearDump != FALSE || DViewMode != VIEW_MEMDUMP)
break;
// highlight any physical watchpoints in physdump mode
if (d->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
{
SetWindowLong(hh, DWL_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW);
return CDRF_NOTIFYSUBITEMDRAW;
}
if (d->nmcd.dwDrawStage == (CDDS_SUBITEM | CDDS_ITEMPREPAINT))
{
d->clrText = RGB(0,0,0); // assume black text
if (d->iSubItem != 0)
{
// For each subitem, calculate its equivalent physmem address
bx_phy_address h = (bx_phy_address) DumpStart +
16*(d->nmcd.dwItemSpec) + d->iSubItem -1;
int j = num_write_watchpoints;
int i = num_read_watchpoints;
while (j > 0)
{
if (write_watchpoint[--j].addr == h)
{
d->clrTextBk = RGB(0,0,0); // black background
d->clrText = RGB(255,0,150); // write watchpoint
j = -1; // on a match j<0 -- else j == 0
}
}
while (--i >= 0)
{
if (read_watchpoint[i].addr == h)
{
if (j < 0) // BOTH read and write
d->clrText = RGB(0,170,255);
else
{
d->clrTextBk = RGB(0,0,0); // black background
d->clrText = RGB(130,255,0); // read watchpoint
}
i = 0; // end the loop on a match
}
}
}
}
break;
}
if (n->code == (UINT)NM_CUSTOMDRAW && n->hwndFrom == hL[REG_WND]) // custom drawing of register window
{
// highlight changed registers
NMLVCUSTOMDRAW *d = (NMLVCUSTOMDRAW *) ll;
if (d->nmcd.dwDrawStage == CDDS_PREPAINT)
return CDRF_NOTIFYITEMDRAW;
if (d->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
{
int i = d->nmcd.dwItemSpec;
Bit8u ClrFlgs = RegColor[ RitemToRnum[i] ];
d->clrText = RGB(0,0,0);
d->clrTextBk = RGB(255,255,255);
// RitemToRnum converts a ListView row number to the corresponding Register number.
// RegColor has the 0x80 bit set if the register is supposed to be red.
// Background color index is in the low nibble of ClrFlgs/RegColor.
if (SeeRegColors != FALSE)
d->clrTextBk = ColorList[ClrFlgs &7];
if ((ClrFlgs & 0x80) != 0) // should this register be red?
d->clrText = RGB(255,0,0);
if (!AtBreak)
d->clrTextBk = RGB(210,210,210); // gray out the background if "running"
}
break;
}
if (n->code == (UINT)NM_DBLCLK)
{
if (AtBreak == FALSE)
break;
if (n->hwndFrom == hL[REG_WND])
ChangeReg();
else if (n->hwndFrom == hL[ASM_WND]) // doubleclick a breakpoint on ASM window
SetBreak(SelectedEntry);
else if (n->hwndFrom == hL[DUMP_WND])
{
if (DViewMode == VIEW_MEMDUMP) // Change values in memory locations
{
if (GetKeyState(VK_SHIFT) < 0)
SetWatchpoint(&num_write_watchpoints,write_watchpoint);
else if (GetKeyState(VK_MENU) < 0) // ALT keys
SetWatchpoint(&num_read_watchpoints,read_watchpoint);
else
{
int L = CallWindowProc(wListView, hL[DUMP_WND], LVM_GETNEXTITEM,(WPARAM) -1,MAKELPARAM(LVNI_SELECTED, 0));
if (L >= 0)
SetMemLine(L);
}
}
else if (DViewMode == VIEW_BREAK) // delete breakpoint in Break window
{
// HIHI I should be using SelectedEntry, instead of SelectedBID, I think
// HIHI -- the BID variable is not making my life easier
i = SelectedBID & 0xf;
if (SelectedBID >= 0x80000) // read watchpoint
{
if (RWP_Snapshot[i] == read_watchpoint[i].addr)
DelWatchpoint(read_watchpoint, &num_read_watchpoints, i);
}
else if (SelectedBID >= 0x40000) // write watchpoint
{
if (WWP_Snapshot[i] == write_watchpoint[i].addr)
DelWatchpoint(write_watchpoint, &num_write_watchpoints, i);
}
else
{
i = SelectedBID & 0xffff;
if (i != 0) // determine the breakpoint TYPE
{
if (SelectedBID > 0x20000)
bx_dbg_del_pbreak(i);
else if (SelectedBID > 0x10000)
bx_dbg_del_vbreak(i);
else // linear brkpt
bx_dbg_del_lbreak(SelectedBID);
}
ParseBkpt();
InvalidateRect(hL[ASM_WND],0,TRUE); // breakpoint colors may have changed
}
RefreshDataWin();
}
}
}
break;
}
case WM_TIMER:
{
if (PO_Tdelay > 0) // output window is delaying display of a partial line?
{
if (--PO_Tdelay == 0) // on a timeout, add a lf to complete the line
ParseIDText ("\n");
}
UpdateStatus();
vgaw_refresh = TRUE; // ask bochs to update its own VGA window
break;
}
case WM_NCMOUSEMOVE:
{
// turn off any sizing operation if the cursor strays off the listviews
Sizing = 0;
// also turn off any half-completed mouseclicks
xClick = -1;
break;
}
case WM_CLOSE:
{
GetWindowRect(hY, &rY);
bx_user_quit = 1;
SIM->debug_break();
KillTimer(hh,2);
if (*CustomFont != DefFont)
DeleteObject (*CustomFont);
DeleteObject(CustomFont[1]);
DeleteObject(CustomFont[2]);
DeleteObject(CustomFont[3]);
DestroyWindow(hY);
hY = NULL;
break;
}
}
return DefWindowProc(hh,mm,ww,ll);
}
void HitBreak()
{
// Sim is at a "break".
if (AtBreak == FALSE)
{
AtBreak = TRUE;
StatusChange = TRUE;
}
if (doDumpRefresh != FALSE)
RefreshDataWin();
OnBreak();
}
// This function must be called immediately after bochs starts
bx_bool OSInit()
{
TEXTMETRIC tm;
if (doOneTimeInit) {
InitCommonControls(); // start the common control dll
SpListView(); // create superclass for listviews to use when they are created
SpBtn(); // same for buttons
WNDCLASSEX wC = {0};
wC.cbSize = sizeof(wC);
wC.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
hCursArrow = LoadCursor(NULL,IDC_ARROW);
wC.hCursor = hCursArrow;
wC.hInstance = GetModuleHandle(0);
wC.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS | CS_DBLCLKS;
wC.lpfnWndProc = B_WP;
wC.cbWndExtra = sizeof(void*);
wC.lpszClassName = "bochs_dbg_x";
wC.hIcon = LoadIcon(GetModuleHandle(0),"ICON_D");
wC.hIconSm = LoadIcon(GetModuleHandle(0),"ICON_D");
RegisterClassEx(&wC);
doOneTimeInit = FALSE;
}
CurXSize = 0;
CurYSize = 0;
HMENU hTopMenu = LoadMenu(GetModuleHandle(0),"MENU_1"); // build the menus from the resource
hOptMenu = GetSubMenu(hTopMenu, 2); // need the main menu handles
hViewMenu = GetSubMenu(hTopMenu, 1);
hCmdMenu = GetSubMenu(hTopMenu, 0);
hY = CreateWindowEx(0,"bochs_dbg_x","Bochs Enhanced Debugger",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
0,hTopMenu,GetModuleHandle(0),0);
if (hY == NULL)
return FALSE;
if (windowInit) {
if ((rY.left >= 0) && (rY.top >= 0)) {
MoveWindow(hY, rY.left, rY.top, rY.right-rY.left, rY.bottom-rY.top, TRUE);
} else {
ShowWindow(hY, SW_MAXIMIZE);
}
}
if (!fontInit) {
*CustomFont = DefFont; // create the deffont with modded attributes (bold, italic)
HDC hdc = GetDC(hY);
memset(&mylf, 0, sizeof(LOGFONT));
mylf.lfWeight = FW_NORMAL;
GetTextFace(hdc, LF_FULLFACESIZE, mylf.lfFaceName); // (constant is max length of a fontname)
GetTextMetrics(hdc, &tm);
ReleaseDC(hY, hdc);
mylf.lfHeight = -(tm.tmHeight); // request a TOTAL font height of tmHeight
} else {
*CustomFont = CreateFontIndirect(&mylf);
}
// create a bold version of the deffont
mylf.lfWeight = FW_BOLD;
CustomFont[1] = CreateFontIndirect(&mylf);
// create a bold + italic version of the deffont
mylf.lfItalic = 1;
CustomFont[3] = CreateFontIndirect(&mylf);
// create an italic version of the deffont (turn off bold)
mylf.lfWeight = FW_NORMAL;
CustomFont[2] = CreateFontIndirect(&mylf);
if (fontInit) {
CallWindowProc(wListView,hL[REG_WND],WM_SETFONT,(WPARAM)*CustomFont,MAKELPARAM(TRUE,0));
CallWindowProc(wListView,hL[ASM_WND],WM_SETFONT,(WPARAM)*CustomFont,MAKELPARAM(TRUE,0));
CallWindowProc(wListView,hL[DUMP_WND],WM_SETFONT,(WPARAM)*CustomFont,MAKELPARAM(TRUE,0));
CallWindowProc(*wEdit,hE_I,WM_SETFONT,(WPARAM)*CustomFont,MAKELPARAM(TRUE,0));
SendMessage(hS_S,WM_SETFONT,(WPARAM)*CustomFont,MAKELPARAM(TRUE,0));
}
return TRUE;
}
void CloseDialog()
{
SendMessage(hY, WM_CLOSE, 0, 0);
}
// recurse displaying each leaf/branch of param_tree -- with values for each leaf
void MakeBL(HTREEITEM *h_P, bx_param_c *p)
{
HTREEITEM h_new;
bx_list_c *as_list = NULL;
int i = 0;
char tmpstr[BX_PATHNAME_LEN];
strcpy(tmpcb, p->get_name());
int j = strlen (tmpcb);
switch (p->get_type())
{
case BXT_LIST:
as_list = (bx_list_c *)p;
i = as_list->get_size();
break;
case BXT_PARAM_NUM:
case BXT_PARAM_BOOL:
case BXT_PARAM_ENUM:
case BXT_PARAM_STRING:
case BXT_PARAM_BYTESTRING:
p->dump_param(tmpstr, BX_PATHNAME_LEN);
sprintf(tmpcb + j,": %s", tmpstr);
break;
case BXT_PARAM_DATA:
sprintf (tmpcb + j,": binary data, size=%d",((bx_shadow_data_c*)p)->get_size());
break;
}
MakeTreeChild (h_P, i, &h_new);
if (i > 0)
{
while (--i >= 0)
MakeBL(&h_new, as_list->get(i)); // recurse for all children that are lists
}
}
bx_bool ParseOSSettings(const char *param, const char *value)
{
char *val2, *ptr;
if (!strcmp(param, "FontName")) {
memset(&mylf, 0, sizeof(LOGFONT));
mylf.lfWeight = FW_NORMAL;
strcpy(mylf.lfFaceName, value);
fontInit |= 1;
return 1;
} else if (!strcmp(param, "FontSize")) {
mylf.lfHeight = atoi(value);
fontInit |= 2;
return 1;
} else if (!strcmp(param, "MainWindow")) {
val2 = strdup(value);
ptr = strtok(val2, ",");
rY.left = atoi(ptr);
ptr = strtok(NULL, ",");
rY.top = atoi(ptr);
ptr = strtok(NULL, ",");
rY.right = atoi(ptr);
ptr = strtok(NULL, "\n");
rY.bottom = atoi(ptr);
windowInit = TRUE;
free(val2);
return 1;
}
return 0;
}
void WriteOSSettings(FILE *fd)
{
fprintf(fd, "FontName = %s\n", mylf.lfFaceName);
fprintf(fd, "FontSize = %d\n", mylf.lfHeight);
if (hY != NULL) {
GetWindowRect(hY, &rY);
}
fprintf(fd, "MainWindow = %d, %d, %d, %d\n", rY.left, rY.top, rY.right, rY.bottom);
}
#endif