|
|
/*++
Copyright (c) 1999-2001 Microsoft Corporation
Module Name:
cmnwin.cpp
Abstract:
This module contains the code for the common window architecture.
--*/
#include "precomp.hxx"
#pragma hdrstop
ULONG g_WinOptions = WOPT_AUTO_ARRANGE | WOPT_AUTO_DISASM;
LIST_ENTRY g_ActiveWin;
PCOMMONWIN_DATA g_IndexedWin[MAXVAL_WINDOW]; HWND g_IndexedHwnd[MAXVAL_WINDOW];
INDEXED_FONT g_Fonts[FONT_COUNT];
BOOL g_LineMarkers = FALSE;
#define CW_WSP_SIG3 '3WCW'
//
//
//
COMMONWIN_DATA::COMMONWIN_DATA(ULONG ChangeBy) : StateBuffer(ChangeBy) { m_Size.cx = 0; m_Size.cy = 0; m_CausedArrange = FALSE; // Creation is an automatic operation so
// InAutoOp is initialized to a non-zero value.
// After CreateWindow returns it is decremented.
m_InAutoOp = 1; m_enumType = MINVAL_WINDOW; m_Font = &g_Fonts[FONT_FIXED]; m_FontHeight = 0; m_LineHeight = 0; m_Toolbar = NULL; m_ShowToolbar = FALSE; m_ToolbarHeight = 0; m_MinToolbarWidth = 0; m_ToolbarEdit = NULL; }
void COMMONWIN_DATA::Validate() { Assert(MINVAL_WINDOW < m_enumType); Assert(m_enumType < MAXVAL_WINDOW); }
void COMMONWIN_DATA::SetFont(ULONG FontIndex) { m_Font = &g_Fonts[FontIndex]; m_FontHeight = m_Font->Metrics.tmHeight; m_LineHeight = m_Size.cy / m_FontHeight; }
BOOL COMMONWIN_DATA::CanCopy() { if (GetFocus() == m_ToolbarEdit) { DWORD Start, End; SendMessage(m_ToolbarEdit, EM_GETSEL, (WPARAM)&Start, (WPARAM)&End); return Start != End; } else { return FALSE; } }
BOOL COMMONWIN_DATA::CanCut() { if (GetFocus() == m_ToolbarEdit) { DWORD Start, End; SendMessage(m_ToolbarEdit, EM_GETSEL, (WPARAM)&Start, (WPARAM)&End); return Start != End; } else { return FALSE; } }
BOOL COMMONWIN_DATA::CanPaste() { if (GetFocus() == m_ToolbarEdit) { return TRUE; } else { return FALSE; } }
void COMMONWIN_DATA::Copy() { if (GetFocus() == m_ToolbarEdit) { SendMessage(m_ToolbarEdit, WM_COPY, 0, 0); } }
void COMMONWIN_DATA::Cut() { if (GetFocus() == m_ToolbarEdit) { SendMessage(m_ToolbarEdit, WM_CUT, 0, 0); } }
void COMMONWIN_DATA::Paste() { if (GetFocus() == m_ToolbarEdit) { SendMessage(m_ToolbarEdit, WM_PASTE, 0, 0); } }
BOOL COMMONWIN_DATA::CanSelectAll() { return FALSE; }
void COMMONWIN_DATA::SelectAll() { }
BOOL COMMONWIN_DATA::HasEditableProperties() { return FALSE; }
BOOL COMMONWIN_DATA::EditProperties() /*++
Returns TRUE - If properties were edited FALSE - If nothing was changed --*/ { return FALSE; }
HMENU COMMONWIN_DATA::GetContextMenu(void) { return NULL; }
void COMMONWIN_DATA::OnContextMenuSelection(UINT Item) { // Nothing to do.
}
BOOL COMMONWIN_DATA::CanGotoLine(void) { return FALSE; }
void COMMONWIN_DATA::GotoLine(ULONG Line) { // Do nothing.
}
void COMMONWIN_DATA::Find(PTSTR Text, ULONG Flags) { // Do nothing.
}
BOOL COMMONWIN_DATA::CodeExprAtCaret(PSTR Expr, PULONG64 Offset) { return FALSE; }
void COMMONWIN_DATA::ToggleBpAtCaret(void) { char CodeExpr[MAX_OFFSET_EXPR]; ULONG64 Offset; if (!CodeExprAtCaret(CodeExpr, &Offset) && Offset != DEBUG_INVALID_OFFSET) { MessageBeep(0); ErrorBox(NULL, 0, ERR_No_Code_For_File_Line); return; }
ULONG CurBpId = DEBUG_ANY_ID;
// This doesn't work too well with duplicate
// breakpoints, but that should be a minor problem.
if (IsBpAtOffset(NULL, Offset, &CurBpId) != BP_NONE) { PrintStringCommand(UIC_SILENT_EXECUTE, "bc %d", CurBpId); } else { PrintStringCommand(UIC_SILENT_EXECUTE, "bp %s", CodeExpr); } }
BOOL COMMONWIN_DATA::OnCreate(void) { return TRUE; }
LRESULT COMMONWIN_DATA::OnCommand(WPARAM wParam, LPARAM lParam) { return 1; }
void COMMONWIN_DATA::OnSetFocus(void) { }
void COMMONWIN_DATA::OnSize(void) { RECT Rect; // Resize the toolbar.
if (m_Toolbar != NULL && m_ShowToolbar) { // If the toolbar gets too small sometimes it's better
// to just let it get clipped rather than have it
// try to fit into a narrow column.
if (m_Size.cx >= m_MinToolbarWidth) { MoveWindow(m_Toolbar, 0, 0, m_Size.cx, m_ToolbarHeight, TRUE); }
// Record what size it ended up.
GetClientRect(m_Toolbar, &Rect); m_ToolbarHeight = Rect.bottom - Rect.top;
if (m_FontHeight != 0) { if (m_ToolbarHeight >= m_Size.cy) { m_LineHeight = 0; } else { m_LineHeight = (m_Size.cy - m_ToolbarHeight) / m_FontHeight; } } } else { Assert(m_ToolbarHeight == 0); } }
void COMMONWIN_DATA::OnButtonDown(ULONG Button) { }
void COMMONWIN_DATA::OnButtonUp(ULONG Button) { }
void COMMONWIN_DATA::OnMouseMove(ULONG Modifiers, ULONG X, ULONG Y) { }
void COMMONWIN_DATA::OnTimer(WPARAM TimerId) { }
LRESULT COMMONWIN_DATA::OnGetMinMaxInfo(LPMINMAXINFO Info) { return 1; }
LRESULT COMMONWIN_DATA::OnVKeyToItem(WPARAM wParam, LPARAM lParam) { return -1; }
LRESULT COMMONWIN_DATA::OnNotify(WPARAM wParam, LPARAM lParam) { return 0; }
void COMMONWIN_DATA::OnUpdate(UpdateType Type) { }
void COMMONWIN_DATA::OnDestroy(void) { }
LRESULT COMMONWIN_DATA::OnOwnerDraw(UINT uMsg, WPARAM wParam, LPARAM lParam) { return 0; }
ULONG COMMONWIN_DATA::GetWorkspaceSize(void) { return 3 * sizeof(ULONG) + sizeof(WINDOWPLACEMENT); }
PUCHAR COMMONWIN_DATA::SetWorkspace(PUCHAR Data) { // First store the special signature that marks
// this version of the workspace data.
*(PULONG)Data = CW_WSP_SIG3; Data += sizeof(ULONG);
// Store the size saved by this layer.
*(PULONG)Data = COMMONWIN_DATA::GetWorkspaceSize(); Data += sizeof(ULONG);
//
// Store the actual data.
//
*(PULONG)Data = m_ShowToolbar; Data += sizeof(ULONG); LPWINDOWPLACEMENT Place = (LPWINDOWPLACEMENT)Data; Place->length = sizeof(WINDOWPLACEMENT); GetWindowPlacement(m_Win, Place); Data += sizeof(WINDOWPLACEMENT);
return Data; }
PUCHAR COMMONWIN_DATA::ApplyWorkspace1(PUCHAR Data, PUCHAR End) { ULONG_PTR Size = End - Data; // There are three versions of the base COMMONWIN data.
// 1. RECT.
// 2. WINDOWPLACEMENT.
// 3. CW_WSP_SIG3 sized block.
// All three cases can be easily distinguished.
if (Size > 2 * sizeof(ULONG) && *(PULONG)Data == CW_WSP_SIG3 && Size >= *(PULONG)(Data + sizeof(ULONG))) { Size = *(PULONG)(Data + sizeof(ULONG)) - 2 * sizeof(ULONG); Data += 2 * sizeof(ULONG); if (Size >= sizeof(ULONG)) { SetShowToolbar(*(PULONG)Data); Size -= sizeof(ULONG); Data += sizeof(ULONG); } }
if (Size >= sizeof(WINDOWPLACEMENT) && ((LPWINDOWPLACEMENT)Data)->length == sizeof(WINDOWPLACEMENT)) { LPWINDOWPLACEMENT Place = (LPWINDOWPLACEMENT)Data;
if (!IsAutoArranged(m_enumType)) { SetWindowPlacement(m_Win, Place); } return (PUCHAR)(Place + 1); } else { LPRECT Rect = (LPRECT)Data; Assert((PUCHAR)(Rect + 1) <= End); if (!IsAutoArranged(m_enumType)) { MoveWindow(m_Win, Rect->left, Rect->top, (Rect->right - Rect->left), (Rect->bottom - Rect->top), TRUE); } return (PUCHAR)(Rect + 1); } }
void COMMONWIN_DATA::UpdateColors(void) { // Nothing to do.
}
void COMMONWIN_DATA::UpdateSize(ULONG Width, ULONG Height) { m_Size.cx = Width; m_Size.cy = Height; if (m_FontHeight != 0) { m_LineHeight = m_Size.cy / m_FontHeight; } }
void COMMONWIN_DATA::SetShowToolbar(BOOL Show) { if (!m_Toolbar) { return; } m_ShowToolbar = Show; if (m_ShowToolbar) { ShowWindow(m_Toolbar, SW_SHOW); } else { ShowWindow(m_Toolbar, SW_HIDE); m_ToolbarHeight = 0; }
OnSize(); if (g_Workspace != NULL) { g_Workspace->AddDirty(WSPF_DIRTY_WINDOWS); } }
PCOMMONWIN_DATA NewWinData(WIN_TYPES Type) { switch(Type) { case DOC_WINDOW: return new DOCWIN_DATA; case WATCH_WINDOW: return new WATCHWIN_DATA; case LOCALS_WINDOW: return new LOCALSWIN_DATA; case CPU_WINDOW: return new CPUWIN_DATA; case DISASM_WINDOW: return new DISASMWIN_DATA; case CMD_WINDOW: return new CMDWIN_DATA; case SCRATCH_PAD_WINDOW: return new SCRATCH_PAD_DATA; case MEM_WINDOW: return new MEMWIN_DATA; #if 0
case QUICKW_WINDOW: // XXX drewb - Unimplemented.
return new QUICKWWIN_DATA; #endif
case CALLS_WINDOW: return new CALLSWIN_DATA; case PROCESS_THREAD_WINDOW: return new PROCESS_THREAD_DATA; default: Assert(FALSE); return NULL; } }
LRESULT CALLBACK COMMONWIN_DATA::WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { PCOMMONWIN_DATA pWinData = GetCommonWinData(hwnd);
#if 0
{ DebugPrint("CommonWin msg %X for %p, args %X %X\n", uMsg, pWinData, wParam, lParam); } #endif
if (uMsg != WM_CREATE && pWinData == NULL) { return DefMDIChildProc(hwnd, uMsg, wParam, lParam); } switch (uMsg) { case WM_CREATE: RECT rc; COMMONWIN_CREATE_DATA* Data;
Assert(NULL == pWinData);
Data = (COMMONWIN_CREATE_DATA*) ((LPMDICREATESTRUCT) (((CREATESTRUCT *)lParam)->lpCreateParams))->lParam;
pWinData = NewWinData(Data->Type); if (!pWinData) { return -1; // Fail window creation
} Assert(pWinData->m_enumType == Data->Type);
pWinData->m_Win = hwnd; GetClientRect(hwnd, &rc); pWinData->m_Size.cx = rc.right; pWinData->m_Size.cy = rc.bottom; if ( !pWinData->OnCreate() ) { delete pWinData; return -1; // Fail window creation
}
// store this in the window
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pWinData);
#if DBG
pWinData->Validate(); #endif
g_IndexedWin[Data->Type] = pWinData; g_IndexedHwnd[Data->Type] = hwnd; InsertHeadList(&g_ActiveWin, &pWinData->m_ActiveWin);
if (g_Workspace != NULL) { g_Workspace->AddDirty(WSPF_DIRTY_WINDOWS); }
SendMessage(hwnd, WM_SETICON, 0, (LPARAM) LoadIcon(g_hInst, MAKEINTRESOURCE(pWinData->m_enumType + MINVAL_WINDOW_ICON)));
// A new buffer has been created so put it in the list
// then wake up the engine to fill it.
Dbg_EnterCriticalSection(&g_QuickLock); InsertHeadList(&g_StateList, pWinData); Dbg_LeaveCriticalSection(&g_QuickLock); UpdateEngine();
// Force initial updates so that the window starts
// out with a state which matches the current debug
// session's state.
PostMessage(hwnd, WU_UPDATE, UPDATE_BUFFER, 0); PostMessage(hwnd, WU_UPDATE, UPDATE_EXEC, 0);
if (g_WinOptions & WOPT_AUTO_ARRANGE) { Arrange(); } return 0;
case WM_COMMAND: if (pWinData->OnCommand(wParam, lParam) == 0) { return 0; } break; case WM_SETFOCUS: pWinData->OnSetFocus(); break;
case WM_MOVE: // When the frame window is minimized or restored
// a move to 0,0 comes through. Ignore this so
// as to not trigger the warning.
if (!IsIconic(g_hwndFrame) && lParam != 0) { DisplayAutoArrangeWarning(pWinData); } if (g_Workspace != NULL) { g_Workspace->AddDirty(WSPF_DIRTY_WINDOWS); } return DefWindowProc(hwnd, uMsg, wParam, lParam); case WM_SIZE: if (wParam == SIZE_MAXHIDE || wParam == SIZE_MAXSHOW) { // We don't care about cover/uncover events.
break; } DisplayAutoArrangeWarning(pWinData); if (g_Workspace != NULL) { g_Workspace->AddDirty(WSPF_DIRTY_WINDOWS); } pWinData->UpdateSize(LOWORD(lParam), HIWORD(lParam));
// No need to run sizing code for minimize.
if (wParam == SIZE_MINIMIZED) { // The minimized window will leave a hole so
// arrange to fill it and leave space for the
// minimized window.
if (g_WinOptions & WOPT_AUTO_ARRANGE) { pWinData->m_CausedArrange = TRUE; Arrange(); } break; }
if (wParam == SIZE_RESTORED && pWinData->m_CausedArrange) { // If we're restoring a window that caused
// a rearrange when it was minimized we
// need to update things to account for it.
pWinData->m_CausedArrange = FALSE; if (g_WinOptions & WOPT_AUTO_ARRANGE) { Arrange(); } } else if (wParam == SIZE_MAXIMIZED) { // Ask for a rearrange on restore just
// for consistency with minimize.
pWinData->m_CausedArrange = TRUE; }
pWinData->OnSize(); break;
case WM_LBUTTONDOWN: pWinData->OnButtonDown(MK_LBUTTON); return 0; case WM_LBUTTONUP: pWinData->OnButtonUp(MK_LBUTTON); return 0; case WM_MBUTTONDOWN: pWinData->OnButtonDown(MK_MBUTTON); return 0; case WM_MBUTTONUP: pWinData->OnButtonUp(MK_MBUTTON); return 0; case WM_RBUTTONDOWN: pWinData->OnButtonDown(MK_RBUTTON); return 0; case WM_RBUTTONUP: pWinData->OnButtonUp(MK_RBUTTON); return 0;
case WM_MOUSEMOVE: pWinData->OnMouseMove((ULONG)wParam, LOWORD(lParam), HIWORD(lParam)); return 0;
case WM_TIMER: pWinData->OnTimer(wParam); return 0;
case WM_GETMINMAXINFO: if (pWinData->OnGetMinMaxInfo((LPMINMAXINFO)lParam) == 0) { return 0; } break; case WM_VKEYTOITEM: return pWinData->OnVKeyToItem(wParam, lParam); case WM_NOTIFY: return pWinData->OnNotify(wParam, lParam); case WU_UPDATE: pWinData->OnUpdate((UpdateType)wParam); return 0;
case WU_RECONFIGURE: pWinData->OnSize(); break;
case WM_DESTROY: pWinData->OnDestroy(); SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL); g_IndexedWin[pWinData->m_enumType] = NULL; g_IndexedHwnd[pWinData->m_enumType] = NULL; RemoveEntryList(&pWinData->m_ActiveWin); if (g_Workspace != NULL) { g_Workspace->AddDirty(WSPF_DIRTY_WINDOWS); } // Mark this buffer as ready for cleanup by the
// engine when it gets around to it.
pWinData->m_Win = NULL; if (pWinData == g_FindLast) { g_FindLast = NULL; } UpdateEngine(); if (g_WinOptions & WOPT_AUTO_ARRANGE) { Arrange(); } break; case WM_MEASUREITEM: case WM_DRAWITEM: //
// Both these messages must be handled by owner drawn windows
//
return pWinData->OnOwnerDraw(uMsg, wParam, lParam); } return DefMDIChildProc(hwnd, uMsg, wParam, lParam); }
//
//
//
SINGLE_CHILDWIN_DATA::SINGLE_CHILDWIN_DATA(ULONG ChangeBy) : COMMONWIN_DATA(ChangeBy) { m_hwndChild = NULL; }
void SINGLE_CHILDWIN_DATA::Validate() { COMMONWIN_DATA::Validate();
Assert(m_hwndChild); }
void SINGLE_CHILDWIN_DATA::SetFont(ULONG FontIndex) { COMMONWIN_DATA::SetFont(FontIndex);
SendMessage(m_hwndChild, WM_SETFONT, (WPARAM) m_Font->Font, (LPARAM) TRUE ); }
BOOL SINGLE_CHILDWIN_DATA::CanCopy() { if (GetFocus() != m_hwndChild) { return COMMONWIN_DATA::CanCopy(); } switch (m_enumType) { default: Assert(!"Unknown type"); return FALSE;
case CMD_WINDOW: Assert(!"Should not be handled here since this is only for windows" " with only one child window."); return FALSE;
case WATCH_WINDOW: case LOCALS_WINDOW: case CPU_WINDOW: case QUICKW_WINDOW: return -1 != ListView_GetNextItem(m_hwndChild, -1, // Find the first match
LVNI_FOCUSED );
case CALLS_WINDOW: return LB_ERR != SendMessage(m_hwndChild, LB_GETCURSEL, 0, 0);
case DOC_WINDOW: case DISASM_WINDOW: case MEM_WINDOW: case SCRATCH_PAD_WINDOW: CHARRANGE chrg; SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&chrg); return chrg.cpMin != chrg.cpMax;
case PROCESS_THREAD_WINDOW: return NULL != TreeView_GetSelection(m_hwndChild); } }
BOOL SINGLE_CHILDWIN_DATA::CanCut() { if (GetFocus() != m_hwndChild) { return COMMONWIN_DATA::CanCut(); } switch (m_enumType) { default: Assert(!"Unknown type"); return FALSE;
case CMD_WINDOW: Assert(!"Should not be handled here since this is only for windows" " with only one child window."); return FALSE;
case WATCH_WINDOW: case LOCALS_WINDOW: case CPU_WINDOW: case QUICKW_WINDOW: case CALLS_WINDOW: case DOC_WINDOW: case DISASM_WINDOW: case MEM_WINDOW: case PROCESS_THREAD_WINDOW: return FALSE; case SCRATCH_PAD_WINDOW: CHARRANGE chrg; SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&chrg); return chrg.cpMin != chrg.cpMax; } }
BOOL SINGLE_CHILDWIN_DATA::CanPaste() { if (GetFocus() != m_hwndChild) { return COMMONWIN_DATA::CanPaste(); } switch (m_enumType) { default: Assert(!"Unknown type"); return FALSE;
case CMD_WINDOW: Assert(!"Should not be handled here since this is only for windows" " with only one child window."); return FALSE;
case WATCH_WINDOW: case LOCALS_WINDOW: case CPU_WINDOW: case QUICKW_WINDOW: case CALLS_WINDOW: case DOC_WINDOW: case DISASM_WINDOW: case MEM_WINDOW: case PROCESS_THREAD_WINDOW: return FALSE; case SCRATCH_PAD_WINDOW: return TRUE; } }
void SINGLE_CHILDWIN_DATA::Copy() { if (GetFocus() != m_hwndChild) { COMMONWIN_DATA::Copy(); } else { SendMessage(m_hwndChild, WM_COPY, 0, 0); } }
void SINGLE_CHILDWIN_DATA::Cut() { if (GetFocus() != m_hwndChild) { COMMONWIN_DATA::Paste(); } }
void SINGLE_CHILDWIN_DATA::Paste() { if (GetFocus() != m_hwndChild) { COMMONWIN_DATA::Paste(); } }
void SINGLE_CHILDWIN_DATA::OnSetFocus() { ::SetFocus(m_hwndChild); }
void SINGLE_CHILDWIN_DATA::OnSize(void) { COMMONWIN_DATA::OnSize(); MoveWindow(m_hwndChild, 0, m_ToolbarHeight, m_Size.cx, m_Size.cy - m_ToolbarHeight, TRUE); }
//
//
//
PROCESS_THREAD_DATA::PROCESS_THREAD_DATA() : SINGLE_CHILDWIN_DATA(512) { m_enumType = PROCESS_THREAD_WINDOW; m_NumProcesses = 0; }
void PROCESS_THREAD_DATA::Validate() { SINGLE_CHILDWIN_DATA::Validate();
Assert(PROCESS_THREAD_WINDOW == m_enumType); }
HRESULT PROCESS_THREAD_DATA::ReadState(void) { HRESULT Status; ULONG CurProc, CurThread; ULONG NumProc, NumThread; ULONG TotalThread, MaxThread; ULONG Proc, Thread; PULONG ProcIds, ProcSysIds, ProcThreads, ProcNames; PULONG ThreadIds, ThreadSysIds; ULONG ThreadsDone; char ExeName[MAX_PATH];
if ((Status = g_pDbgSystem->GetCurrentProcessId(&CurProc)) != S_OK || (Status = g_pDbgSystem->GetCurrentThreadId(&CurThread)) != S_OK || (Status = g_pDbgSystem->GetNumberProcesses(&NumProc)) != S_OK || (Status = g_pDbgSystem-> GetTotalNumberThreads(&TotalThread, &MaxThread)) != S_OK) { return Status; }
Empty(); ProcIds = (PULONG)AddData((NumProc * 4 + TotalThread * 2) * sizeof(ULONG)); if (ProcIds == NULL) { return E_OUTOFMEMORY; } ProcSysIds = ProcIds + NumProc; if ((Status = g_pDbgSystem-> GetProcessIdsByIndex(0, NumProc, ProcIds, ProcSysIds)) != S_OK) { return Status; }
ThreadsDone = 0; for (Proc = 0; Proc < NumProc; Proc++) { PSTR ExeStore;
// Refresh pointers on every loop in case a resize
// caused buffer movement.
ProcIds = (PULONG)GetDataBuffer(); ProcSysIds = ProcIds + NumProc; ProcThreads = ProcSysIds + NumProc; ProcNames = ProcThreads + NumProc; ThreadIds = ProcNames + NumProc + ThreadsDone; ThreadSysIds = ThreadIds + TotalThread; if ((Status = g_pDbgSystem-> SetCurrentProcessId(ProcIds[Proc])) != S_OK || FAILED(Status = g_pDbgSystem-> GetCurrentProcessExecutableName(ExeName, sizeof(ExeName), NULL)) || (Status = g_pDbgSystem->GetNumberThreads(&NumThread)) != S_OK || (Status = g_pDbgSystem-> GetThreadIdsByIndex(0, NumThread, ThreadIds, ThreadSysIds)) != S_OK) { goto CurProc; }
ProcThreads[Proc] = NumThread; ThreadsDone += NumThread; ProcNames[Proc] = strlen(ExeName) + 1;
if (ProcNames[Proc] > 1) { ExeStore = (PSTR)AddData(ProcNames[Proc]); if (ExeStore == NULL) { Status = E_OUTOFMEMORY; goto CurProc; }
strcpy(ExeStore, ExeName); } }
m_NumProcesses = NumProc; m_TotalThreads = TotalThread; Status = S_OK; CurProc: g_pDbgSystem->SetCurrentProcessId(CurProc);
return Status; }
BOOL PROCESS_THREAD_DATA::OnCreate(void) { if (!SINGLE_CHILDWIN_DATA::OnCreate()) { return FALSE; }
m_hwndChild = CreateWindow( WC_TREEVIEW, // class name
NULL, // title
WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES, // style
0, // x
0, // y
m_Size.cx, // width
m_Size.cy, // height
m_Win, // parent
(HMENU) IDC_PROCESS_TREE, // control id
g_hInst, // hInstance
NULL); // user defined data
if (!m_hwndChild) { return FALSE; } SetFont(FONT_FIXED); return TRUE; }
LRESULT PROCESS_THREAD_DATA::OnNotify(WPARAM Wpm, LPARAM Lpm) { LPNMTREEVIEW Tvn; HTREEITEM Sel;
Tvn = (LPNMTREEVIEW)Lpm; if (Tvn->hdr.idFrom != IDC_PROCESS_TREE) { return FALSE; } switch(Tvn->hdr.code) { case NM_DBLCLK: TVHITTESTINFO HitTest; if (!GetCursorPos(&HitTest.pt)) { break; } ScreenToClient(m_hwndChild, &HitTest.pt); Sel = TreeView_HitTest(m_hwndChild, &HitTest); if (Sel != NULL && (HitTest.flags & TVHT_ONITEMLABEL)) { SetCurThreadFromProcessTreeItem(m_hwndChild, Sel); } break; }
return FALSE; }
void PROCESS_THREAD_DATA::OnUpdate(UpdateType Type) { if (Type != UPDATE_BUFFER && Type != UPDATE_EXEC) { return; } HRESULT Status; Status = UiLockForRead(); if (Status != S_OK) { return; } ULONG NumThread; ULONG Proc, Thread; PULONG ProcIds, ProcSysIds, ProcThreads, ProcNames; PULONG ThreadIds, ThreadSysIds; char Text[MAX_PATH + 64]; PSTR Names; HTREEITEM CurThreadItem = NULL;
ProcIds = (PULONG)GetDataBuffer(); ProcSysIds = ProcIds + m_NumProcesses; ProcThreads = ProcSysIds + m_NumProcesses; ProcNames = ProcThreads + m_NumProcesses; ThreadIds = ProcNames + m_NumProcesses; ThreadSysIds = ThreadIds + m_TotalThreads; Names = (PSTR)(ThreadSysIds + m_TotalThreads); TreeView_DeleteAllItems(m_hwndChild);
for (Proc = 0; Proc < m_NumProcesses; Proc++) { HTREEITEM ProcItem; TVINSERTSTRUCT Insert;
sprintf(Text, "%03d:%x ", ProcIds[Proc], ProcSysIds[Proc]); if (ProcNames[Proc] > 1) { strcpy(Text + strlen(Text), Names); Names += strlen(Names) + 1; } Insert.hParent = TVI_ROOT; Insert.hInsertAfter = TVI_LAST; Insert.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM; Insert.item.pszText = Text; Insert.item.state = ProcIds[Proc] == g_CurProcessId ? TVIS_EXPANDED | TVIS_BOLD: 0; Insert.item.stateMask = TVIS_EXPANDED | TVIS_BOLD; // Parameter is the thread ID to set to select the given thread.
Insert.item.lParam = (LPARAM)ThreadIds[0]; ProcItem = TreeView_InsertItem(m_hwndChild, &Insert);
for (Thread = 0; Thread < ProcThreads[Proc]; Thread++) { HTREEITEM ThreadItem; sprintf(Text, "%03d:%x", ThreadIds[Thread], ThreadSysIds[Thread]); Insert.hParent = ProcItem; Insert.hInsertAfter = TVI_LAST; Insert.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM; Insert.item.pszText = Text; Insert.item.state = ProcIds[Proc] == g_CurProcessId && ThreadIds[Thread] == g_CurThreadId ? TVIS_BOLD : 0; Insert.item.stateMask = TVIS_BOLD; Insert.item.lParam = (LPARAM)ThreadIds[Thread]; ThreadItem = TreeView_InsertItem(m_hwndChild, &Insert); if (Insert.item.state & TVIS_BOLD) { CurThreadItem = ThreadItem; } }
ThreadIds += ProcThreads[Proc]; ThreadSysIds += ProcThreads[Proc]; }
if (CurThreadItem) { TreeView_Select(m_hwndChild, CurThreadItem, TVGN_CARET); } UnlockStateBuffer(this); }
void PROCESS_THREAD_DATA::SetCurThreadFromProcessTreeItem(HWND Tree, HTREEITEM Sel) { TVITEM Item; Item.hItem = Sel; Item.mask = TVIF_CHILDREN | TVIF_PARAM; TreeView_GetItem(Tree, &Item); g_pUiSystem->SetCurrentThreadId((ULONG)Item.lParam); }
//
//
//
EDITWIN_DATA::EDITWIN_DATA(ULONG ChangeBy) : SINGLE_CHILDWIN_DATA(ChangeBy) { m_TextLines = 0; m_Highlights = NULL; }
void EDITWIN_DATA::Validate() { SINGLE_CHILDWIN_DATA::Validate(); }
void EDITWIN_DATA::SetFont(ULONG FontIndex) { SINGLE_CHILDWIN_DATA::SetFont(FontIndex);
// Force the tabstop size to be recomputed
// with the new font.
SendMessage(m_hwndChild, EM_SETTABSTOPS, 1, (LPARAM)&g_TabWidth); }
BOOL EDITWIN_DATA::CanSelectAll() { return TRUE; }
void EDITWIN_DATA::SelectAll() { CHARRANGE Sel;
Sel.cpMin = 0; Sel.cpMax = INT_MAX; SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&Sel); }
BOOL EDITWIN_DATA::OnCreate(void) { m_hwndChild = CreateWindowEx( WS_EX_CLIENTEDGE, // Extended style
RICHEDIT_CLASS, // class name
NULL, // title
WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_AUTOVSCROLL | WS_HSCROLL | ES_AUTOHSCROLL | ES_READONLY | ES_MULTILINE, // style
0, // x
m_ToolbarHeight, // y
m_Size.cx, // width
m_Size.cy - m_ToolbarHeight, // height
m_Win, // parent
(HMENU) 0, // control id
g_hInst, // hInstance
NULL); // user defined data
if (m_hwndChild) { SetFont( FONT_FIXED ); SendMessage(m_hwndChild, EM_SETBKGNDCOLOR, FALSE, g_Colors[COL_PLAIN].Color); }
return m_hwndChild != NULL; }
LRESULT EDITWIN_DATA::OnNotify(WPARAM Wpm, LPARAM Lpm) { NMHDR* Hdr = (NMHDR*)Lpm; if (Hdr->code == EN_SAVECLIPBOARD) { // Indicate that the clipboard contents should
// be kept alive.
return 0; } else if (Hdr->code == EN_MSGFILTER) { MSGFILTER* Filter = (MSGFILTER*)Lpm; if (WM_SYSKEYDOWN == Filter->msg || WM_SYSKEYUP == Filter->msg || WM_SYSCHAR == Filter->msg) { // Force default processing for menu operations
// so that the Alt-minus menu comes up.
return 1; } }
return 0; }
void EDITWIN_DATA::OnDestroy(void) { EDIT_HIGHLIGHT* Next; while (m_Highlights != NULL) { Next = m_Highlights->Next; delete m_Highlights; m_Highlights = Next; }
SINGLE_CHILDWIN_DATA::OnDestroy(); }
void EDITWIN_DATA::UpdateColors(void) { SendMessage(m_hwndChild, EM_SETBKGNDCOLOR, FALSE, g_Colors[COL_PLAIN].Color); UpdateBpMarks(); }
void EDITWIN_DATA::SetCurrentLineHighlight(ULONG Line) { //
// Clear any other current line highlight in this window.
// Also, oOnly one doc window can have a current IP highlight so if
// this is a doc window getting a current IP highlight make
// sure no other doc windows have a current IP highlight.
//
if (m_enumType == DOC_WINDOW && ULONG_MAX != Line) { RemoveActiveWinHighlights(1 << DOC_WINDOW, EHL_CURRENT_LINE); } else { RemoveAllHighlights(EHL_CURRENT_LINE); } if (ULONG_MAX != Line) { AddHighlight(Line, EHL_CURRENT_LINE);
CHARRANGE crSet; // Set the caret on the current line. This automatically
// scrolls the line into view if necessary and prevents
// the view from snapping back to whatever old selection
// there was.
HWND OldFocus = ::SetFocus(m_hwndChild); crSet.cpMax = crSet.cpMin = (LONG) SendMessage(m_hwndChild, EM_LINEINDEX, Line, 0); SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&crSet);
::SetFocus(OldFocus); } } EDIT_HIGHLIGHT* EDITWIN_DATA::GetLineHighlighting(ULONG Line) { EDIT_HIGHLIGHT* Hl; for (Hl = m_Highlights; Hl != NULL; Hl = Hl->Next) { if (Hl->Line == Line) { return Hl; } }
return NULL; }
void EDITWIN_DATA::ApplyHighlight(EDIT_HIGHLIGHT* Hl) { CHARRANGE crOld;
// Get the old selection
SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM) &crOld);
//
// Compute the highlight information.
//
char Markers[LINE_MARKERS + 1]; CHARFORMAT2 cf; ULONG TextCol, BgCol;
Markers[2] = 0; ZeroMemory(&cf, sizeof(cf)); cf.cbSize = sizeof(cf); cf.dwMask = CFM_COLOR | CFM_BACKCOLOR; if (Hl->Flags & EHL_CURRENT_LINE) { Markers[1] = '>'; switch(Hl->Flags & EHL_ANY_BP) { case EHL_ENABLED_BP: Markers[0] = 'B'; TextCol = COL_BP_CURRENT_LINE_TEXT; BgCol = COL_BP_CURRENT_LINE; break; case EHL_DISABLED_BP: Markers[0] = 'D'; TextCol = COL_BP_CURRENT_LINE_TEXT; BgCol = COL_BP_CURRENT_LINE; break; default: Markers[0] = ' '; TextCol = COL_CURRENT_LINE_TEXT; BgCol = COL_CURRENT_LINE; break; } } else { Markers[1] = ' '; switch(Hl->Flags & EHL_ANY_BP) { case EHL_ENABLED_BP: Markers[0] = 'B'; TextCol = COL_ENABLED_BP_TEXT; BgCol = COL_ENABLED_BP; break; case EHL_DISABLED_BP: Markers[0] = 'D'; TextCol = COL_DISABLED_BP_TEXT; BgCol = COL_DISABLED_BP; break; default: Markers[0] = ' '; TextCol = COL_PLAIN_TEXT; BgCol = COL_PLAIN; break; } }
cf.crTextColor = g_Colors[TextCol].Color; cf.crBackColor = g_Colors[BgCol].Color; //
// Select the line to be highlighted
//
CHARRANGE crNew; crNew.cpMin = (LONG)SendMessage(m_hwndChild, EM_LINEINDEX, Hl->Line, 0);
if (g_LineMarkers) { // Replace the markers at the beginning of the line.
crNew.cpMax = crNew.cpMin + 2; SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&crNew); SendMessage(m_hwndChild, EM_REPLACESEL, FALSE, (LPARAM)Markers); }
// Color the line.
crNew.cpMax = crNew.cpMin + (LONG) SendMessage(m_hwndChild, EM_LINELENGTH, crNew.cpMin, 0) + 1; if (g_LineMarkers) { crNew.cpMin += 2; } SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM) &crNew); SendMessage(m_hwndChild, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
// Restore the old selection
SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM) &crOld); }
EDIT_HIGHLIGHT* EDITWIN_DATA::AddHighlight(ULONG Line, ULONG Flags) { EDIT_HIGHLIGHT* Hl;
// Search for an existing highlight record for the line.
Hl = GetLineHighlighting(Line);
if (Hl == NULL) { Hl = new EDIT_HIGHLIGHT; if (Hl == NULL) { return NULL; }
Hl->Data = 0; Hl->Line = Line; Hl->Flags = 0; Hl->Next = m_Highlights; m_Highlights = Hl; }
Hl->Flags |= Flags; ApplyHighlight(Hl);
return Hl; }
void EDITWIN_DATA::RemoveHighlight(ULONG Line, ULONG Flags) { EDIT_HIGHLIGHT* Hl; EDIT_HIGHLIGHT* Prev; // Search for an existing highlight record for the line.
Prev = NULL; for (Hl = m_Highlights; Hl != NULL; Hl = Hl->Next) { if (Hl->Line == Line) { break; }
Prev = Hl; }
if (Hl == NULL) { return; }
Hl->Flags &= ~Flags; ApplyHighlight(Hl);
if (Hl->Flags == 0) { if (Prev == NULL) { m_Highlights = Hl->Next; } else { Prev->Next = Hl->Next; }
delete Hl; } }
void EDITWIN_DATA::RemoveAllHighlights(ULONG Flags) { EDIT_HIGHLIGHT* Hl; EDIT_HIGHLIGHT* Next; EDIT_HIGHLIGHT* Prev;
Prev = NULL; for (Hl = m_Highlights; Hl != NULL; Hl = Next) { Next = Hl->Next;
if (Hl->Flags & Flags) { Hl->Flags &= ~Flags; ApplyHighlight(Hl);
if (Hl->Flags == 0) { if (Prev == NULL) { m_Highlights = Hl->Next; } else { Prev->Next = Hl->Next; }
delete Hl; } else { Prev = Hl; } } else { Prev = Hl; } } }
void EDITWIN_DATA::RemoveActiveWinHighlights(ULONG Types, ULONG Flags) { PLIST_ENTRY Entry = g_ActiveWin.Flink;
while (Entry != &g_ActiveWin) { PEDITWIN_DATA WinData = (PEDITWIN_DATA) ACTIVE_WIN_ENTRY(Entry); if (Types & (1 << WinData->m_enumType)) { WinData->RemoveAllHighlights(Flags); }
Entry = Entry->Flink; } }
void EDITWIN_DATA::UpdateBpMarks(void) { // Empty implementation for derived classes
// that do not show BP marks.
}
int EDITWIN_DATA::CheckForFileChanges(PCSTR File, FILETIME* LastWrite) { HANDLE Handle; Handle = CreateFile(File, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (Handle == INVALID_HANDLE_VALUE) { goto Changed; }
FILETIME NewWrite; if (!GetFileTime(Handle, NULL, NULL, &NewWrite)) { if (!GetFileTime(Handle, &NewWrite, NULL, NULL)) { ZeroMemory(&NewWrite, sizeof(NewWrite)); } }
CloseHandle(Handle);
if (CompareFileTime(LastWrite, &NewWrite) == 0) { // No change.
return IDCANCEL; }
Changed: return QuestionBox(ERR_File_Has_Changed, MB_YESNO, File); }
//
//
//
SCRATCH_PAD_DATA::SCRATCH_PAD_DATA() : EDITWIN_DATA(16) { m_enumType = SCRATCH_PAD_WINDOW; }
void SCRATCH_PAD_DATA::Validate() { EDITWIN_DATA::Validate();
Assert(SCRATCH_PAD_WINDOW == m_enumType); }
void SCRATCH_PAD_DATA::Cut() { SendMessage(m_hwndChild, WM_CUT, 0, 0); }
void SCRATCH_PAD_DATA::Paste() { SendMessage(m_hwndChild, WM_PASTE, 0, 0); }
BOOL SCRATCH_PAD_DATA::OnCreate(void) { if (!EDITWIN_DATA::OnCreate()) { return FALSE; }
SendMessage(m_hwndChild, EM_SETOPTIONS, ECOOP_AND, ~ECO_READONLY); return TRUE; }
//
//
//
DISASMWIN_DATA::DISASMWIN_DATA() : EDITWIN_DATA(2048) { m_enumType = DISASM_WINDOW; sprintf(m_OffsetExpr, "0x%I64x", g_EventIp); m_UpdateExpr = FALSE; m_FirstInstr = 0; m_LastInstr = 0; }
void DISASMWIN_DATA::Validate() { EDITWIN_DATA::Validate();
Assert(DISASM_WINDOW == m_enumType); }
HRESULT DISASMWIN_DATA::ReadState(void) { HRESULT Status; // Sample these values right away in case the UI changes them.
ULONG LinesTotal = m_LineHeight; ULONG LinesBefore = LinesTotal / 2; ULONG Line; DEBUG_VALUE Value;
if ((Status = g_pDbgControl->Evaluate(m_OffsetExpr, DEBUG_VALUE_INT64, &Value, NULL)) != S_OK) { return Status; }
m_PrimaryInstr = Value.I64; // Reserve space at the beginning of the buffer to
// store the line to offset mapping table.
PULONG64 LineMap; Empty(); LineMap = (PULONG64)AddData(sizeof(ULONG64) * LinesTotal); if (LineMap == NULL) { return E_OUTOFMEMORY; }
// We also need to allocate a temporary line map to
// pass to the engine for filling. This can't be
// the state buffer data since that may move as
// output is generated.
LineMap = new ULONG64[LinesTotal]; if (LineMap == NULL) { return E_OUTOFMEMORY; } g_OutStateBuf.SetBuffer(this); if ((Status = g_OutStateBuf.Start(FALSE)) != S_OK) { delete LineMap; return Status; }
Status = g_pOutCapControl-> OutputDisassemblyLines(DEBUG_OUTCTL_THIS_CLIENT | DEBUG_OUTCTL_OVERRIDE_MASK | DEBUG_OUTCTL_NOT_LOGGED, LinesBefore, LinesTotal, m_PrimaryInstr, DEBUG_DISASM_EFFECTIVE_ADDRESS | DEBUG_DISASM_MATCHING_SYMBOLS, &m_PrimaryLine, &m_FirstInstr, &m_LastInstr, LineMap);
memcpy(m_Data, LineMap, sizeof(ULONG64) * LinesTotal); delete LineMap;
if (Status != S_OK) { g_OutStateBuf.End(FALSE); return Status; }
m_TextLines = LinesTotal; m_TextOffset = LinesTotal * sizeof(ULONG64); // The line map is generated with offsets followed by
// invalid offsets for continuation lines. We want
// the offsets to be on the last line of the disassembly
// for a continuation set so move them down.
// We don't want to move the offsets down to blank lines,
// though, such as the blank lines that separate bundles
// in IA64 disassembly.
LineMap = (PULONG64)m_Data; PULONG64 LineMapEnd = LineMap + m_TextLines; PULONG64 SetStart; PSTR Text = (PSTR)m_Data + m_TextOffset; PSTR PrevText; while (LineMap < LineMapEnd) { if (*LineMap != DEBUG_INVALID_OFFSET) { SetStart = LineMap; for (;;) { PrevText = Text; Text = strchr(Text, '\n') + 1; LineMap++; if (LineMap >= LineMapEnd || *LineMap != DEBUG_INVALID_OFFSET || *Text == '\n') { break; } } LineMap--; Text = PrevText; if (LineMap > SetStart) { *LineMap = *SetStart; *SetStart = DEBUG_INVALID_OFFSET; } } LineMap++; Text = strchr(Text, '\n') + 1; } #ifdef DEBUG_DISASM
LineMap = (PULONG64)m_Data; for (Line = 0; Line < m_TextLines; Line++) { DebugPrint("%d: %I64x\n", Line, LineMap[Line]); } #endif
return g_OutStateBuf.End(TRUE); }
BOOL DISASMWIN_DATA::CodeExprAtCaret(PSTR Expr, PULONG64 Offset) { BOOL Succ = FALSE; LRESULT LineChar; LONG Line; PULONG64 LineMap; if (UiLockForRead() != S_OK) { goto NoCode; } LineChar = SendMessage(m_hwndChild, EM_LINEINDEX, -1, 0); Line = (LONG)SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, LineChar); if (Line < 0 || (ULONG)Line >= m_TextLines) { goto UnlockNoCode; }
ULONG64 LineOff; // Look up the offset in the line map. If it's part of
// a multiline group move forward to the offset.
LineMap = (PULONG64)m_Data; LineOff = LineMap[Line]; while ((ULONG)(Line + 1) < m_TextLines && LineOff == DEBUG_INVALID_OFFSET) { Line++; LineOff = LineMap[Line]; }
if (Expr != NULL) { sprintf(Expr, "0x%I64x", LineOff); } if (Offset != NULL) { *Offset = LineOff; } Succ = TRUE; UnlockNoCode: UnlockStateBuffer(this); NoCode: return Succ; }
BOOL DISASMWIN_DATA::OnCreate(void) { RECT Rect; int i; ULONG Height;
Height = GetSystemMetrics(SM_CYVSCROLL) + 4 * GetSystemMetrics(SM_CYEDGE); m_Toolbar = CreateWindowEx(0, REBARCLASSNAME, NULL, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOPARENTALIGN | RBS_VARHEIGHT | RBS_BANDBORDERS, 0, 0, m_Size.cx, Height, m_Win, (HMENU)ID_TOOLBAR, g_hInst, NULL); if (m_Toolbar == NULL) { return FALSE; }
REBARINFO BarInfo; BarInfo.cbSize = sizeof(BarInfo); BarInfo.fMask = 0; BarInfo.himl = NULL; SendMessage(m_Toolbar, RB_SETBARINFO, 0, (LPARAM)&BarInfo);
m_ToolbarEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", NULL, WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL, 0, 0, 18 * m_Font->Metrics.tmAveCharWidth, Height, m_Toolbar, (HMENU)IDC_EDIT_OFFSET, g_hInst, NULL); if (m_ToolbarEdit == NULL) { return FALSE; }
SendMessage(m_ToolbarEdit, WM_SETFONT, (WPARAM)m_Font->Font, 0); SendMessage(m_ToolbarEdit, EM_LIMITTEXT, sizeof(m_OffsetExpr) - 1, 0); GetClientRect(m_ToolbarEdit, &Rect);
REBARBANDINFO BandInfo; BandInfo.cbSize = sizeof(BandInfo); BandInfo.fMask = RBBIM_STYLE | RBBIM_TEXT | RBBIM_CHILD | RBBIM_CHILDSIZE; BandInfo.fStyle = RBBS_FIXEDSIZE; BandInfo.lpText = "Offset:"; BandInfo.hwndChild = m_ToolbarEdit; BandInfo.cxMinChild = Rect.right - Rect.left; BandInfo.cyMinChild = Rect.bottom - Rect.top; SendMessage(m_Toolbar, RB_INSERTBAND, -1, (LPARAM)&BandInfo);
// If the toolbar is allowed to shrink too small it hangs
// while resizing. Just let it clip off below a certain width.
m_MinToolbarWidth = BandInfo.cxMinChild * 2; PSTR PrevText = "Previous"; m_PreviousButton = AddButtonBand(m_Toolbar, PrevText, PrevText, IDC_DISASM_PREVIOUS); m_NextButton = AddButtonBand(m_Toolbar, "Next", PrevText, IDC_DISASM_NEXT); if (m_PreviousButton == NULL || m_NextButton == NULL) { return FALSE; }
// Maximize the space for the offset expression.
SendMessage(m_Toolbar, RB_MAXIMIZEBAND, 0, FALSE); GetClientRect(m_Toolbar, &Rect); m_ToolbarHeight = Rect.bottom - Rect.top; m_ShowToolbar = TRUE; if (!EDITWIN_DATA::OnCreate()) { return FALSE; }
// Suppress the scroll bar as the text is always
// fitted to the window size.
SendMessage(m_hwndChild, EM_SHOWSCROLLBAR, SB_VERT, FALSE);
SendMessage(m_hwndChild, EM_SETEVENTMASK, 0, ENM_KEYEVENTS);
return TRUE; }
LRESULT DISASMWIN_DATA::OnCommand(WPARAM Wpm, LPARAM Lpm) { switch(LOWORD(Wpm)) { case IDC_EDIT_OFFSET: if (HIWORD(Wpm) == EN_CHANGE) { // This message is sent on every keystroke
// which causes a bit too much updating.
// Set up a timer to trigger the actual
// update in half a second.
SetTimer(m_Win, IDC_EDIT_OFFSET, EDIT_DELAY, NULL); m_UpdateExpr = TRUE; } break; case IDC_DISASM_PREVIOUS: ScrollLower(); break; case IDC_DISASM_NEXT: ScrollHigher(); break; } return 0; }
void DISASMWIN_DATA::OnSize(void) { EDITWIN_DATA::OnSize();
// Force buffer to refill for new line count.
UiRequestRead(); }
void DISASMWIN_DATA::OnTimer(WPARAM TimerId) { if (TimerId == IDC_EDIT_OFFSET && m_UpdateExpr) { m_UpdateExpr = FALSE; GetWindowText(m_ToolbarEdit, m_OffsetExpr, sizeof(m_OffsetExpr)); UiRequestRead(); } }
LRESULT DISASMWIN_DATA::OnNotify(WPARAM Wpm, LPARAM Lpm) { MSGFILTER* Filter = (MSGFILTER*)Lpm;
if (Filter->nmhdr.code != EN_MSGFILTER) { return EDITWIN_DATA::OnNotify(Wpm, Lpm); } if (Filter->msg == WM_KEYDOWN) { switch(Filter->wParam) { case VK_UP: { CHARRANGE range;
SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM) &range); if (!SendMessage(m_hwndChild, EM_LINEFROMCHAR, range.cpMin, 0)) { // up arrow on top line, scroll
ScrollLower(); return 1; } break; } case VK_DOWN: { CHARRANGE range; int MaxLine;
SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM) &range); MaxLine = (int) SendMessage(m_hwndChild, EM_GETLINECOUNT, 0, 0);
if (MaxLine == (1+SendMessage(m_hwndChild, EM_LINEFROMCHAR, range.cpMin, 0))) { // down arrow on bottom line, scroll
ScrollHigher(); return 1; } break; } case VK_PRIOR: ScrollLower(); return 1; case VK_NEXT: ScrollHigher(); return 1; } } else if (WM_SYSKEYDOWN == Filter->msg || WM_SYSKEYUP == Filter->msg || WM_SYSCHAR == Filter->msg) { // Force default processing for menu operations
// so that the Alt-minus menu comes up.
return 1; }
return 0; }
void DISASMWIN_DATA::OnUpdate(UpdateType Type) { if (Type == UPDATE_BP || Type == UPDATE_END_SESSION) { UpdateBpMarks(); return; } else if (Type != UPDATE_BUFFER) { return; } HRESULT Status; Status = UiLockForRead(); if (Status == S_OK) { PULONG64 LineMap; ULONG Line;
if (!g_LineMarkers) { SendMessage(m_hwndChild, WM_SETTEXT, 0, (LPARAM)m_Data + m_TextOffset); } else { SendMessage(m_hwndChild, WM_SETTEXT, 0, (LPARAM)""); PSTR Text = (PSTR)m_Data + m_TextOffset; for (;;) { SendMessage(m_hwndChild, EM_REPLACESEL, FALSE, (LPARAM)" "); PSTR NewLine = strchr(Text, '\n'); if (NewLine != NULL) { *NewLine = 0; } SendMessage(m_hwndChild, EM_REPLACESEL, FALSE, (LPARAM)Text); if (NewLine == NULL) { break; } SendMessage(m_hwndChild, EM_REPLACESEL, FALSE, (LPARAM)"\n"); *NewLine = '\n'; Text = NewLine + 1; } }
// Highlight the last line of multiline disassembly.
LineMap = (PULONG64)m_Data; Line = m_PrimaryLine; while (Line + 1 < m_TextLines && LineMap[Line] == DEBUG_INVALID_OFFSET) { Line++; } SetCurrentLineHighlight(Line); UnlockStateBuffer(this);
UpdateBpMarks();
EnableWindow(m_PreviousButton, m_FirstInstr != m_PrimaryInstr); EnableWindow(m_NextButton, m_LastInstr != m_PrimaryInstr); } else { SendLockStatusMessage(m_hwndChild, WM_SETTEXT, Status); RemoveCurrentLineHighlight(); } }
void DISASMWIN_DATA::UpdateBpMarks(void) { if (m_TextLines == 0 || UiLockForRead() != S_OK) { return; }
if (g_BpBuffer->UiLockForRead() != S_OK) { UnlockStateBuffer(this); return; }
SendMessage(m_hwndChild, WM_SETREDRAW, FALSE, 0);
// Remove existing BP highlights.
RemoveAllHighlights(EHL_ANY_BP); //
// Highlight every line that matches a breakpoint.
//
PULONG64 LineMap = (PULONG64)m_Data; BpBufferData* BpData = (BpBufferData*)g_BpBuffer->GetDataBuffer(); ULONG Line; BpStateType State;
for (Line = 0; Line < m_TextLines; Line++) { if (*LineMap != DEBUG_INVALID_OFFSET) { State = IsBpAtOffset(BpData, *LineMap, NULL); if (State != BP_NONE) { AddHighlight(Line, State == BP_ENABLED ? EHL_ENABLED_BP : EHL_DISABLED_BP); } }
LineMap++; }
SendMessage(m_hwndChild, WM_SETREDRAW, TRUE, 0); InvalidateRect(m_hwndChild, NULL, TRUE); UnlockStateBuffer(g_BpBuffer); UnlockStateBuffer(this); }
void DISASMWIN_DATA::SetCurInstr(ULONG64 Offset) { // Any pending user update is now irrelevant.
m_UpdateExpr = FALSE; sprintf(m_OffsetExpr, "0x%I64x", Offset); // Force engine to update buffer.
UiRequestRead(); }
void RicheditFind(HWND Edit, PTSTR Text, ULONG Flags, CHARRANGE* SaveSel, PULONG SaveFlags, BOOL HideSel) { if (Text == NULL) { // Clear last find.
if (SaveSel->cpMax >= SaveSel->cpMin) { if (*SaveFlags & FR_DOWN) { SaveSel->cpMin = SaveSel->cpMax; } else { SaveSel->cpMax = SaveSel->cpMin; } if (HideSel) { SendMessage(Edit, EM_SETOPTIONS, ECOOP_AND, ~ECO_NOHIDESEL); } SendMessage(Edit, EM_EXSETSEL, 0, (LPARAM)SaveSel); SendMessage(Edit, EM_SCROLLCARET, 0, 0); SaveSel->cpMin = 1; SaveSel->cpMax = 0; } } else { LRESULT Match; FINDTEXTEX Find;
SendMessage(Edit, EM_EXGETSEL, 0, (LPARAM)&Find.chrg); if (Flags & FR_DOWN) { Find.chrg.cpMax = LONG_MAX; } else { Find.chrg.cpMax = 0; } Find.lpstrText = Text; Match = SendMessage(Edit, EM_FINDTEXTEX, Flags, (LPARAM)&Find); if (Match != -1) { *SaveSel = Find.chrgText; *SaveFlags = Flags; if (HideSel) { SendMessage(Edit, EM_SETOPTIONS, ECOOP_OR, ECO_NOHIDESEL); } SendMessage(Edit, EM_EXSETSEL, 0, (LPARAM)SaveSel); SendMessage(Edit, EM_SCROLLCARET, 0, 0); } else { InformationBox(ERR_No_More_Matches, Text); SetFocus(g_FindDialog); } } }
#undef DEFINE_GET_WINDATA
#undef ASSERT_CLASS_TYPE
#ifndef DBG
#define ASSERT_CLASS_TYPE(p, ct) ((VOID)0)
#else
#define ASSERT_CLASS_TYPE(p, ct) if (p) { AssertType(*p, ct); }
#endif
#define DEFINE_GET_WINDATA(ClassType, FuncName) \
ClassType * \ Get##FuncName##WinData( \ HWND hwnd \ ) \ { \ ClassType *p = (ClassType *) \ GetWindowLongPtr(hwnd, GWLP_USERDATA); \ \ ASSERT_CLASS_TYPE(p, ClassType); \ \ return p; \ }
#include "fncdefs.h"
#undef DEFINE_GET_WINDATA
#undef ASSERT_CLASS_TYPE
|