Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

832 lines
23 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 2000
  6. //
  7. // File: processes.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // Processes.cpp: implementation of the CProcesses class.
  11. //
  12. //////////////////////////////////////////////////////////////////////
  13. #ifndef NO_STRICT
  14. #ifndef STRICT
  15. #define STRICT 1
  16. #endif
  17. #endif /* NO_STRICT */
  18. #include <WINDOWS.H>
  19. #include <STDIO.H>
  20. #include <TCHAR.H>
  21. #include <stdlib.h>
  22. #include "Globals.h"
  23. #include "Processes.h"
  24. #include "ProcessInfo.h"
  25. #include "ProcessInfoNode.h"
  26. #include "FileData.h"
  27. #include "UtilityFunctions.h"
  28. //////////////////////////////////////////////////////////////////////
  29. // Construction/Destruction
  30. //////////////////////////////////////////////////////////////////////
  31. CProcesses::CProcesses()
  32. {
  33. m_fInitialized = false;
  34. m_iNumberOfProcesses = 0;
  35. m_enumProcessCollectionMethod = NO_METHOD;
  36. // Contained Objects
  37. m_lpProcessInfoHead = NULL;
  38. m_ProcessInfoHeadMutex = NULL;
  39. // m_lpProgramOptions = NULL;
  40. m_lpModuleInfoCache = NULL;
  41. m_lpOutputFile = NULL;
  42. m_lpInputFile = NULL;
  43. }
  44. CProcesses::~CProcesses()
  45. {
  46. WaitForSingleObject(m_ProcessInfoHeadMutex, INFINITE);
  47. // If we have Process Info Objects... nuke them now...
  48. if (m_lpProcessInfoHead)
  49. {
  50. CProcessInfoNode * lpProcessInfoNodePointer = m_lpProcessInfoHead;
  51. CProcessInfoNode * lpProcessInfoNodePointerToDelete = m_lpProcessInfoHead;
  52. // Traverse the linked list to the end..
  53. while (lpProcessInfoNodePointer)
  54. { // Keep looking for the end...
  55. // Advance our pointer to the next node...
  56. lpProcessInfoNodePointer = lpProcessInfoNodePointer->m_lpNextProcessInfoNode;
  57. // Delete the one behind us...
  58. delete lpProcessInfoNodePointerToDelete;
  59. // Set the node to delete to the current...
  60. lpProcessInfoNodePointerToDelete = lpProcessInfoNodePointer;
  61. }
  62. // Now, clear out the Head pointer...
  63. m_lpProcessInfoHead = NULL;
  64. }
  65. // Be a good citizen and release the Mutex
  66. ReleaseMutex(m_ProcessInfoHeadMutex);
  67. // Now, close the Mutex
  68. if (m_ProcessInfoHeadMutex)
  69. {
  70. CloseHandle(m_ProcessInfoHeadMutex);
  71. m_ProcessInfoHeadMutex = NULL;
  72. }
  73. }
  74. //bool CProcesses::Initialize(CProgramOptions * lpProgramOptions, CModuleInfoCache * lpModuleInfoCache, CFileData * lpInputFile, CFileData * lpOutputFile)
  75. bool CProcesses::Initialize(CModuleInfoCache * lpModuleInfoCache, CFileData * lpInputFile, CFileData * lpOutputFile)
  76. {
  77. // We need the following objects to do business...
  78. // if ( lpProgramOptions == NULL || lpModuleInfoCache == NULL)
  79. if ( lpModuleInfoCache == NULL)
  80. return false;
  81. // Let's save away our program options (beats passing it as an
  82. // argument to every method...)
  83. // m_lpProgramOptions = lpProgramOptions;
  84. m_lpInputFile = lpInputFile;
  85. m_lpOutputFile = lpOutputFile;
  86. m_lpModuleInfoCache = lpModuleInfoCache;
  87. m_ProcessInfoHeadMutex = CreateMutex(NULL, FALSE, NULL);
  88. if (m_ProcessInfoHeadMutex == NULL)
  89. return false;
  90. // We only need to grab these exported functions if we intend to
  91. // actively query our local machine's processes directly...
  92. if (g_lpProgramOptions->GetMode(CProgramOptions::InputProcessesFromLiveSystemMode))
  93. {
  94. // PSAPI.DLL API's ARE NOW PREFERRED!!
  95. // It doesn't tend to hang when enumerating modules for a process that is being debugged.
  96. // The Toolhelp32 APIs seem to hang occasionally taking a snapshot of a process being debugged
  97. // and this impacts Exception Monitor (which runs from a script against a process under
  98. // windbg)
  99. if ( g_lpProgramOptions->IsRunningWindowsNT() )
  100. {
  101. // Get the functions for Windows NT 4.0/2000
  102. // Load library and get the procedures explicitly. We do
  103. // this so that we don't have to worry about modules using
  104. // this code failing to load under Windows 95, because
  105. // it can't resolve references to the PSAPI.DLL.
  106. if (g_lpDelayLoad->Initialize_PSAPI())
  107. {
  108. m_enumProcessCollectionMethod = PSAPI_METHOD;
  109. } else
  110. {
  111. _tprintf(TEXT("Unable to load PSAPI.DLL, which may be required for enumeration of processes.\n"));
  112. }
  113. }
  114. if ( m_enumProcessCollectionMethod == NO_METHOD )
  115. {
  116. if (g_lpDelayLoad->Initialize_TOOLHELP32())
  117. {
  118. m_enumProcessCollectionMethod = TOOLHELP32_METHOD;
  119. } else
  120. {
  121. _tprintf(TEXT("KERNEL32.DLL is missing required function entry points!!\n"));
  122. }
  123. }
  124. // On Windows NT, we need to enable SeDebugPrivilege to open some processes...
  125. if ( ( m_enumProcessCollectionMethod != NO_METHOD ) &&
  126. g_lpProgramOptions->IsRunningWindowsNT() )
  127. {
  128. HANDLE hOurProcessToken = 0;
  129. bool fPrivilegeSet = false;
  130. // To permit as much access to obtain a process handle as possible,
  131. // we need to set the SeDebugPrivilege on our process handle, we can
  132. // then open nearly any process...
  133. if(OpenProcessToken( GetCurrentProcess(),
  134. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  135. &hOurProcessToken))
  136. {
  137. // We got our Process Token...
  138. if(SetPrivilege(hOurProcessToken, SE_DEBUG_NAME, TRUE))
  139. {
  140. fPrivilegeSet = true;
  141. }
  142. }
  143. if (!fPrivilegeSet)
  144. {
  145. _tprintf(TEXT("\nWARNING: A required privilege (SeDebugPrivilege) is not held by the user\n"));
  146. _tprintf(TEXT("running this program. Due to security, some processes running on this\n"));
  147. _tprintf(TEXT("system may not be accessible. An administrator of this machine can grant\n"));
  148. _tprintf(TEXT("you this privilege by using User Manager to enable the advanced User Right\n"));
  149. _tprintf(TEXT("\"Debug Programs\" to enable complete access to this system.\n"));
  150. }
  151. if (hOurProcessToken)
  152. CloseHandle(hOurProcessToken);
  153. }
  154. // We are initialized if we were able to enable a Process Collection Method
  155. m_fInitialized = ( m_enumProcessCollectionMethod != NO_METHOD );
  156. } else
  157. {
  158. m_fInitialized = true;
  159. }
  160. return m_fInitialized;
  161. }
  162. bool CProcesses::GetProcessesDataForRunningProcessesUsingPSAPI()
  163. {
  164. LPDWORD lpdwPIDs = NULL;
  165. DWORD dwProcessIDHeapSizeUsed, dwProcessIDHeapSize, dwIndex ;
  166. CProcessInfo * lpProcessInfo = NULL;
  167. bool fRetval = false;
  168. if (!m_fInitialized)
  169. return false;
  170. // It's possible the user provided a PID directly... if so,
  171. // we can circumvent the whole search of PIDs on the system...
  172. if (g_lpProgramOptions->GetProcessID())
  173. {
  174. // Okay, let's create a ProcessInfo object and pass this down to EnumerateModules()
  175. lpProcessInfo = new CProcessInfo();
  176. if (lpProcessInfo == NULL)
  177. goto error_cleanup;
  178. if (!lpProcessInfo->Initialize(m_lpModuleInfoCache, NULL, m_lpOutputFile, NULL))
  179. {
  180. goto error_cleanup;
  181. }
  182. if (lpProcessInfo->EnumerateModules(g_lpProgramOptions->GetProcessID(), this, NULL))
  183. {
  184. // Success... add this to the Processes Object...
  185. if (!AddNewProcessInfoObject(lpProcessInfo))
  186. { // Failure adding the node...
  187. goto error_cleanup; // For now, let's just error on out...
  188. }
  189. } else
  190. {
  191. // Failure enumerating modules on the only PID of interest... very bad...
  192. goto error_cleanup;
  193. }
  194. }
  195. else
  196. { // Nope, we brute force this baby...
  197. // Call the PSAPI function EnumProcesses to get all of the
  198. // ProcID's currently in the system.
  199. // NOTE: In the documentation, the third parameter of
  200. // EnumProcesses is named cbNeeded, which implies that you
  201. // can call the function once to find out how much space to
  202. // allocate for a buffer and again to fill the buffer.
  203. // This is not the case. The cbNeeded parameter returns
  204. // the number of PIDs returned, so if your buffer size is
  205. // zero cbNeeded returns zero.
  206. // NOTE: The loop here ensures that we
  207. // actually allocate a buffer large enough for all the
  208. // PIDs in the system.
  209. dwProcessIDHeapSize = 256 * sizeof( DWORD ) ;
  210. lpdwPIDs = NULL ;
  211. do
  212. {
  213. if( lpdwPIDs )
  214. { // Hmm.. we've been through this loop already, double the HeapSize and try again.
  215. delete [] lpdwPIDs;
  216. dwProcessIDHeapSize *= 2 ;
  217. }
  218. lpdwPIDs = (LPDWORD) new DWORD[dwProcessIDHeapSize];
  219. if( lpdwPIDs == NULL )
  220. {
  221. goto error_cleanup;
  222. }
  223. // Query the system for the total number of processes
  224. if( !g_lpDelayLoad->EnumProcesses( lpdwPIDs, dwProcessIDHeapSize, &dwProcessIDHeapSizeUsed ) )
  225. {
  226. // It's bad if we can't enum processes... no place to go but to bail out...
  227. goto error_cleanup;
  228. }
  229. } while( dwProcessIDHeapSizeUsed == dwProcessIDHeapSize );
  230. // How many ProcID's did we get?
  231. DWORD dwNumberOfPIDs = dwProcessIDHeapSizeUsed / sizeof( DWORD ) ;
  232. // Loop through each ProcID.
  233. for( dwIndex = 0 ; dwIndex < dwNumberOfPIDs; dwIndex++ )
  234. {
  235. // Okay, let's create a ProcessInfo object and pass this down to EnumerateModules()
  236. // Each Process gets its own
  237. lpProcessInfo = new CProcessInfo();
  238. if (lpProcessInfo == NULL)
  239. goto error_cleanup;
  240. if (!lpProcessInfo->Initialize(m_lpModuleInfoCache, NULL, m_lpOutputFile, NULL))
  241. { // Failure initializing the ProcessInfo object?!?
  242. delete lpProcessInfo;
  243. lpProcessInfo = NULL;
  244. continue;
  245. }
  246. if (lpProcessInfo->EnumerateModules(lpdwPIDs[dwIndex], this, NULL))
  247. {
  248. // Success... add this to the Processes Object...
  249. if (!AddNewProcessInfoObject(lpProcessInfo))
  250. { // Failure adding the node...
  251. delete lpProcessInfo;
  252. lpProcessInfo = NULL;
  253. continue;
  254. }
  255. // For now, let's error out...
  256. } else
  257. {
  258. // An error enumerating modules might be normal...
  259. delete lpProcessInfo;
  260. lpProcessInfo = NULL;
  261. continue;
  262. }
  263. }
  264. }
  265. fRetval = true;
  266. goto cleanup;
  267. error_cleanup:
  268. if (lpProcessInfo)
  269. delete lpProcessInfo;
  270. cleanup:
  271. if (lpdwPIDs)
  272. {
  273. delete [] lpdwPIDs;
  274. }
  275. return fRetval;
  276. }
  277. bool CProcesses::AddNewProcessInfoObject(CProcessInfo * lpProcessInfo)
  278. {
  279. if (!m_fInitialized)
  280. return false;
  281. // First, create a ProcessInfoNode object and then attach it to the bottom of the
  282. // linked list of nodes...
  283. CProcessInfoNode * lpProcessInfoNode = new CProcessInfoNode(lpProcessInfo);
  284. /*
  285. #ifdef _DEBUG
  286. _tprintf(TEXT("Adding Process Info Object for [%s]\n"), lpProcessInfo->m_tszProcessName);
  287. #endif
  288. */
  289. if (lpProcessInfoNode == NULL)
  290. return false; // Couldn't allocate memory..
  291. // Acquire Mutex object to protect the linked-list...
  292. WaitForSingleObject(m_ProcessInfoHeadMutex, INFINITE);
  293. CProcessInfoNode * lpProcessInfoNodePointer = m_lpProcessInfoHead;
  294. if (lpProcessInfoNodePointer) {
  295. // Traverse the linked list to the end..
  296. while (lpProcessInfoNodePointer->m_lpNextProcessInfoNode)
  297. { // Keep looking for the end...
  298. lpProcessInfoNodePointer = lpProcessInfoNodePointer->m_lpNextProcessInfoNode;
  299. }
  300. lpProcessInfoNodePointer->m_lpNextProcessInfoNode = lpProcessInfoNode;
  301. }
  302. else
  303. { // First time through, the Process Info Head pointer is null...
  304. m_lpProcessInfoHead = lpProcessInfoNode;
  305. }
  306. // Be a good citizen and release the Mutex
  307. ReleaseMutex(m_ProcessInfoHeadMutex);
  308. InterlockedIncrement(&m_iNumberOfProcesses);
  309. return true;
  310. }
  311. bool CProcesses::SetPrivilege(HANDLE hToken, LPCTSTR Privilege, bool bEnablePrivilege)
  312. {
  313. TOKEN_PRIVILEGES tp;
  314. LUID luid;
  315. TOKEN_PRIVILEGES tpPrevious = {0};
  316. DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
  317. if(!LookupPrivilegeValue( NULL, Privilege, &luid )) return false;
  318. //
  319. // first pass. get current privilege setting
  320. //
  321. tp.PrivilegeCount = 1;
  322. tp.Privileges[0].Luid = luid;
  323. tp.Privileges[0].Attributes = 0;
  324. AdjustTokenPrivileges(
  325. hToken,
  326. FALSE,
  327. &tp,
  328. sizeof(TOKEN_PRIVILEGES),
  329. &tpPrevious,
  330. &cbPrevious
  331. );
  332. if (GetLastError() != ERROR_SUCCESS) return false;
  333. //
  334. // second pass. set privilege based on previous setting
  335. //
  336. tpPrevious.PrivilegeCount = 1;
  337. tpPrevious.Privileges[0].Luid = luid;
  338. if(bEnablePrivilege) {
  339. tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
  340. }
  341. else {
  342. tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
  343. tpPrevious.Privileges[0].Attributes);
  344. }
  345. AdjustTokenPrivileges(
  346. hToken,
  347. FALSE,
  348. &tpPrevious,
  349. cbPrevious,
  350. NULL,
  351. NULL
  352. );
  353. if (GetLastError() != ERROR_SUCCESS) return false;
  354. return true;
  355. }
  356. bool CProcesses::OutputProcessesData(CollectionTypes enumCollectionType, bool fCSVFileContext, bool fDumpHeader)
  357. {
  358. // Output to file?
  359. if ( !g_lpProgramOptions->GetMode(CProgramOptions::QuietMode) &&
  360. !g_lpProgramOptions->GetMode(CProgramOptions::PrintTaskListMode) )
  361. {
  362. // Output to Stdout?
  363. if (!OutputProcessesDataToStdout(enumCollectionType, fCSVFileContext, fDumpHeader))
  364. return false;
  365. }
  366. // Output to file?
  367. if (g_lpProgramOptions->GetMode(CProgramOptions::OutputCSVFileMode))
  368. {
  369. // Try and output to file...
  370. if (!OutputProcessesDataToFile(enumCollectionType, fDumpHeader))
  371. return false;
  372. }
  373. if (m_lpProcessInfoHead) {
  374. CProcessInfoNode * lpCurrentProcessInfoNode = m_lpProcessInfoHead;
  375. while (lpCurrentProcessInfoNode)
  376. {
  377. // We have a node... print out Process Info for it, then the Modules Data...
  378. if (lpCurrentProcessInfoNode->m_lpProcessInfo)
  379. {
  380. lpCurrentProcessInfoNode->m_lpProcessInfo->OutputProcessData(enumCollectionType, fCSVFileContext, false);
  381. }
  382. lpCurrentProcessInfoNode = lpCurrentProcessInfoNode->m_lpNextProcessInfoNode;
  383. }
  384. }
  385. return true;
  386. }
  387. bool CProcesses::OutputProcessesDataToStdout(CollectionTypes enumCollectionType, bool fCSVFileContext, bool fDumpHeader)
  388. {
  389. if (fDumpHeader)
  390. {
  391. // Output to stdout...
  392. _tprintf(TEXT("\n"));
  393. CUtilityFunctions::OutputLineOfStars();
  394. _tprintf(TEXT("%s - Printing Process Information for %d Processes.\n"), g_tszCollectionArray[enumCollectionType].tszCSVLabel, m_iNumberOfProcesses);
  395. _tprintf(TEXT("%s - Context: %s\n"), g_tszCollectionArray[enumCollectionType].tszCSVLabel, fCSVFileContext ? g_tszCollectionArray[enumCollectionType].tszCSVContext : g_tszCollectionArray[enumCollectionType].tszLocalContext);
  396. CUtilityFunctions::OutputLineOfStars();
  397. }
  398. return true;
  399. }
  400. bool CProcesses::OutputProcessesDataToFile(CollectionTypes enumCollectionType, bool fDumpHeader)
  401. {
  402. // Don't write anything if there are no processes to report...
  403. if (0 == m_iNumberOfProcesses)
  404. return true;
  405. if (fDumpHeader)
  406. {
  407. // We skip output of the [PROCESSES] header if -E was specified...
  408. if (!g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode))
  409. {
  410. // Write out the Processes tag so I can detect this output format...
  411. if (!m_lpOutputFile->WriteString(TEXT("\r\n")) ||
  412. !m_lpOutputFile->WriteString(g_tszCollectionArray[enumCollectionType].tszCSVLabel) ||
  413. !m_lpOutputFile->WriteString(TEXT("\r\n"))
  414. )
  415. {
  416. _tprintf(TEXT("Failure writing CSV header to file [%s]!"), m_lpOutputFile->GetFilePath());
  417. m_lpOutputFile->PrintLastError();
  418. return false;
  419. }
  420. }
  421. // We have different output for -E
  422. if (g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode))
  423. {
  424. // Write out the header... for the -E option...
  425. if (!m_lpOutputFile->WriteString(TEXT("Module Path,Symbol Status,Time/Date String,File Version,Company Name,File Description,File Time/Date String,Local DBG Status,Local DBG,Local PDB Status,Local PDB\r\n")))
  426. {
  427. _tprintf(TEXT("Failure writing CSV header to file [%s]!"), m_lpOutputFile->GetFilePath());
  428. m_lpOutputFile->PrintLastError();
  429. return false;
  430. }
  431. } else
  432. {
  433. // Write out the Processes Header
  434. if (!m_lpOutputFile->WriteString(g_tszCollectionArray[enumCollectionType].tszCSVColumnHeaders))
  435. {
  436. _tprintf(TEXT("Failure writing CSV header to file [%s]!"), m_lpOutputFile->GetFilePath());
  437. m_lpOutputFile->PrintLastError();
  438. return false;
  439. }
  440. }
  441. }
  442. return true;
  443. }
  444. bool CProcesses::GetProcessesData()
  445. {
  446. // Is this being collected interactively?
  447. if (g_lpProgramOptions->GetMode(CProgramOptions::InputProcessesFromLiveSystemMode))
  448. {
  449. // Invoke the correct Process Collection Method
  450. if (GetProcessCollectionMethod() == TOOLHELP32_METHOD)
  451. {
  452. GetProcessesDataForRunningProcessesUsingTOOLHELP32();
  453. }
  454. else if (GetProcessCollectionMethod() == PSAPI_METHOD)
  455. {
  456. GetProcessesDataForRunningProcessesUsingPSAPI();
  457. }
  458. }
  459. // Is this being collected from a file?
  460. if (g_lpProgramOptions->GetMode(CProgramOptions::InputCSVFileMode))
  461. GetProcessesDataFromFile();
  462. return true;
  463. }
  464. bool CProcesses::GetProcessesDataFromFile()
  465. {
  466. CProcessInfo * lpProcessInfo = NULL;
  467. char szProcessNameToMatch[_MAX_FNAME+1];
  468. // In case we're matching against these...
  469. LPTSTR tszProcessNameToMatch = g_lpProgramOptions->GetProcessName();
  470. DWORD dwProcessIDToMatch = g_lpProgramOptions->GetProcessID();
  471. // If we're going to be matching on a process name, go ahead and grab it
  472. // once now, convert to ANSI if necessary (since it comes from the CSV
  473. // file in ANSI), and upper case it...
  474. if ( ( g_lpProgramOptions->GetMode(CProgramOptions::InputProcessesWithMatchingNameOrPID) ) &&
  475. ( tszProcessNameToMatch )
  476. )
  477. {
  478. // Let's save away the Process Name...
  479. CUtilityFunctions::CopyTSTRStringToAnsi(tszProcessNameToMatch, szProcessNameToMatch, _MAX_FNAME+1);
  480. // Upper case the process name... we should be ready to match on this now...
  481. _strupr(szProcessNameToMatch);
  482. }
  483. // Read the Process Header Line
  484. if (!m_lpInputFile->ReadFileLine())
  485. return false;
  486. // Currently, we don't actually read the data...
  487. enum { BUFFER_SIZE = 128};
  488. char szProcessName[BUFFER_SIZE];
  489. TCHAR tszProcessName[BUFFER_SIZE];
  490. DWORD iProcessID;
  491. // Read the first field (should be blank, unless this is a new collection type
  492. if (m_lpInputFile->ReadString())
  493. return true;
  494. bool fReturn = true;
  495. while (fReturn == true)
  496. {
  497. // Read the process name...
  498. if (0 == m_lpInputFile->ReadString(szProcessName, BUFFER_SIZE))
  499. break;
  500. if (!m_lpInputFile->ReadDWORD(&iProcessID))
  501. {
  502. fReturn = false;
  503. break;
  504. }
  505. if ( g_lpProgramOptions->GetMode(CProgramOptions::InputProcessesWithMatchingNameOrPID) )
  506. {
  507. // Okay, the user has provided us something to match against our data...
  508. if ( tszProcessNameToMatch )
  509. {
  510. // Process name provided... does it match?
  511. if ( strcmp(szProcessNameToMatch, szProcessName) )
  512. {
  513. // Nope... well then, we should nuke this line...
  514. m_lpInputFile->ReadFileLine();
  515. // Then, jump to the next line processing...
  516. goto ReadNewLine;
  517. }
  518. #ifdef _DEBUG
  519. else
  520. {
  521. printf("DEBUG: MATCH FOUND ON Process Name [%s]\n", szProcessName);
  522. }
  523. #endif
  524. } else
  525. {
  526. if ( dwProcessIDToMatch != iProcessID )
  527. {
  528. // Nope... well then, we should nuke this line...
  529. m_lpInputFile->ReadFileLine();
  530. // Then, jump to the next line processing...
  531. goto ReadNewLine;
  532. }
  533. #ifdef _DEBUG
  534. else
  535. {
  536. _tprintf(TEXT("DEBUG: MATCH FOUND ON Process ID [%d]\n"), iProcessID);
  537. }
  538. #endif
  539. }
  540. }
  541. // Okay, let's create a ProcessInfo object and pass this down to EnumerateModules()
  542. // Each Process gets its own
  543. lpProcessInfo = new CProcessInfo();
  544. if (lpProcessInfo == NULL)
  545. {
  546. fReturn = false;
  547. break;
  548. }
  549. if (!lpProcessInfo->Initialize(m_lpModuleInfoCache, m_lpInputFile, m_lpOutputFile, NULL))
  550. { // Failure initializing the ProcessInfo object?!?
  551. delete lpProcessInfo;
  552. lpProcessInfo = NULL;
  553. fReturn = false;
  554. break;
  555. }
  556. // We need to convert this to Unicode possibly... (it will be copied in EnumModules())
  557. CUtilityFunctions::CopyAnsiStringToTSTR(szProcessName, tszProcessName, BUFFER_SIZE);
  558. // Save the process name...
  559. lpProcessInfo->SetProcessName(tszProcessName);
  560. // Enumerate the modules for the process
  561. if (!lpProcessInfo->EnumerateModules(iProcessID, this, tszProcessName))
  562. {
  563. fReturn = false;
  564. break;
  565. }
  566. // Success... add this to the Processes Object...
  567. if (!AddNewProcessInfoObject(lpProcessInfo))
  568. { // Failure adding the node...
  569. delete lpProcessInfo;
  570. lpProcessInfo = NULL;
  571. return false;
  572. }
  573. ReadNewLine:
  574. // Before we read a new line... are we already pointing to the end?
  575. if (m_lpInputFile->EndOfFile())
  576. {
  577. break;
  578. }
  579. // Read the first field (should be blank, unless this is a new collection type
  580. if (m_lpInputFile->ReadString())
  581. break;
  582. }
  583. // We don't expect to find anything...
  584. return fReturn;
  585. }
  586. CProcesses::ProcessCollectionMethod CProcesses::GetProcessCollectionMethod()
  587. {
  588. return m_enumProcessCollectionMethod;
  589. }
  590. bool CProcesses::GetProcessesDataForRunningProcessesUsingTOOLHELP32()
  591. {
  592. CProcessInfo * lpProcessInfo = NULL;
  593. HANDLE hSnapShot = NULL;
  594. bool fReturn = false;
  595. if (!m_fInitialized)
  596. return false;
  597. // It's possible the user provided a PID directly... if so,
  598. // we can circumvent the whole search of PIDs on the system...
  599. if (g_lpProgramOptions->GetProcessID())
  600. {
  601. // Okay, let's create a ProcessInfo object and pass this down to EnumerateModules()
  602. lpProcessInfo = new CProcessInfo();
  603. if (lpProcessInfo == NULL)
  604. goto error_cleanup;
  605. if (!lpProcessInfo->Initialize(m_lpModuleInfoCache, NULL, m_lpOutputFile, NULL))
  606. {
  607. goto error_cleanup;
  608. }
  609. if (lpProcessInfo->EnumerateModules(g_lpProgramOptions->GetProcessID(), this, NULL))
  610. {
  611. // Success... add this to the Processes Object...
  612. if (!AddNewProcessInfoObject(lpProcessInfo))
  613. { // Failure adding the node...
  614. goto error_cleanup; // For now, let's just error on out...
  615. }
  616. } else
  617. {
  618. // Failure enumerating modules on the only PID of interest... very bad...
  619. goto error_cleanup;
  620. }
  621. }
  622. else
  623. {
  624. PROCESSENTRY32 procentry;
  625. BOOL bFlag;
  626. // Get a handle to a Toolhelp snapshot of the systems processes.
  627. hSnapShot = g_lpDelayLoad->CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  628. if( hSnapShot == INVALID_HANDLE_VALUE )
  629. {
  630. goto error_cleanup ;
  631. }
  632. // Clear this structure
  633. memset(&procentry, 0, sizeof(procentry));
  634. // Get the first process' information.
  635. procentry.dwSize = sizeof(PROCESSENTRY32) ;
  636. bFlag = g_lpDelayLoad->Process32First( hSnapShot, &procentry ) ;
  637. // While there are processes, keep looping.
  638. while( bFlag )
  639. {
  640. // Okay, let's create a ProcessInfo object and pass this down to EnumerateModules()
  641. // Each Process gets its own
  642. lpProcessInfo = new CProcessInfo();
  643. if (lpProcessInfo == NULL)
  644. goto error_cleanup;
  645. if (!lpProcessInfo->Initialize(m_lpModuleInfoCache, NULL, m_lpOutputFile, NULL))
  646. {
  647. // Failure initializing the ProcessInfo object?!?
  648. delete lpProcessInfo;
  649. lpProcessInfo = NULL;
  650. // Clear this structure
  651. memset(&procentry, 0, sizeof(procentry));
  652. // Get the next Process...
  653. procentry.dwSize = sizeof(PROCESSENTRY32) ;
  654. bFlag = g_lpDelayLoad->Process32Next( hSnapShot, &procentry );
  655. continue;
  656. }
  657. // Enumerate the modules for this process...
  658. if (lpProcessInfo->EnumerateModules(procentry.th32ProcessID, this, procentry.szExeFile))
  659. {
  660. // Success... add this to the Processes Object...
  661. if (!AddNewProcessInfoObject(lpProcessInfo))
  662. {
  663. // Failure adding the node...
  664. delete lpProcessInfo;
  665. lpProcessInfo = NULL;
  666. }
  667. } else
  668. {
  669. // An error enumerating modules might be normal...
  670. delete lpProcessInfo;
  671. lpProcessInfo = NULL;
  672. }
  673. // Get the next Process...
  674. procentry.dwSize = sizeof(PROCESSENTRY32) ;
  675. bFlag = g_lpDelayLoad->Process32Next( hSnapShot, &procentry );
  676. }
  677. }
  678. fReturn = true;
  679. goto cleanup;
  680. error_cleanup:
  681. if (lpProcessInfo)
  682. delete lpProcessInfo;
  683. cleanup:
  684. if (hSnapShot != INVALID_HANDLE_VALUE)
  685. CloseHandle(hSnapShot);
  686. return fReturn;
  687. }