Enumerating the Processes Running in the System

[Previous] [Next]

Many software developers try to write tools or utilities for Windows that require the set of running processes to be enumerated. The Windows API originally had no functions that enumerated the running processes. However, Windows NT has a constantly updating database called the Performance Data database. This database contains a ton of information and is available through registry functions such as RegQueryValueEx with the HKEY_PERFORMANCE_DATA root key. Few Windows programmers know about the performance database for these reasons:

  • It has no functions that are specific to it; it simply uses existing registry functions.
  • It is not available on Windows 95 and Windows 98.
  • The layout of information in the database is complex; many developers avoid using it. This prevents knowledge of its existence from spreading by word of mouth.

To make working with this database easier, Microsoft created a Performance Data Helper set of functions (contained in PDH.dll). For more information about this library, search for Performance Data Helper in the Platform SDK documentation.

As I mentioned above, Windows 95 and 98 do not offer this performance database. Instead, they have their own set of functions to enumerate processes and information about them. These are in the ToolHelp API. For more information, search for the Process32First and Process32Next functions in the Platform SDK documentation.

To make things more fun, Microsoft's Windows NT team, which doesn't like the ToolHelp functions, did not add them to Windows NT. Instead, they produced their own Process Status functions to enumerate processes (contained in PSAPI.dll). For more information, search for the EnumProcesses function in the Platform SDK documentation.

Microsoft might appear to be making life difficult for tool and utility developers, but I'm happy to report that it has added the ToolHelp functions to Windows 2000. Finally, developers have a way to write tools and utilities that have common source code for Windows 95, Windows 98, and Windows 2000!

The Process Information Sample Application

The ProcessInfo application, "04 ProcessInfo.exe"(listed in Figure 4-6), shows how to use the ToolHelp functions to produce a very useful utility. The source code and resource files for the application are in the 04ProcessInfo directory on the companion CD-ROM. When you start the program, the window shown in Figure 4-4 appears.

click to view at full size.

Figure 4-4. ProcessInfo in action

ProcessInfo first enumerates the set of processes currently running and places each process's name and ID in the top combo box. Then the first process is selected and information about that process is shown in the large read-only edit control. As you can see, the process's ID is shown along with its parent process's ID, the priority class of the process, and the number of threads currently running in the context of the process. Much of the information is beyond the scope of this chapter but will be discussed in later chapters.

When you look at the process list, the VMMap menu item is available. (This item is disabled when you look at the module information.) Selecting the VMMap menu item causes the VMMap sample application (discussed in Chapter14) to run. This application walks the address space of the selected process.

The module information portion shows the list of modules (executables and DLLs) that are mapped into the process's address space. A fixed module is one that was implicitly loaded when the process initialized. For explicitly loaded DLLs, the DLL's usage count is shown. The second field shows the memory address where the module is mapped. If the module is not mapped at its preferred base address, the preferred base address also appears in parentheses. The third field shows the size of the module in bytes, and finally, the full pathname of the module is displayed. The thread information portion shows the set of threads currently running in the context of this process. Each thread's ID and priority is shown.

In addition to the process information, you can choose the Modules! menu item. This causes ProcessInfo to enumerate the set of modules currently loaded throughout the system and places each module's name in the top combo box. Then ProcessInfo selects the first module and displays information about it, as Figure 4-5 shows.

click to view at full size.

Figure 4-5. ProcessInfo showing all processes that have User32.dll loaded in their address space

When you use the ProcessInfo utility in this way, you can easily determine which processes are using a particular module. As you can see, the module's full pathname is shown at the top. The Process Information section then shows the list of processes that contain the module. In addition to each process's ID and name, the address where the module is loaded in each process is shown.

Basically, all of the information displayed by the ProcessInfo application is produced by calling the various ToolHelp functions. To make working with the ToolHelp functions a little easier, I created a CToolhelp C++ class (contained in the Toolhelp.h file). This C++ class encapsulates a ToolHelp snapshot and makes calling the other ToolHelp functions a bit easier.

The GetModulePreferredBaseAddr function inside ProcessInfo.cpp is particularly interesting:

 PVOID GetModulePreferredBaseAddr( DWORD dwProcessId, PVOID pvModuleRemote); 

