BOOL fCreateMainTabControl(HWND hMainWnd, __out HWND *phTabControl, DWORD *pdwErrCode) { ASSERT(ISVALID_HANDLE(hMainWnd)); ASSERT(phTabControl); ASSERT(pdwErrCode); RECT rcClientArea; HWND hTab = NULL; if(!GetClientRect(hMainWnd, &rcClientArea)) { // todo: log error goto error_return; } hTab = CreateWindow(WC_TABCONTROL, NULL, WS_CHILD|WS_VISIBLE|WS_BORDER, rcClientArea.left + 5, rcClientArea.top + 5, rcClientArea.right - 10, rcClientArea.bottom - 10, hMainWnd, (HMENU)IDC_MAINTAB, g_hMainInstance, NULL); if(ISNULL(hTab)) { // todo: log error goto error_return; } *phTabControl = hTab; return TRUE; error_return: *pdwErrCode = GetLastError(); return FALSE; }
BOOL fResumeAllThreads(CHL_HTABLE *phtThreads) { ASSERT(phtThreads); CHL_HT_ITERATOR itr; DWORD dwThreadID = 0; LPCREATE_THREAD_DEBUG_INFO pThreadDbgInfo = NULL; int keysize, valsize; BOOL fRetVal = TRUE; fChlDsInitIteratorHT(&itr); while(fChlDsGetNextHT(phtThreads, &itr, &dwThreadID, &keysize, &pThreadDbgInfo, &valsize)) { ASSERT(pThreadDbgInfo); ASSERT(ISVALID_HANDLE(pThreadDbgInfo->hThread)); dbgwprintf(L"Resuming thread %u\n", dwThreadID); if( ResumeThread(pThreadDbgInfo->hThread) == -1 ) { logerror(pstLogger, L"ResumeThread() failed for thread %u: %u", dwThreadID, GetLastError()); fRetVal = FALSE; } } return fRetVal; }
// Given handle to a map view of a file, return pointer to the IMAGE_NT_HEADERS structure // HRESULT CHL_PsGetNtHeaders(_In_ HANDLE hMapView, _Out_ PIMAGE_NT_HEADERS *ppstNtHeaders) { PIMAGE_DOS_HEADER pDOSHeader = NULL; HRESULT hr = S_OK; if(!ISVALID_HANDLE(hMapView) || !ppstNtHeaders) { hr = E_INVALIDARG; } else { pDOSHeader = (PIMAGE_DOS_HEADER)hMapView; // verify "MZ" in the DOS header if(pDOSHeader->e_magic == IMAGE_DOS_SIGNATURE) { *ppstNtHeaders = (PIMAGE_NT_HEADERS)((BYTE*)hMapView + pDOSHeader->e_lfanew); } else { hr = E_UNEXPECTED; } } return hr; }
BOOL fSetTabPageText(HWND hTab, int iTabIndex, PWCHAR pszTabText) { ASSERT(ISVALID_HANDLE(hTab)); ASSERT(iTabIndex >= 0); ASSERT(pszTabText); TCITEM stTcItem = {0}; stTcItem.mask = TCIF_TEXT; stTcItem.pszText = pszTabText; return SendMessage(hTab, TCM_SETITEM, iTabIndex, (LPARAM)&stTcItem); }
HRESULT CHL_GuiAddListViewRow( _In_ HWND hList, _In_ WCHAR *apszItemText[], _In_ int nItems, _In_opt_ LPARAM lParam) { int index; int iInsertedAt; int nItemsInListView; LVITEM lvItem; HRESULT hr = S_OK; // Parameter validation if(!ISVALID_HANDLE(hList) || !apszItemText || nItems <= 0) { hr = E_INVALIDARG; goto done; } // First, get the current number of list items to use as item index nItemsInListView = ListView_GetItemCount(hList); // Insert the item, as in, append to the list ZeroMemory(&lvItem, sizeof(lvItem)); lvItem.iItem = nItemsInListView; lvItem.mask = LVIF_TEXT|LVIF_PARAM; lvItem.pszText = apszItemText[0]; lvItem.lParam = lParam; if( (iInsertedAt = SendMessage(hList, LVM_INSERTITEM, 0, (LPARAM)&lvItem)) == -1 ) { hr = E_FAIL; goto done; } // Now, insert sub items for(index = 1; index < nItems; ++index) { lvItem.iSubItem = index; lvItem.pszText = apszItemText[index]; if( !SendMessage(hList, LVM_SETITEMTEXT, iInsertedAt, (LPARAM)&lvItem) ) { hr = E_FAIL; } } done: return hr; }
void vDeleteTabPage(HWND hTab, PTABPAGEINFO pstTabPageInfo) { ASSERT(ISVALID_HANDLE(hTab)); ASSERT(pstTabPageInfo); ASSERT(pstTabPageInfo->iTabIndex >= 0); // First, destroy all child windows DestroyWindow(pstTabPageInfo->hEditDisass); DestroyWindow(pstTabPageInfo->hListCallStack); DestroyWindow(pstTabPageInfo->hListRegisters); DestroyWindow(pstTabPageInfo->hListThreads); DestroyWindow(pstTabPageInfo->hStaticCommand); DestroyWindow(pstTabPageInfo->hEditCommand); DestroyWindow(pstTabPageInfo->hTabBottom); // Remove the tab item SendMessage(hTab, TCM_DELETEITEM, (int)pstTabPageInfo->iTabIndex, (LPARAM)NULL); }
BOOL fUpdateRegistersListView(HWND hList, DWORD dwThreadId) { ASSERT(ISVALID_HANDLE(hList)); ASSERT(dwThreadId > 0); CONTEXT stContext; HANDLE hThread = NULL; DWORD adwValues[_countof(apszRegNames)]; ASSERT(_countof(apszRegNames) == 9); hThread = OpenThread(THREAD_GET_CONTEXT, FALSE, dwThreadId); if(hThread == NULL) { logerror(pstLogger, L"%s(): OpenThread() failed %u", __FUNCTIONW__, GetLastError()); return FALSE; } stContext.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; if(!GetThreadContext(hThread, &stContext)) { logerror(pstLogger, L"%s(): GetThreadContext() failed %u", __FUNCTIONW__, GetLastError()); CloseHandle(hThread); return FALSE; } CloseHandle(hThread); adwValues[0] = stContext.Eax; adwValues[1] = stContext.Ebx; adwValues[2] = stContext.Ecx; adwValues[3] = stContext.Edx; adwValues[4] = stContext.Esi; adwValues[5] = stContext.Edi; adwValues[6] = stContext.Esp; adwValues[7] = stContext.Ebp; adwValues[8] = stContext.Eip; return fGuiUpdateRegistersList(hList, apszRegNames, adwValues, _countof(apszRegNames)); }
// Given the window handle and the number of characters, returns the // width and height in pixels that will be occupied by a string of that // consisting of those number of characters HRESULT CHL_GuiGetTextArea(_In_ HWND hWindow, _In_ int nCharsInText, _Out_ int *pnPixelsWidth, _Out_ int *pnPixelsHeight) { HDC hDC = NULL; TEXTMETRIC stTextMetric; HRESULT hr = S_OK; // Parameter validation if(!ISVALID_HANDLE(hWindow) || nCharsInText < 0 || !pnPixelsWidth || !pnPixelsHeight) { hr = E_INVALIDARG; goto done; } hDC = GetDC(hWindow); if(hDC == NULL) { hr = E_FAIL; // GetDC doesn't set last error goto done; } // TODO: hDC is uninitialized so system (bitmap) font by default? Should I select the font into the DC first? if(!GetTextMetrics(hDC, &stTextMetric)) { hr = E_FAIL; // GetTextMetric doesn't set last error goto done; } *pnPixelsWidth = stTextMetric.tmMaxCharWidth * nCharsInText; *pnPixelsHeight = stTextMetric.tmHeight + stTextMetric.tmExternalLeading; done: if(hDC != NULL) { ReleaseDC(hWindow, hDC); } return hr; }
HRESULT CHL_GuiInitListViewColumns( _In_ HWND hList, _In_ WCHAR *apszColumNames[], _In_ int nColumns, _In_opt_ int *paiColumnSizePercent) { int index; LVCOLUMN lvColumn = {0}; int *paiColumnSizes = NULL; RECT rcList; LONG lListWidth; HRESULT hr = S_OK; // Parameter validation if(!ISVALID_HANDLE(hList) || !apszColumNames || nColumns <= 0) { hr = E_INVALIDARG; goto done; } // Create memory to hold calculated column sizes hr = CHL_MmAlloc((void**)&paiColumnSizes, sizeof(int) * nColumns, NULL); if(FAILED(hr)) { goto done; } // Calculate listview width if(!GetWindowRect(hList, &rcList)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto done; } // Calculate column sizes lListWidth = rcList.right - rcList.left; if(!paiColumnSizePercent) { for(index = 0; index < nColumns; ++index) { paiColumnSizes[index] = (int)(0.5 * lListWidth); } } else { for(index = 0; index < nColumns; ++index) { paiColumnSizes[index] = (int)(paiColumnSizePercent[index] / 100.0 * lListWidth); } } // List view headers lvColumn.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; for(index = 0; index < nColumns; ++index) { lvColumn.pszText = apszColumNames[index]; lvColumn.cx = paiColumnSizes[index]; SendMessage(hList, LVM_INSERTCOLUMN, index, (LPARAM)&lvColumn); } done: IFPTR_FREE(paiColumnSizes); return hr; }
BOOL fCreateTabPage(HWND hTab, __out PTABPAGEINFO pstTabPageInfo, __out DWORD *pdwErrCode) { ASSERT(ISVALID_HANDLE(hTab)); ASSERT(pstTabPageInfo); ASSERT(pdwErrCode); RECT rcTabWindow; RECT rcTabDisplay; int iNewIndex = -1; HWND hEditDisass, hListCStack, hListRegisters, hListThreads, hTabBottom, hEditCommand, hStaticCommand; // Init all handles to NULL hEditDisass = hListCStack = hListRegisters = hListThreads = hTabBottom = hEditCommand = hStaticCommand = NULL; // Insert a new tab item if(!fInsertTabItem(hTab, L"Test", &iNewIndex, NULL)) { // todo: log goto error_return; } ASSERT(iNewIndex > -1); if(!GetWindowRect(hTab, &rcTabWindow)) { // todo: log goto error_return; } CopyRect(&rcTabDisplay, &rcTabWindow); SendMessage(hTab, TCM_ADJUSTRECT, FALSE, (LPARAM)&rcTabDisplay); ScreenToClient(hTab, (LPPOINT)&rcTabDisplay.left); ScreenToClient(hTab, (LPPOINT)&rcTabDisplay.right); // Calculate width for the text static 'Command:' (without quotes) and the edit control WCHAR szTextCommand[] = L"Command:"; int iTextWidth, iTextHeight; if(!fChlGuiGetTextArea(hTab, wcslen(szTextCommand), &iTextWidth, &iTextHeight)) { logerror(pstLogger, L"%s(): fChlGuiGetTextArea() failed %u", GetLastError()); goto error_return; } int iCursorHeight = GetSystemMetrics(SM_CYCURSOR); // Bounding rectangle of the tab page's display area int x0 = rcTabDisplay.left; int y0 = rcTabDisplay.top; int xMax = rcTabDisplay.right; int yMax = rcTabDisplay.bottom; int tabWidth = xMax - x0; int tabHeight = yMax - y0; int liHeight = (tabHeight - iCursorHeight) * 0.33; int w50 = tabWidth / 2; // width 1/2 int h75 = tabHeight * 0.75; // height 3/4 int h25 = tabHeight - h75; // height 1/4 // Create the disass window hEditDisass = CreateWindow( WC_EDIT, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE | ES_LEFT | ES_MULTILINE | ES_READONLY, x0, y0, w50, h75, hTab, (HMENU)IDC_EDIT_DISASS, g_hMainInstance, NULL); ISNULL_GOTO(hEditDisass, error_return); RECT rcTemp; // Three list views hListCStack = CreateWindow( WC_LISTVIEW, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT, x0 + w50, y0, w50, liHeight, hTab, (HMENU)IDC_LIST_CALLSTACK, g_hMainInstance, NULL); ISNULL_GOTO(hListCStack, error_return); GetWindowRect(hListCStack, &rcTemp); // TODO: initialize columns hListRegisters = CreateWindow( WC_LISTVIEW, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT, x0 + w50, y0 + liHeight, w50, liHeight, hTab, (HMENU)IDC_LIST_REGISTERS, g_hMainInstance, NULL); ISNULL_GOTO(hListRegisters, error_return); GetWindowRect(hListRegisters, &rcTemp); // Initialize columns if(!fChlGuiInitListViewColumns(hListRegisters, aszColumnNames_Regs, NELEMS_ARRAY(aszColumnNames_Regs), aiColumnSizePercent_Regs)) { // todo: log error goto error_return; } hListThreads = CreateWindow( WC_LISTVIEW, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT, x0 + w50, y0 + liHeight + liHeight, w50, liHeight, hTab, (HMENU)IDC_LIST_THREADS, g_hMainInstance, NULL); ISNULL_GOTO(hListThreads, error_return); GetWindowRect(hListThreads, &rcTemp); // Initialize columns if(!fChlGuiInitListViewColumns(hListThreads, aszColumnNames_Threads, NELEMS_ARRAY(aszColumnNames_Threads), aiColumnSizePercent_Threads)) { // todo: log error goto error_return; } // Command static and edit controls hStaticCommand = CreateWindow( WC_STATIC, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE, x0 + w50, yMax - iCursorHeight, iTextWidth, iCursorHeight, hTab, NULL, g_hMainInstance, NULL); ISNULL_GOTO(hStaticCommand, error_return); SendMessage(hStaticCommand, WM_SETTEXT, 0, (LPARAM)szTextCommand); GetWindowRect(hStaticCommand, &rcTemp); hEditCommand = CreateWindow( WC_EDIT, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE | ES_LEFT, x0 + w50 + iTextWidth + 2, yMax - iCursorHeight, w50 - iTextWidth - 2, iCursorHeight, hTab, NULL, g_hMainInstance, NULL); ISNULL_GOTO(hEditCommand, error_return); // The bottom tab control hTabBottom = CreateWindow( WC_TABCONTROL, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE, x0, y0 + h75, w50, h25, hTab, (HMENU)IDC_TAB_BOTTOM, g_hMainInstance, NULL); ISNULL_GOTO(hTabBottom, error_return); pstTabPageInfo->hMainTab = hTab; pstTabPageInfo->hEditDisass = hEditDisass; pstTabPageInfo->hListCallStack = hListCStack; pstTabPageInfo->hListRegisters = hListRegisters; pstTabPageInfo->hListThreads = hListThreads; pstTabPageInfo->hEditCommand = hEditCommand; pstTabPageInfo->hStaticCommand = hStaticCommand; pstTabPageInfo->hTabBottom = hTabBottom; pstTabPageInfo->iTabIndex = iNewIndex; return TRUE; error_return: SET_ERRORCODE_PTR(pdwErrCode); ZeroMemory(pstTabPageInfo, sizeof(TABPAGEINFO)); return FALSE; }
BOOL fUpdateThreadsListView(HWND hList, CHL_HTABLE *phtThreads, HANDLE hMainThread) { ASSERT(ISVALID_HANDLE(hList)); ASSERT(phtThreads); BOOL fRetVal = TRUE; CHL_HT_ITERATOR itr; int keysize, valsize; DWORD dwThreadID = 0; LPCREATE_THREAD_DEBUG_INFO pThreadDbgInfo = NULL; int nThreads; PLV_THREADINFO pstThreadInfo = NULL; CONTEXT stContext; // Create memory to hold thread info for display // Assume 32 max threads now because there is no easy way to get this info // from the hashtable // TODO: Handle dynamic number of threads if(!fChlMmAlloc((void**)&pstThreadInfo, sizeof(LV_THREADINFO) * 32, NULL)) { return FALSE; } ZeroMemory(&stContext, sizeof(stContext)); nThreads = 0; fChlDsInitIteratorHT(&itr); while(fChlDsGetNextHT(phtThreads, &itr, &dwThreadID, &keysize, &pThreadDbgInfo, &valsize)) { ASSERT(pThreadDbgInfo); ASSERT(ISVALID_HANDLE(pThreadDbgInfo->hThread)); pstThreadInfo[nThreads].dwThreadId = dwThreadID; // Get EIP value stContext.ContextFlags = CONTEXT_CONTROL; if(!GetThreadContext(pThreadDbgInfo->hThread, &stContext)) { dbgwprintf(L"%s(): GetThreadPriority() failed for id = %u, handle = 0x%08x", __FUNCTIONW__, dwThreadID, pThreadDbgInfo->hThread); logwarn(pstLogger, L"%s(): GetThreadContext() failed for id = %u, handle = 0x%08x", __FUNCTIONW__, dwThreadID, pThreadDbgInfo->hThread); pstThreadInfo[nThreads].dwEIPLocation = 0; fRetVal = FALSE; } else { pstThreadInfo[nThreads].dwEIPLocation = stContext.Eip; } // Determine main / worker thread pstThreadInfo[nThreads].thType = pThreadDbgInfo->hThread == hMainThread ? THTYPE_MAIN : THTYPE_WORKER; // Get priority pstThreadInfo[nThreads].iThreadPri = GetThreadPriority(pThreadDbgInfo->hThread); if(pstThreadInfo[nThreads].iThreadPri == THREAD_PRIORITY_ERROR_RETURN) { dbgwprintf(L"%s(): GetThreadPriority() failed for id = %u, handle = 0x%08x", __FUNCTIONW__, dwThreadID, pThreadDbgInfo->hThread); logwarn(pstLogger, L"%s(): GetThreadPriority() failed for id = %u, handle = 0x%08x", __FUNCTIONW__, dwThreadID, pThreadDbgInfo->hThread); fRetVal = FALSE; } pstThreadInfo[nThreads].szFunction[0] = 0; ++nThreads; } // Update listview fRetVal &= fGuiUpdateThreadsList(hList, pstThreadInfo, nThreads); vChlMmFree((void**)&pstThreadInfo); return fRetVal; }