|
|
/*++
Copyright (c) 1999-2002 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::SelectedText(PTSTR Buffer, ULONG BufferChars) { return FALSE; }
BOOL COMMONWIN_DATA::CanWriteTextToFile() { return FALSE; }
HRESULT COMMONWIN_DATA::WriteTextToFile(HANDLE File) { return E_NOTIMPL; }
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, BOOL FromDlg) { // Do nothing.
}
HRESULT COMMONWIN_DATA::CodeExprAtCaret(PSTR Expr, ULONG ExprSize, PULONG64 Offset) { return E_NOINTERFACE; }
void COMMONWIN_DATA::ToggleBpAtCaret(void) { char CodeExpr[MAX_OFFSET_EXPR]; ULONG64 Offset; if (CodeExprAtCaret(CodeExpr, DIMA(CodeExpr), &Offset) != S_OK) { 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 && !IsIconic(hwnd) && !pWinData->m_CausedArrange) { 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; } // We don't care about size events while the frame is
// minimized as the children can't be seen. When
// the frame is restored a new size event will come through
// and things will get updated when they're actually visible.
if (IsIconic(g_hwndFrame)) { break; }
if (wParam == SIZE_RESTORED && !pWinData->m_CausedArrange) { 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);
case WM_CTLCOLORLISTBOX: // Substitute windbg's default window colors.
SetTextColor((HDC)wParam, g_Colors[COL_PLAIN_TEXT].Color); SetBkColor((HDC)wParam, g_Colors[COL_PLAIN].Color); return (LRESULT)g_Colors[COL_PLAIN].Brush; } 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); }
void SINGLE_CHILDWIN_DATA::UpdateColors(void) { // Force a repaint of the child.
InvalidateRect(m_hwndChild, NULL, TRUE); }
//
//
//
PROCESS_THREAD_DATA::PROCESS_THREAD_DATA() : SINGLE_CHILDWIN_DATA(512) { m_enumType = PROCESS_THREAD_WINDOW; m_TotalSystems = 0; m_NamesOffset = 0; }
void PROCESS_THREAD_DATA::Validate() { SINGLE_CHILDWIN_DATA::Validate();
Assert(PROCESS_THREAD_WINDOW == m_enumType); }
HRESULT PROCESS_THREAD_DATA::ReadProcess(ULONG ProcId, PULONG Offset) { HRESULT Status; PULONG ThreadIds, ThreadSysIds; ULONG NumThread; char Name[MAX_PATH]; ULONG NameLen; PULONG Data;
if ((Status = g_pDbgSystem-> SetCurrentProcessId(ProcId)) != S_OK || (Status = g_pDbgSystem->GetNumberThreads(&NumThread)) != S_OK) { return Status; } if (FAILED(Status = g_pDbgSystem-> GetCurrentProcessExecutableName(Name, sizeof(Name), NULL))) { PrintString(Name, DIMA(Name), "<%s>", FormatStatusCode(Status)); } NameLen = strlen(Name) + 1; if (NameLen > 1) { PSTR NameStore = (PSTR)AddData(NameLen); if (NameStore == NULL) { return E_OUTOFMEMORY; }
strcpy(NameStore, Name); } // Refresh pointers in case a resize
// caused buffer movement.
Data = (PULONG)GetDataBuffer() + *Offset; *Data++ = NumThread; *Data++ = NameLen; *Offset += 2; ThreadIds = Data; ThreadSysIds = ThreadIds + NumThread; if ((Status = g_pDbgSystem-> GetThreadIdsByIndex(0, NumThread, ThreadIds, ThreadSysIds)) != S_OK) { return Status; }
*Offset += 2 * NumThread;
return S_OK; }
HRESULT PROCESS_THREAD_DATA::ReadSystem(ULONG SysId, PULONG Offset) { HRESULT Status; ULONG ProcIdsOffset; PULONG ProcIds, ProcSysIds; ULONG NumProc; ULONG i; char Name[MAX_PATH + 32]; ULONG NameLen; PULONG Data;
if (g_pDbgSystem3) { if ((Status = g_pDbgSystem3-> SetCurrentSystemId(SysId)) != S_OK || FAILED(Status = g_pDbgSystem3-> GetCurrentSystemServerName(Name, sizeof(Name), NULL))) { return Status; } } else { Name[0] = 0; }
NameLen = strlen(Name) + 1; if (NameLen > 1) { PSTR NameStore = (PSTR)AddData(NameLen); if (NameStore == NULL) { return E_OUTOFMEMORY; }
strcpy(NameStore, Name); } if ((Status = g_pDbgSystem-> GetNumberProcesses(&NumProc)) != S_OK) { return Status; } // Refresh pointers in case a resize
// caused buffer movement.
Data = (PULONG)GetDataBuffer() + *Offset; *Data++ = NumProc; *Data++ = NameLen; *Offset += 2;
if (NumProc == 0) { return S_OK; } ProcIds = Data; ProcIdsOffset = *Offset; ProcSysIds = ProcIds + NumProc; if ((Status = g_pDbgSystem-> GetProcessIdsByIndex(0, NumProc, ProcIds, ProcSysIds)) != S_OK) { return Status; }
*Offset += 2 * NumProc; for (i = 0; i < NumProc; i++) { ProcIds = (PULONG)GetDataBuffer() + ProcIdsOffset; if ((Status = ReadProcess(ProcIds[i], Offset)) != S_OK) { return Status; } }
return S_OK; }
HRESULT PROCESS_THREAD_DATA::ReadState(void) { HRESULT Status; ULONG CurProc; ULONG TotalSys, TotalThread, TotalProc; ULONG MaxProcThread, MaxSysThread, MaxSysProc; PULONG SysIds; ULONG i; ULONG Offset; ULONG NamesOffset;
if ((Status = g_pDbgSystem->GetCurrentProcessId(&CurProc)) != S_OK) { return Status; } if (g_pDbgSystem3) { if ((Status = g_pDbgSystem3->GetNumberSystems(&TotalSys)) != S_OK || (Status = g_pDbgSystem3-> GetTotalNumberThreadsAndProcesses(&TotalThread, &TotalProc, &MaxProcThread, &MaxSysThread, &MaxSysProc)) != S_OK) { return Status; } } else { if ((Status = g_pDbgSystem->GetNumberProcesses(&TotalProc)) != S_OK || (Status = g_pDbgSystem-> GetTotalNumberThreads(&TotalThread, &MaxProcThread)) != S_OK) { return Status; } TotalSys = 1; MaxSysThread = MaxProcThread; MaxSysProc = TotalProc; }
Empty();
NamesOffset = (TotalSys * 3 + TotalProc * 4 + TotalThread * 2) * sizeof(ULONG); SysIds = (PULONG)AddData(NamesOffset); if (SysIds == NULL) { return E_OUTOFMEMORY; }
if (g_pDbgSystem3) { if ((Status = g_pDbgSystem3-> GetSystemIdsByIndex(0, TotalSys, SysIds)) != S_OK) { return Status; } } else { *SysIds = 0; }
ULONG OutMask, LogMask; // Ignore thread notifications as we're changing the thread.
g_IgnoreThreadChange = TRUE; // Switching threads causes output which we don't want so
// ignore all output.
g_pDbgClient->GetOutputMask(&OutMask); g_pDbgControl->GetLogMask(&LogMask); g_pDbgClient->SetOutputMask(0); g_pDbgControl->SetLogMask(0); Offset = TotalSys; for (i = 0; i < TotalSys; i++) { SysIds = (PULONG)GetDataBuffer(); if ((Status = ReadSystem(SysIds[i], &Offset)) != S_OK) { break; } }
// This will also set the current system and thread
// from the process information.
g_pDbgSystem->SetCurrentProcessId(CurProc);
g_IgnoreThreadChange = FALSE; g_pDbgClient->SetOutputMask(OutMask); g_pDbgControl->SetLogMask(LogMask);
if (Status == S_OK) { m_TotalSystems = TotalSys; m_NamesOffset = NamesOffset; } 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); SendMessage(m_hwndChild, TVM_SETTEXTCOLOR, 0, g_Colors[COL_PLAIN_TEXT].Color); SendMessage(m_hwndChild, TVM_SETBKCOLOR, 0, g_Colors[COL_PLAIN].Color); 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 TVN_SELCHANGED: if (Tvn->action == TVC_BYMOUSE) { SetCurThreadFromProcessTreeItem(m_hwndChild, Tvn->itemNew.hItem); } break;
case NM_DBLCLK: case NM_RETURN: Sel = TreeView_GetSelection(m_hwndChild); if (Sel) { SetCurThreadFromProcessTreeItem(m_hwndChild, Sel); } return TRUE; }
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 Sys; ULONG NameLen; PULONG SysIds, Data; char Text[MAX_PATH + 64]; PSTR Names; TVINSERTSTRUCT Insert; HTREEITEM CurThreadItem = NULL;
SysIds = (PULONG)GetDataBuffer(); Data = SysIds + m_TotalSystems; Names = (PSTR)GetDataBuffer() + m_NamesOffset; TreeView_DeleteAllItems(m_hwndChild);
for (Sys = 0; Sys < m_TotalSystems; Sys++) { HTREEITEM SysItem; ULONG NumProc, Proc; PULONG ProcIds, ProcSysIds;
NumProc = *Data++; NameLen = *Data++; ProcIds = Data; ProcSysIds = ProcIds + NumProc; Data = ProcSysIds + NumProc;
sprintf(Text, "%d ", SysIds[Sys]); if (NameLen > 1) { CatString(Text, Names, DIMA(Text)); Names += strlen(Names) + 1; } if (m_TotalSystems > 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 = SysIds[Sys] == g_CurSystemId ? TVIS_EXPANDED | TVIS_BOLD: 0; Insert.item.stateMask = TVIS_EXPANDED | TVIS_BOLD; // Parameter is the thread ID to set to select the given system.
Insert.item.lParam = NumProc > 0 ? (LPARAM)Data[2] : (LPARAM)-1; SysItem = TreeView_InsertItem(m_hwndChild, &Insert); } else { SysItem = TVI_ROOT; }
for (Proc = 0; Proc < NumProc; Proc++) { HTREEITEM ProcItem; ULONG NumThread, Thread; PULONG ThreadIds, ThreadSysIds;
NumThread = *Data++; NameLen = *Data++; ThreadIds = Data; ThreadSysIds = Data + NumThread; Data = ThreadSysIds + NumThread; sprintf(Text, "%03d:%x ", ProcIds[Proc], ProcSysIds[Proc]); if (NameLen > 1) { CatString(Text, Names, DIMA(Text)); Names += strlen(Names) + 1; } Insert.hParent = SysItem; Insert.hInsertAfter = TVI_LAST; Insert.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM; Insert.item.pszText = Text; Insert.item.state = SysIds[Sys] == g_CurSystemId && 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 < NumThread; 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 = SysIds[Sys] == g_CurSystemId && 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; } } } }
if (CurThreadItem) { TreeView_Select(m_hwndChild, CurThreadItem, TVGN_CARET); } UnlockStateBuffer(this); }
void PROCESS_THREAD_DATA::UpdateColors(void) { SendMessage(m_hwndChild, TVM_SETTEXTCOLOR, 0, g_Colors[COL_PLAIN_TEXT].Color); SendMessage(m_hwndChild, TVM_SETBKCOLOR, 0, g_Colors[COL_PLAIN].Color); InvalidateRect(m_hwndChild, NULL, TRUE); }
void PROCESS_THREAD_DATA::SetCurThreadFromProcessTreeItem(HWND Tree, HTREEITEM Sel) { TVITEM Item; Item.hItem = Sel; Item.mask = TVIF_CHILDREN | TVIF_PARAM; TreeView_GetItem(Tree, &Item); if (Item.lParam != (LPARAM)-1) { 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) { CHARFORMAT2 Fmt;
SetFont(FONT_FIXED);
SendMessage(m_hwndChild, EM_SETBKGNDCOLOR, FALSE, g_Colors[COL_PLAIN].Color);
ZeroMemory(&Fmt, sizeof(Fmt)); Fmt.cbSize = sizeof(Fmt); Fmt.dwMask = CFM_COLOR; Fmt.crTextColor = g_Colors[COL_PLAIN_TEXT].Color; SendMessage(m_hwndChild, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&Fmt); }
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) { RicheditUpdateColors(m_hwndChild, g_Colors[COL_PLAIN_TEXT].Color, TRUE, g_Colors[COL_PLAIN].Color, TRUE); UpdateCurrentLineHighlight(); UpdateBpMarks(); }
void EDITWIN_DATA::SetCurrentLineHighlight(ULONG Line) { //
// Clear any other current line highlight in this window.
// Also, only 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); RicheditScrollToLine(m_hwndChild, Line, m_LineHeight); } } void EDITWIN_DATA::UpdateCurrentLineHighlight(void) { EDIT_HIGHLIGHT* Hl;
for (Hl = m_Highlights; Hl != NULL; Hl = Hl->Next) { if (Hl->Flags & EHL_CURRENT_LINE) { break; } }
if (Hl) { ApplyHighlight(Hl); } }
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 OldSel; BOOL HasFocus = ::GetFocus() == m_hwndChild;
// Get the old selection and scroll position.
SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&OldSel);
// Disable the window to prevent auto-scrolling
// when the selection is set.
EnableWindow(m_hwndChild, FALSE); //
// Compute the highlight information.
//
char Markers[LINE_MARKERS + 1]; CHARFORMAT2 Fmt; ULONG TextCol, BgCol;
Markers[2] = 0; ZeroMemory(&Fmt, sizeof(Fmt)); Fmt.cbSize = sizeof(Fmt); Fmt.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; } }
Fmt.crTextColor = g_Colors[TextCol].Color; Fmt.crBackColor = g_Colors[BgCol].Color; //
// Select the line to be highlighted
//
CHARRANGE FmtSel; FmtSel.cpMin = (LONG)SendMessage(m_hwndChild, EM_LINEINDEX, Hl->Line, 0);
if (g_LineMarkers) { // Replace the markers at the beginning of the line.
FmtSel.cpMax = FmtSel.cpMin + 2; SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&FmtSel); SendMessage(m_hwndChild, EM_REPLACESEL, FALSE, (LPARAM)Markers); }
// Color the line.
FmtSel.cpMax = FmtSel.cpMin + (LONG) SendMessage(m_hwndChild, EM_LINELENGTH, FmtSel.cpMin, 0) + 1; if (g_LineMarkers) { FmtSel.cpMin += 2; } SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&FmtSel); SendMessage(m_hwndChild, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&Fmt);
// Restore the old selection
SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&OldSel); EnableWindow(m_hwndChild, TRUE);
// The disabling of the window caused the richedit
// to forget its focus status so force the focus
// back if it had it.
if (HasFocus) { ::SetFocus(m_hwndChild); } }
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 g_QuietSourceMode == QMODE_ALWAYS_YES ? IDYES : (g_QuietSourceMode == QMODE_ALWAYS_NO ? IDCANCEL : 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, EM_PASTESPECIAL, CF_TEXT, 0); }
BOOL SCRATCH_PAD_DATA::CanWriteTextToFile() { return TRUE; }
HRESULT SCRATCH_PAD_DATA::WriteTextToFile(HANDLE File) { return RicheditWriteToFile(m_hwndChild, File); }
BOOL SCRATCH_PAD_DATA::OnCreate(void) { if (!EDITWIN_DATA::OnCreate()) { return FALSE; }
SendMessage(m_hwndChild, EM_SETOPTIONS, ECOOP_AND, ~ECO_READONLY); SendMessage(m_hwndChild, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS);
return TRUE; }
LRESULT SCRATCH_PAD_DATA::OnNotify(WPARAM Wpm, LPARAM Lpm) { MSGFILTER* Filter = (MSGFILTER *)Lpm; if (EN_MSGFILTER != Filter->nmhdr.code) { return 0; }
if (WM_RBUTTONDOWN == Filter->msg || WM_RBUTTONDBLCLK == Filter->msg) { // If there's a selection copy it to the clipboard
// and clear it. Otherwise try to paste.
if (CanCopy()) { Copy(); CHARRANGE Sel; SendMessage(m_hwndChild, EM_EXGETSEL, 0, (LPARAM)&Sel); Sel.cpMax = Sel.cpMin; SendMessage(m_hwndChild, EM_EXSETSEL, 0, (LPARAM)&Sel); } else if (SendMessage(m_hwndChild, EM_CANPASTE, CF_TEXT, 0)) { Paste(); } // Ignore right-button events.
return 1; }
return 0; }
//
//
//
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; 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); }
HRESULT DISASMWIN_DATA::CodeExprAtCaret(PSTR Expr, ULONG ExprSize, PULONG64 Offset) { HRESULT Status; LRESULT LineChar; LONG Line; PULONG64 LineMap; if ((Status = UiLockForRead()) != S_OK) { // Don't want to return any success codes here.
return FAILED(Status) ? Status : E_FAIL; }
LineChar = SendMessage(m_hwndChild, EM_LINEINDEX, -1, 0); Line = (LONG)SendMessage(m_hwndChild, EM_EXLINEFROMCHAR, 0, LineChar); if (Line < 0 || (ULONG)Line >= m_TextLines) { Status = E_INVALIDARG; goto Unlock; }
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) { if (!PrintString(Expr, ExprSize, "0x%I64x", LineOff)) { Status = E_INVALIDARG; goto Unlock; } } if (Offset != NULL) { *Offset = LineOff; } Status = S_OK; Unlock: UnlockStateBuffer(this); return Status; }
BOOL DISASMWIN_DATA::OnCreate(void) { RECT Rect; 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);
RicheditUpdateColors(m_hwndChild, g_Colors[COL_PLAIN_TEXT].Color, TRUE, 0, FALSE); UpdateCurrentLineHighlight(); 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) { if (Find.chrg.cpMax > Find.chrg.cpMin) { Find.chrg.cpMin++; } 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 { if (g_FindDialog) { EnableWindow(g_FindDialog, FALSE); } InformationBox(ERR_No_More_Matches, Text); if (g_FindDialog) { EnableWindow(g_FindDialog, TRUE); SetFocus(g_FindDialog); } } } }
DWORD CALLBACK StreamOutCb(DWORD_PTR File, LPBYTE Buffer, LONG Request, PLONG Done) { return WriteFile((HANDLE)File, Buffer, Request, (LPDWORD)Done, NULL) ? 0 : GetLastError(); }
HRESULT RicheditWriteToFile(HWND Edit, HANDLE File) { EDITSTREAM Stream;
Stream.dwCookie = (DWORD_PTR)File; Stream.dwError = 0; Stream.pfnCallback = StreamOutCb; SendMessage(Edit, EM_STREAMOUT, SF_TEXT, (LPARAM)&Stream); if (Stream.dwError) { return HRESULT_FROM_WIN32(Stream.dwError); } return S_OK; }
void RicheditUpdateColors(HWND Edit, COLORREF Fg, BOOL UpdateFg, COLORREF Bg, BOOL UpdateBg) { if (UpdateBg) { if (UpdateFg) { SendMessage(Edit, WM_SETREDRAW, FALSE, 0); }
SendMessage(Edit, EM_SETBKGNDCOLOR, FALSE, Bg);
if (UpdateFg) { SendMessage(Edit, WM_SETREDRAW, TRUE, 0); } }
if (UpdateFg) { CHARFORMAT2 Fmt;
ZeroMemory(&Fmt, sizeof(Fmt)); Fmt.cbSize = sizeof(Fmt); Fmt.dwMask = CFM_COLOR; Fmt.crTextColor = Fg; SendMessage(Edit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&Fmt); } }
#define EXTRA_VIS 3
void RicheditScrollToLine(HWND Edit, ULONG Line, ULONG VisLines) { CHARRANGE Sel; ULONG CurLine; ULONG VisAround; ULONG TotalLines; LONG Scroll;
//
// Scroll the given line into view. Try to keep
// the line from being the first or last line
// in view.
//
// Disable the window during this to prevent
// the default richedit scrolling from occurring.
//
VisAround = VisLines / 2; if (VisAround > EXTRA_VIS) { VisAround = EXTRA_VIS; } TotalLines = (ULONG)SendMessage(Edit, EM_GETLINECOUNT, 0, 0); CurLine = (ULONG)SendMessage(Edit, EM_GETFIRSTVISIBLELINE, 0, 0);
if (Line < CurLine + VisAround) { Scroll = (LONG)Line - (LONG)(CurLine + VisAround); if ((ULONG)-Scroll > CurLine) { Scroll = -(LONG)CurLine; } } else if (Line >= CurLine + VisLines - VisAround && CurLine + VisLines < TotalLines) { Scroll = (LONG)Line - (LONG)(CurLine + VisLines - VisAround) + 1; } else { Scroll = 0; }
if (Scroll) { SendMessage(Edit, EM_LINESCROLL, 0, Scroll); }
Sel.cpMax = Sel.cpMin = (LONG) SendMessage(Edit, EM_LINEINDEX, Line, 0); SendMessage(Edit, EM_EXSETSEL, 0, (LPARAM)&Sel); }
ULONG RicheditGetSelectionText(HWND Edit, PTSTR Buffer, ULONG BufferChars) { CHARRANGE Sel;
SendMessage(Edit, EM_EXGETSEL, 0, (LPARAM)&Sel); if (Sel.cpMin >= Sel.cpMax) { return 0; }
Sel.cpMax -= Sel.cpMin; if ((ULONG)Sel.cpMax + 1 > BufferChars) { return 0; }
SendMessage(Edit, EM_GETSELTEXT, 0, (LPARAM)Buffer); return Sel.cpMax; }
ULONG RicheditGetSourceToken(HWND Edit, PTSTR Buffer, ULONG BufferChars, CHARRANGE* Range) { LRESULT Idx; TEXTRANGE GetRange; CHARRANGE Sel;
//
// Get the text for the line containing the selection.
//
SendMessage(Edit, EM_EXGETSEL, 0, (LPARAM)&Sel); if (Sel.cpMin > Sel.cpMax) { return 0; }
if ((Idx = SendMessage(Edit, EM_LINEINDEX, -1, 0)) < 0) { return 0; } GetRange.chrg.cpMin = (LONG)Idx;
if (!(Idx = SendMessage(Edit, EM_LINELENGTH, GetRange.chrg.cpMin, 0))) { return 0; } if (BufferChars <= (ULONG)Idx) { Idx = (LONG)BufferChars - 1; } GetRange.chrg.cpMax = GetRange.chrg.cpMin + (LONG)Idx; GetRange.lpstrText = Buffer; if (!SendMessage(Edit, EM_GETTEXTRANGE, 0, (LPARAM)&GetRange)) { return 0; }
//
// Check and see if the selection is within a source token.
//
PTSTR Scan = Buffer + (Sel.cpMin - GetRange.chrg.cpMin); if (!iscsym(*Scan)) { return 0; }
//
// Find the start of the token and validate it.
//
PTSTR Start = Scan; if (Start > Buffer) { while (--Start >= Buffer && iscsym(*Start)) { // Back up.
} Start++; } if (!iscsymf(*Start)) { return 0; }
//
// Find the end of the token.
//
Scan++; while (iscsym(*Scan)) { Scan++; }
ULONG Len; // Chop the buffer down to just the token and return.
Len = (ULONG)(Scan - Start); memmove(Buffer, Start, Len); Buffer[Len] = 0; Range->cpMin = GetRange.chrg.cpMin + (LONG)(Start - Buffer); Range->cpMax = Range->cpMin + Len; return Len; }
#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
|