This function accepts a process ID and the address of a module in that process. It then looks in that process's address space, locates that module, and reads the module's header information to determine the module's preferred base address. A module should always load at its preferred base address; otherwise applications that use the module require more memory and take a performance hit while initializing. Since this is such a horrible situation, I added this function and I show when a module doesn't load at its preferred base address. You'll see more on preferred base addresses and this time/memory performance hit in the "Rebasing Modules" section of Chapter 20.

Figure 4-6. The ProcessInfo application

ProcessInfo.cpp

 /****************************************************************************** Module: ProcessInfo.cpp Notices: Copyright (c) 2000 Jeffrey Richter ******************************************************************************/ #include "..\CmnHdr.h" /* See Appendix A. */ #include <windowsx.h> #include <tlhelp32.h> #include <tchar.h> #include <stdarg.h> #include <stdio.h> #include "Toolhelp.h" #include "Resource.h" /////////////////////////////////////////////////////////////////////////////// // Adds a string to an edit control void AddText(HWND hwnd, PCTSTR pszFormat, ...) { va_list argList; va_start(argList, pszFormat); TCHAR sz[20 * 1024]; Edit_GetText(hwnd, sz, chDIMOF(sz)); _vstprintf(_tcschr(sz, 0), pszFormat, argList); Edit_SetText(hwnd, sz); va_end(argList); } /////////////////////////////////////////////////////////////////////////////// VOID Dlg_PopulateProcessList(HWND hwnd) { HWND hwndList = GetDlgItem(hwnd, IDC_PROCESSMODULELIST); SetWindowRedraw(hwndList, FALSE); ComboBox_ResetContent(hwndList); CToolhelp thProcesses(TH32CS_SNAPPROCESS); PROCESSENTRY32 pe = { sizeof(pe) }; BOOL fOk = thProcesses.ProcessFirst(&pe); for (; fOk; fOk = thProcesses.ProcessNext(&pe)) { TCHAR sz[1024]; // Place the process name (without its path) & ID in the list PCTSTR pszExeFile = _tcsrchr(pe.szExeFile, TEXT('\\')); if (pszExeFile == NULL) pszExeFile = pe.szExeFile; else pszExeFile++; // Skip over the slash wsprintf(sz, TEXT("%s (0x%08X)"), pszExeFile, pe.th32ProcessID); int n = ComboBox_AddString(hwndList, sz); // Associate the process ID with the added item ComboBox_SetItemData(hwndList, n, pe.th32ProcessID); } ComboBox_SetCurSel(hwndList, 0); // Select the first entry // Simulate the user selecting this first item so that the // results pane shows something interesting FORWARD_WM_COMMAND(hwnd, IDC_PROCESSMODULELIST, hwndList, CBN_SELCHANGE, SendMessage); SetWindowRedraw(hwndList, TRUE); InvalidateRect(hwndList, NULL, FALSE); } /////////////////////////////////////////////////////////////////////////////// VOID Dlg_PopulateModuleList(HWND hwnd) { HWND hwndModuleHelp = GetDlgItem(hwnd, IDC_MODULEHELP); ListBox_ResetContent(hwndModuleHelp); CToolhelp thProcesses(TH32CS_SNAPPROCESS); PROCESSENTRY32 pe = { sizeof(pe) }; BOOL fOk = thProcesses.ProcessFirst(&pe); for (; fOk; fOk = thProcesses.ProcessNext(&pe)) { CToolhelp thModules(TH32CS_SNAPMODULE, pe.th32ProcessID); MODULEENTRY32 me = { sizeof(me) }; BOOL fOk = thModules.ModuleFirst(&me); for (; fOk; fOk = thModules.ModuleNext(&me)) { int n = ListBox_FindStringExact(hwndModuleHelp, -1, me.szExePath); if (n == LB_ERR) { // This module hasn't been added before ListBox_AddString(hwndModuleHelp, me.szExePath); } } } HWND hwndList = GetDlgItem(hwnd, IDC_PROCESSMODULELIST); SetWindowRedraw(hwndList, FALSE); ComboBox_ResetContent(hwndList); int nNumModules = ListBox_GetCount(hwndModuleHelp); for (int i = 0; i < nNumModules; i++) { TCHAR sz[1024]; ListBox_GetText(hwndModuleHelp, i, sz); // Place module name (without its path) in the list int nIndex = ComboBox_AddString(hwndList, _tcsrchr(sz, TEXT('\\')) + 1); // Associate the index of the full path with the added item ComboBox_SetItemData(hwndList, nIndex, i); } ComboBox_SetCurSel(hwndList, 0); // Select the first entry // Simulate the user selecting this first item so that the // results pane shows something interesting FORWARD_WM_COMMAND(hwnd, IDC_PROCESSMODULELIST, hwndList, CBN_SELCHANGE, SendMessage); SetWindowRedraw(hwndList, TRUE); InvalidateRect(hwndList, NULL, FALSE); } /////////////////////////////////////////////////////////////////////////////// PVOID GetModulePreferredBaseAddr(DWORD dwProcessId, PVOID pvModuleRemote) { PVOID pvModulePreferredBaseAddr = NULL; IMAGE_DOS_HEADER idh; IMAGE_NT_HEADERS inth; // Read the remote module's DOS header Toolhelp32ReadProcessMemory(dwProcessId, pvModuleRemote, &idh, sizeof(idh), NULL); // Verify the DOS image header if (idh.e_magic == IMAGE_DOS_SIGNATURE) { // Read the remote module's NT header Toolhelp32ReadProcessMemory(dwProcessId, (PBYTE) pvModuleRemote + idh.e_lfanew, &inth, sizeof(inth), NULL); // Verify the NT image header if (inth.Signature == IMAGE_NT_SIGNATURE) { // This is valid NT header, get the image's preferred base address pvModulePreferredBaseAddr = (PVOID) inth.OptionalHeader.ImageBase; } } return(pvModulePreferredBaseAddr); } /////////////////////////////////////////////////////////////////////////////// VOID ShowProcessInfo(HWND hwnd, DWORD dwProcessID) { SetWindowText(hwnd, TEXT("")); // Clear the output box CToolhelp th(TH32CS_SNAPALL, dwProcessID); // Show Process details PROCESSENTRY32 pe = { sizeof(pe) }; BOOL fOk = th.ProcessFirst(&pe); for (; fOk; fOk = th.ProcessNext(&pe)) { if (pe.th32ProcessID == dwProcessID) { AddText(hwnd, TEXT("Filename: %s\r\n"), pe.szExeFile); AddText(hwnd, TEXT(" PID=%08X, ParentPID=%08X, ") TEXT("PriorityClass=%d, Threads=%d, Heaps=%d\r\n"), pe.th32ProcessID, pe.th32ParentProcessID, pe.pcPriClassBase, pe.cntThreads, th.HowManyHeaps()); break; // No need to continue looping } } // Show Modules in the Process // Number of characters to display an address const int cchAddress = sizeof(PVOID) * 2; AddText(hwnd, TEXT("\r\nModules Information:\r\n") TEXT(" Usage %-*s(%-*s) %8s Module\r\n"), cchAddress, TEXT("BaseAddr"), cchAddress, TEXT("ImagAddr"), TEXT("Size")); MODULEENTRY32 me = { sizeof(me) }; fOk = th.ModuleFirst(&me); for (; fOk; fOk = th.ModuleNext(&me)) { if (me.ProccntUsage == 65535) { // Module was implicitly loaded and cannot be unloaded AddText(hwnd, TEXT(" Fixed")); } else { AddText(hwnd, TEXT(" %5d"), me.ProccntUsage); } PVOID pvPreferredBaseAddr = GetModulePreferredBaseAddr(pe.th32ProcessID, me.modBaseAddr); if (me.modBaseAddr == pvPreferredBaseAddr) { AddText(hwnd, TEXT(" %p %*s %8u %s\r\n"), me.modBaseAddr, cchAddress, TEXT(""), me.modBaseSize, me.szExePath); } else { AddText(hwnd, TEXT(" %p(%p) %8u %s\r\n"), me.modBaseAddr, pvPreferredBaseAddr, me.modBaseSize, me.szExePath); } } // Show threads in the process AddText(hwnd, TEXT("\r\nThread Information:\r\n") TEXT(" TID Priority\r\n")); THREADENTRY32 te = { sizeof(te) }; fOk = th.ThreadFirst(&te); for (; fOk; fOk = th.ThreadNext(&te)) { if (te.th32OwnerProcessID == dwProcessID) { int nPriority = te.tpBasePri + te.tpDeltaPri; if ((te.tpBasePri < 16) && (nPriority > 15)) nPriority = 15; if ((te.tpBasePri > 15) && (nPriority > 31)) nPriority = 31; if ((te.tpBasePri < 16) && (nPriority < 1)) nPriority = 1; if ((te.tpBasePri > 15) && (nPriority < 16)) nPriority = 16; AddText(hwnd, TEXT(" %08X %2d\r\n"), te.th32ThreadID, nPriority); } } } /////////////////////////////////////////////////////////////////////////////// VOID ShowModuleInfo(HWND hwnd, LPCTSTR pszModulePath) { SetWindowText(hwnd, TEXT("")); // Clear the output box CToolhelp thProcesses(TH32CS_SNAPPROCESS); PROCESSENTRY32 pe = { sizeof(pe) }; BOOL fOk = thProcesses.ProcessFirst(&pe); AddText(hwnd, TEXT("Pathname: %s\r\n\r\n"), pszModulePath); AddText(hwnd, TEXT("Process Information:\r\n")); AddText(hwnd, TEXT(" PID BaseAddr Process\r\n")); for (; fOk; fOk = thProcesses.ProcessNext(&pe)) { CToolhelp thModules(TH32CS_SNAPMODULE, pe.th32ProcessID); MODULEENTRY32 me = { sizeof(me) }; BOOL fOk = thModules.ModuleFirst(&me); for (; fOk; fOk = thModules.ModuleNext(&me)) { if (_tcscmp(me.szExePath, pszModulePath) == 0) { AddText(hwnd, TEXT(" %08X %p %s\r\n"), pe.th32ProcessID, me.modBaseAddr, pe.szExeFile); } } } } /////////////////////////////////////////////////////////////////////////////// BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) { chSETDLGICONS(hwnd, IDI_PROCESSINFO); // Hide the module-helper listbox. ShowWindow(GetDlgItem(hwnd, IDC_MODULEHELP), SW_HIDE); // Have the results window use a fixed-pitch font SetWindowFont(GetDlgItem(hwnd, IDC_RESULTS), GetStockFont(ANSI_FIXED_FONT), FALSE); // By default, show the running processes Dlg_PopulateProcessList(hwnd); return(TRUE); } /////////////////////////////////////////////////////////////////////////////// BOOL Dlg_OnSize(HWND hwnd, UINT state, int cx, int cy) { RECT rc; int n = LOWORD(GetDialogBaseUnits()); HWND hwndCtl = GetDlgItem(hwnd, IDC_PROCESSMODULELIST); GetClientRect(hwndCtl, &rc); SetWindowPos(hwndCtl, NULL, n, n, cx - n - n, rc.bottom, SWP_NOZORDER); hwndCtl = GetDlgItem(hwnd, IDC_RESULTS); SetWindowPos(hwndCtl, NULL, n, n + rc.bottom + n, cx - n - n, cy - (n + rc.bottom + n) - n, SWP_NOZORDER); return(0); } /////////////////////////////////////////////////////////////////////////////// void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { static BOOL s_fProcesses = TRUE; switch (id) { case IDCANCEL: EndDialog(hwnd, id); break; case ID_PROCESSES: s_fProcesses = TRUE; EnableMenuItem(GetMenu(hwnd), ID_VMMAP, MF_BYCOMMAND | MF_ENABLED); DrawMenuBar(hwnd); Dlg_PopulateProcessList(hwnd); break; case ID_MODULES: EnableMenuItem(GetMenu(hwnd), ID_VMMAP, MF_BYCOMMAND | MF_GRAYED); DrawMenuBar(hwnd); s_fProcesses = FALSE; Dlg_PopulateModuleList(hwnd); break; case IDC_PROCESSMODULELIST: if (codeNotify == CBN_SELCHANGE) { DWORD dw = ComboBox_GetCurSel(hwndCtl); if (s_fProcesses) { dw = (DWORD) ComboBox_GetItemData(hwndCtl, dw); // Process ID ShowProcessInfo(GetDlgItem(hwnd, IDC_RESULTS), dw); } else { // Index in helper listbox of full path dw = (DWORD) ComboBox_GetItemData(hwndCtl, dw); TCHAR szModulePath[1024]; ListBox_GetText(GetDlgItem(hwnd, IDC_MODULEHELP), dw, szModulePath); ShowModuleInfo(GetDlgItem(hwnd, IDC_RESULTS), szModulePath); } } break; case ID_VMMAP: STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; TCHAR szCmdLine[1024]; HWND hwndCB = GetDlgItem(hwnd, IDC_PROCESSMODULELIST); DWORD dwProcessId = (DWORD) ComboBox_GetItemData(hwndCB, ComboBox_GetCurSel(hwndCB)); wsprintf(szCmdLine, TEXT("\"14 VMMap\" %d"), dwProcessId); BOOL fOk = CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); if (fOk) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } else { chMB("Failed to execute VMMAP.EXE."); } break; } } /////////////////////////////////////////////////////////////////////////////// INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog); chHANDLE_DLGMSG(hwnd, WM_SIZE, Dlg_OnSize); chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand); } return(FALSE); } /////////////////////////////////////////////////////////////////////////////// int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) { CToolhelp::EnableDebugPrivilege(TRUE); DialogBox(hinstExe, MAKEINTRESOURCE(IDD_PROCESSINFO), NULL, Dlg_Proc); CToolhelp::EnableDebugPrivilege(FALSE); return(0); } //////////////////////////////// End of File////////////////////////////////// 

ProcessInfo.rc

 //Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_PROCESSINFO DIALOGEX 0, 0, 400, 317 STYLE DS_3DLOOK | DS_NOFAILCREATE | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE CAPTION "Process Information" MENU IDR_PROCESSINFO FONT 8, "MS Sans Serif" BEGIN COMBOBOX IDC_PROCESSMODULELIST,4,4,392,156,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP LISTBOX IDC_MODULEHELP,0,0,48,40,NOT LBS_NOTIFY | LBS_SORT | LBS_NOINTEGRALHEIGHT | NOT WS_VISIBLE | NOT WS_BORDER | WS_TABSTOP EDITTEXT IDC_RESULTS,4,24,392,284,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_PROCESSINFO, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 393 TOPMARGIN, 7 BOTTOMMARGIN, 310 END END #endif // APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Menu // IDR_PROCESSINFO MENU DISCARDABLE BEGIN MENUITEM "&Processes!", ID_PROCESSES MENUITEM "&Modules!", ID_MODULES MENUITEM "&VMMap!", ID_VMMAP END ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_PROCESSINFO ICON DISCARDABLE "ProcessInfo.ico" #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED 

Toolhelp.h

 /****************************************************************************** Module: Toolhelp.h Notices: Copyright (c) 2000 Jeffrey Richter ******************************************************************************/ #include "..\CmnHdr.h" /* See Appendix A. */ #include <tlhelp32.h> #include <tchar.h> /////////////////////////////////////////////////////////////////////////////// class CToolhelp { private: HANDLE m_hSnapshot; public: CToolhelp(DWORD dwFlags = 0, DWORD dwProcessID = 0); ~CToolhelp(); BOOL CreateSnapshot(DWORD dwFlags, DWORD dwProcessID = 0); BOOL ProcessFirst(PPROCESSENTRY32 ppe) const; BOOL ProcessNext(PPROCESSENTRY32 ppe) const; BOOL ProcessFind(DWORD dwProcessId, PPROCESSENTRY32 ppe) const; BOOL ModuleFirst(PMODULEENTRY32 pme) const; BOOL ModuleNext(PMODULEENTRY32 pme) const; BOOL ModuleFind(PVOID pvBaseAddr, PMODULEENTRY32 pme) const; BOOL ModuleFind(PTSTR pszModName, PMODULEENTRY32 pme) const; BOOL ThreadFirst(PTHREADENTRY32 pte) const; BOOL ThreadNext(PTHREADENTRY32 pte) const; BOOL HeapListFirst(PHEAPLIST32 phl) const; BOOL HeapListNext(PHEAPLIST32 phl) const; int HowManyHeaps() const; // Note: The heap block functions do not reference a snapshot and // just walk the process's heap from the beginning each time. Infinite // loops can occur if the target process changes its heap while the // functions below are enumerating the blocks in the heap. BOOL HeapFirst(PHEAPENTRY32 phe, DWORD dwProcessID, UINT_PTR dwHeapID) const; BOOL HeapNext(PHEAPENTRY32 phe) const; int HowManyBlocksInHeap(DWORD dwProcessID, DWORD dwHeapId) const; BOOL IsAHeap(HANDLE hProcess, PVOID pvBlock, PDWORD pdwFlags) const; public: static BOOL EnableDebugPrivilege(BOOL fEnable = TRUE); static BOOL ReadProcessMemory(DWORD dwProcessID, LPCVOID pvBaseAddress, PVOID pvBuffer, DWORD cbRead, PDWORD pdwNumberOfBytesRead = NULL); }; /////////////////////////////////////////////////////////////////////////////// inline CToolhelp::CToolhelp(DWORD dwFlags, DWORD dwProcessID) { m_hSnapshot = INVALID_HANDLE_VALUE; CreateSnapshot(dwFlags, dwProcessID); } /////////////////////////////////////////////////////////////////////////////// inline CToolhelp::~CToolhelp() { if (m_hSnapshot != INVALID_HANDLE_VALUE) CloseHandle(m_hSnapshot); } /////////////////////////////////////////////////////////////////////////////// inline CToolhelp::CreateSnapshot(DWORD dwFlags, DWORD dwProcessID) { if (m_hSnapshot != INVALID_HANDLE_VALUE) CloseHandle(m_hSnapshot); if (dwFlags == 0) { m_hSnapshot = INVALID_HANDLE_VALUE; } else { m_hSnapshot = CreateToolhelp32Snapshot(dwFlags, dwProcessID); } return(m_hSnapshot != INVALID_HANDLE_VALUE); } /////////////////////////////////////////////////////////////////////////////// inline BOOL CToolhelp::EnableDebugPrivilege(BOOL fEnable) { // Enabling the debug privilege allows the application to see // information about service applications BOOL fOk = FALSE; // Assume function fails HANDLE hToken; // Try to open this process's access token if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { // Attempt to modify the "Debug" privilege TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0; AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); fOk = (GetLastError() == ERROR_SUCCESS); CloseHandle(hToken); } return(fOk); } /////////////////////////////////////////////////////////////////////////////// inline BOOL CToolhelp::ReadProcessMemory(DWORD dwProcessID, LPCVOID pvBaseAddress, PVOID pvBuffer, DWORD cbRead, PDWORD pdwNumberOfBytesRead) { return(Toolhelp32ReadProcessMemory(dwProcessID, pvBaseAddress, pvBuffer, cbRead, pdwNumberOfBytesRead)); } /////////////////////////////////////////////////////////////////////////////// inline BOOL CToolhelp::ProcessFirst(PPROCESSENTRY32 ppe) const { BOOL fOk = Process32First(m_hSnapshot, ppe); if (fOk && (ppe->th32ProcessID == 0)) fOk = ProcessNext(ppe); // Remove the "[System Process]" (PID = 0) return(fOk); } inline BOOL CToolhelp::ProcessNext(PPROCESSENTRY32 ppe) const { BOOL fOk = Process32Next(m_hSnapshot, ppe); if (fOk && (ppe->th32ProcessID == 0)) fOk = ProcessNext(ppe); // Remove the "[System Process]" (PID = 0) return(fOk); } inline BOOL CToolhelp::ProcessFind(DWORD dwProcessId, PPROCESSENTRY32 ppe) const { BOOL fFound = FALSE; for (BOOL fOk = ProcessFirst(ppe); fOk; fOk = ProcessNext(ppe)) { fFound = (ppe->th32ProcessID == dwProcessId); if (fFound) break; } return(fFound); } /////////////////////////////////////////////////////////////////////////////// inline BOOL CToolhelp::ModuleFirst(PMODULEENTRY32 pme) const { return(Module32First(m_hSnapshot, pme)); } inline BOOL CToolhelp::ModuleNext(PMODULEENTRY32 pme) const { return(Module32Next(m_hSnapshot, pme)); } inline BOOL CToolhelp::ModuleFind(PVOID pvBaseAddr, PMODULEENTRY32 pme) const { BOOL fFound = FALSE; for (BOOL fOk = ModuleFirst(pme); fOk; fOk = ModuleNext(pme)) { fFound = (pme->modBaseAddr == pvBaseAddr); if (fFound) break; } return(fFound); } inline BOOL CToolhelp::ModuleFind(PTSTR pszModName, PMODULEENTRY32 pme) const { BOOL fFound = FALSE; for (BOOL fOk = ModuleFirst(pme); fOk; fOk = ModuleNext(pme)) { fFound = (lstrcmpi(pme->szModule, pszModName) == 0) || (lstrcmpi(pme->szExePath, pszModName) == 0); if (fFound) break; } return(fFound); } /////////////////////////////////////////////////////////////////////////////// inline BOOL CToolhelp::ThreadFirst(PTHREADENTRY32 pte) const { return(Thread32First(m_hSnapshot, pte)); } inline BOOL CToolhelp::ThreadNext(PTHREADENTRY32 pte) const { return(Thread32Next(m_hSnapshot, pte)); } /////////////////////////////////////////////////////////////////////////////// inline int CToolhelp::HowManyHeaps() const { int nHowManyHeaps = 0; HEAPLIST32 hl = { sizeof(hl) }; for (BOOL fOk = HeapListFirst(&hl); fOk; fOk = HeapListNext(&hl)) nHowManyHeaps++; return(nHowManyHeaps); } inline int CToolhelp::HowManyBlocksInHeap(DWORD dwProcessID, DWORD dwHeapID) const { int nHowManyBlocksInHeap = 0; HEAPENTRY32 he = { sizeof(he) }; BOOL fOk = HeapFirst(&he, dwProcessID, dwHeapID); for (; fOk; fOk = HeapNext(&he)) nHowManyBlocksInHeap++; return(nHowManyBlocksInHeap); } inline BOOL CToolhelp::HeapListFirst(PHEAPLIST32 phl) const { return(Heap32ListFirst(m_hSnapshot, phl)); } inline BOOL CToolhelp::HeapListNext(PHEAPLIST32 phl) const { return(Heap32ListNext(m_hSnapshot, phl)); } inline BOOL CToolhelp::HeapFirst(PHEAPENTRY32 phe, DWORD dwProcessID, UINT_PTR dwHeapID) const { return(Heap32First(phe, dwProcessID, dwHeapID)); } inline BOOL CToolhelp::HeapNext(PHEAPENTRY32 phe) const { return(Heap32Next(phe)); } inline BOOL CToolhelp::IsAHeap(HANDLE hProcess, PVOID pvBlock, PDWORD pdwFlags) const { HEAPLIST32 hl = { sizeof(hl) }; for (BOOL fOkHL = HeapListFirst(&hl); fOkHL; fOkHL = HeapListNext(&hl)) { HEAPENTRY32 he = { sizeof(he) }; BOOL fOkHE = HeapFirst(&he, hl.th32ProcessID, hl.th32HeapID); for (; fOkHE; fOkHE = HeapNext(&he)) { MEMORY_BASIC_INFORMATION mbi; VirtualQueryEx(hProcess, (PVOID) he.dwAddress, &mbi, sizeof(mbi)); if (chINRANGE(mbi.AllocationBase, pvBlock, (PBYTE) mbi.AllocationBase + mbi.RegionSize)) { *pdwFlags = hl.dwFlags; return(TRUE); } } } return(FALSE); } //////////////////////////////// End of File ////////////////////////////////// 



Programming Applications for Microsoft Windows
Programming Applications for Microsoft Windows (Microsoft Programming Series)
ISBN: 1572319968
EAN: 2147483647
Year: 1999
Pages: 193

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net