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.

898 lines
25 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 2000
  6. //
  7. // File: processinfo.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // ProcessInfo.cpp: implementation of the CProcessInfo 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 <TIME.H>
  22. #include "Globals.h"
  23. #include "ProcessInfo.h"
  24. #include "ProcessInfoNode.h"
  25. #include "ProgramOptions.h"
  26. #include "Processes.h"
  27. #include "ModuleInfo.h"
  28. #include "ModuleInfoNode.h"
  29. #include "ModuleInfoCache.h"
  30. #include "FileData.h"
  31. #include "UtilityFunctions.h"
  32. #include "DmpFile.h"
  33. //////////////////////////////////////////////////////////////////////
  34. // Construction/Destruction
  35. //////////////////////////////////////////////////////////////////////
  36. CProcessInfo::CProcessInfo()
  37. {
  38. m_fInitialized = false;
  39. m_tszProcessName= NULL;
  40. m_iProcessID = 0;
  41. m_lpModuleInfoHead = NULL;
  42. m_hModuleInfoHeadMutex = NULL;
  43. m_iNumberOfModules = 0;
  44. m_lpInputFile = NULL;
  45. m_lpOutputFile = NULL;
  46. m_lpModuleInfoCache = NULL;
  47. m_hModuleInfoHeadMutex = NULL;
  48. m_lpDmpFile = NULL;
  49. }
  50. CProcessInfo::~CProcessInfo()
  51. {
  52. if (m_tszProcessName)
  53. delete [] m_tszProcessName;
  54. WaitForSingleObject(m_hModuleInfoHeadMutex, INFINITE);
  55. // If we have Module Info Objects... nuke them now...
  56. if (m_lpModuleInfoHead)
  57. {
  58. CModuleInfoNode * lpModuleInfoNodePointer = m_lpModuleInfoHead;
  59. CModuleInfoNode * lpModuleInfoNodePointerToDelete = m_lpModuleInfoHead;
  60. // Traverse the linked list to the end..
  61. while (lpModuleInfoNodePointer)
  62. { // Keep looking for the end...
  63. // Advance our pointer to the next node...
  64. lpModuleInfoNodePointer = lpModuleInfoNodePointer->m_lpNextModuleInfoNode;
  65. // Delete the one behind us...
  66. delete lpModuleInfoNodePointerToDelete;
  67. // Set the node to delete to the current...
  68. lpModuleInfoNodePointerToDelete = lpModuleInfoNodePointer;
  69. }
  70. // Now, clear out the Head pointer...
  71. m_lpModuleInfoHead = NULL;
  72. }
  73. // Be a good citizen and release the Mutex
  74. ReleaseMutex(m_hModuleInfoHeadMutex);
  75. // Now, close the Mutex
  76. if (m_hModuleInfoHeadMutex)
  77. {
  78. CloseHandle(m_hModuleInfoHeadMutex);
  79. m_hModuleInfoHeadMutex = NULL;
  80. }
  81. }
  82. //bool CProcessInfo::Initialize(CProgramOptions *lpProgramOptions, CModuleInfoCache * lpModuleInfoCache, CFileData * lpInputFile, CFileData * lpOutputFile)
  83. bool CProcessInfo::Initialize(CModuleInfoCache * lpModuleInfoCache, CFileData * lpInputFile, CFileData * lpOutputFile, CDmpFile * lpDmpFile)
  84. {
  85. if (lpModuleInfoCache == NULL)
  86. return false;
  87. // Let's save off big objects so we don't have to keep passing this to
  88. // our methods...
  89. m_lpInputFile = lpInputFile;
  90. m_lpOutputFile = lpOutputFile;
  91. m_lpModuleInfoCache = lpModuleInfoCache;
  92. m_lpDmpFile = lpDmpFile;
  93. m_hModuleInfoHeadMutex = CreateMutex(NULL, FALSE, NULL);
  94. if (m_hModuleInfoHeadMutex == NULL)
  95. return false;
  96. m_fInitialized = true;
  97. return true;
  98. }
  99. bool CProcessInfo::EnumerateModules(DWORD iProcessID, CProcesses * lpProcesses, LPTSTR tszProcessName)
  100. {
  101. bool fReturn = true;
  102. // Is this being collected interactively?
  103. if (g_lpProgramOptions->GetMode(CProgramOptions::InputProcessesFromLiveSystemMode))
  104. {
  105. // Invoke the correct Process Collection Method
  106. if (lpProcesses->GetProcessCollectionMethod() == CProcesses::TOOLHELP32_METHOD)
  107. {
  108. fReturn = EnumerateModulesForRunningProcessUsingTOOLHELP32(iProcessID, tszProcessName);
  109. }
  110. else if (lpProcesses->GetProcessCollectionMethod() == CProcesses::PSAPI_METHOD)
  111. {
  112. fReturn = EnumerateModulesForRunningProcessUsingPSAPI(iProcessID);
  113. }
  114. }
  115. // Is this being collected from a file?
  116. if (g_lpProgramOptions->GetMode(CProgramOptions::InputCSVFileMode))
  117. {
  118. fReturn = EnumerateModulesFromFile(iProcessID, tszProcessName);
  119. }
  120. return fReturn;
  121. }
  122. bool CProcessInfo::fModuleNameMatches(LPTSTR tszProcessName, LPTSTR tszModulePath)
  123. {
  124. if (!tszProcessName || !tszModulePath)
  125. return false;
  126. TCHAR fname1[_MAX_FNAME], fname2[_MAX_FNAME];
  127. TCHAR ext1[_MAX_EXT], ext2[_MAX_EXT];
  128. _tsplitpath( tszProcessName, NULL, NULL, fname1, ext1 );
  129. _tsplitpath( tszModulePath, NULL, NULL, fname2, ext2 );
  130. if (!ext1 && _tcsicmp(ext1, ext2))
  131. return false; // Extensions must match (if provided on process name)
  132. if (_tcsicmp(fname1, fname2))
  133. return false; // Filename must match
  134. // Do we care about a full path? If so, we can add in drive and dir vars...
  135. return true;
  136. }
  137. //
  138. // This function takes a provided tszFileName, and looks to see if it has an
  139. // extension of EXE. If it does, it's saved off...
  140. bool CProcessInfo::fIsProcessName(LPTSTR tszFileName)
  141. {
  142. if (!tszFileName)
  143. return false;
  144. TCHAR fname[_MAX_FNAME];
  145. TCHAR ext[_MAX_EXT];
  146. _tsplitpath( tszFileName, NULL, NULL, fname, ext );
  147. if (!ext || _tcsicmp(ext, TEXT(".EXE")))
  148. return false; // Extensions must match (if provided on process name)
  149. // Let's save off the process name...
  150. m_tszProcessName = new TCHAR[_tcsclen(fname)+_tcsclen(ext)+1];
  151. if (m_tszProcessName == NULL)
  152. return false;
  153. _stprintf(m_tszProcessName, TEXT("%s%s"), _tcsupr(fname), _tcsupr(ext));
  154. // Yup! It's the Process Name...
  155. return true;
  156. }
  157. bool CProcessInfo::AddNewModuleInfoObject(CModuleInfo *lpModuleInfo)
  158. {
  159. if (!m_fInitialized)
  160. return false;
  161. // First, create a ModuleInfoNode object and then attach it to the bottom of the
  162. // linked list of nodes...
  163. CModuleInfoNode * lpModuleInfoNode = new CModuleInfoNode(lpModuleInfo);
  164. if (lpModuleInfoNode == NULL)
  165. return false; // Couldn't allocate memory..
  166. // Acquire Mutex object to protect the linked-list...
  167. WaitForSingleObject(m_hModuleInfoHeadMutex, INFINITE);
  168. CModuleInfoNode * lpModuleInfoNodePointer = m_lpModuleInfoHead;
  169. if (lpModuleInfoNodePointer) {
  170. // Traverse the linked list to the end..
  171. while (lpModuleInfoNodePointer->m_lpNextModuleInfoNode)
  172. { // Keep looking for the end...
  173. lpModuleInfoNodePointer = lpModuleInfoNodePointer->m_lpNextModuleInfoNode;
  174. }
  175. lpModuleInfoNodePointer->m_lpNextModuleInfoNode = lpModuleInfoNode;
  176. }
  177. else
  178. { // First time through, the Process Info Head pointer is null...
  179. m_lpModuleInfoHead = lpModuleInfoNode;
  180. }
  181. // Be a good citizen and release the Mutex
  182. ReleaseMutex(m_hModuleInfoHeadMutex);
  183. InterlockedIncrement(&m_iNumberOfModules);
  184. return true;
  185. }
  186. bool CProcessInfo::OutputProcessData(CollectionTypes enumCollectionType, bool fCSVFileContext, bool fDumpHeader)
  187. {
  188. if (g_lpProgramOptions->GetMode(CProgramOptions::PrintTaskListMode))
  189. {
  190. if ( g_lpProgramOptions->IsRunningWindowsNT() )
  191. {
  192. // Provide TLIST like output (though no window text info)
  193. _tprintf(TEXT("%4d %s\n"), m_iProcessID, m_tszProcessName);
  194. } else
  195. {
  196. // Provide TLIST like output (though no window text info)
  197. _tprintf(TEXT("%9d %s\n"), m_iProcessID, m_tszProcessName);
  198. }
  199. return true;
  200. }
  201. // Output to STDOUT?
  202. if ( !g_lpProgramOptions->GetMode(CProgramOptions::QuietMode) )
  203. {
  204. // Output to Stdout?
  205. if (!OutputProcessDataToStdout(enumCollectionType, fCSVFileContext, fDumpHeader))
  206. return false;
  207. }
  208. if (!g_lpProgramOptions->GetMode(CProgramOptions::QuietMode))
  209. {
  210. CUtilityFunctions::OutputLineOfDashes();
  211. // Output to STDOUT
  212. _tprintf(TEXT("\nProcess Name [%s] - PID=%d (0x%x) - "), m_tszProcessName, m_iProcessID, m_iProcessID);
  213. }
  214. // Output to file?
  215. if (g_lpProgramOptions->GetMode(CProgramOptions::OutputCSVFileMode))
  216. {
  217. // Try and output to file...
  218. if (!OutputProcessDataToFile(enumCollectionType, fDumpHeader))
  219. return false;
  220. }
  221. if (m_lpModuleInfoHead) {
  222. if (!g_lpProgramOptions->GetMode(CProgramOptions::QuietMode))
  223. {
  224. _tprintf(TEXT("%d modules recorded\n\n"), m_iNumberOfModules);
  225. CUtilityFunctions::OutputLineOfDashes();
  226. _tprintf(TEXT("\n"));
  227. }
  228. CModuleInfoNode * lpCurrentModuleInfoNode = m_lpModuleInfoHead;
  229. unsigned int dwModuleNumber = 1;
  230. while (lpCurrentModuleInfoNode)
  231. {
  232. // We have a node... print out Module Info for it...
  233. if (lpCurrentModuleInfoNode->m_lpModuleInfo)
  234. {
  235. lpCurrentModuleInfoNode->m_lpModuleInfo->OutputData(m_tszProcessName, m_iProcessID, dwModuleNumber);
  236. dwModuleNumber++;
  237. }
  238. lpCurrentModuleInfoNode = lpCurrentModuleInfoNode->m_lpNextModuleInfoNode;
  239. }
  240. }
  241. else
  242. {
  243. if (!g_lpProgramOptions->GetMode(CProgramOptions::QuietMode) && fDumpHeader)
  244. {
  245. _tprintf(TEXT("no recorded modules\n\n"));
  246. CUtilityFunctions::OutputLineOfDashes();
  247. _tprintf(TEXT("\n"));
  248. }
  249. }
  250. return true;
  251. }
  252. //bool CProcessInfo::OutputProcessDataToStdout(LPCTSTR tszOutputContext, bool fDumpHeader)
  253. bool CProcessInfo::OutputProcessDataToStdout(CollectionTypes enumCollectionType, bool fCSVFileContext, bool fDumpHeader)
  254. {
  255. if (fDumpHeader)
  256. {
  257. CUtilityFunctions::OutputLineOfStars();
  258. _tprintf(TEXT("%s - Printing Process Information for 1 Process.\n"), g_tszCollectionArray[enumCollectionType].tszCSVLabel);
  259. _tprintf(TEXT("%s - Context: %s\n"), g_tszCollectionArray[enumCollectionType].tszCSVLabel, fCSVFileContext ? g_tszCollectionArray[enumCollectionType].tszCSVContext : g_tszCollectionArray[enumCollectionType].tszLocalContext);
  260. CUtilityFunctions::OutputLineOfStars();
  261. }
  262. return true;
  263. }
  264. bool CProcessInfo::OutputProcessDataToFile(CollectionTypes enumCollectionType, bool fDumpHeader)
  265. {
  266. // We skip output of the [processes ]header if -E was specified...
  267. if (!g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode) && fDumpHeader)
  268. {
  269. // Write out the Process tag so I can detect this output format...
  270. if (!m_lpOutputFile->WriteString(TEXT("\r\n")) ||
  271. !m_lpOutputFile->WriteString(g_tszCollectionArray[enumCollectionType].tszCSVLabel) ||
  272. !m_lpOutputFile->WriteString(TEXT("\r\n"))
  273. )
  274. {
  275. _tprintf(TEXT("Failure writing CSV header to file [%s]!"), m_lpOutputFile->GetFilePath());
  276. m_lpOutputFile->PrintLastError();
  277. return false;
  278. }
  279. }
  280. // We skip output of the [processes ]header if -E was specified...
  281. if (g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode) && fDumpHeader)
  282. {
  283. // Write out the header... for the -E option...
  284. 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")))
  285. {
  286. _tprintf(TEXT("Failure writing CSV header to file [%s]!"), m_lpOutputFile->GetFilePath());
  287. m_lpOutputFile->PrintLastError();
  288. return false;
  289. }
  290. } else
  291. {
  292. if (fDumpHeader)
  293. {
  294. // Write out the Process Header
  295. if (!m_lpOutputFile->WriteString(g_tszCollectionArray[enumCollectionType].tszCSVColumnHeaders))
  296. {
  297. _tprintf(TEXT("Failure writing CSV header to file [%s]!"), m_lpOutputFile->GetFilePath());
  298. m_lpOutputFile->PrintLastError();
  299. return false;
  300. }
  301. }
  302. }
  303. return true;
  304. }
  305. bool CProcessInfo::EnumerateModulesForRunningProcessUsingPSAPI(DWORD iProcessID)
  306. {
  307. HMODULE hMod[1024] ;
  308. HANDLE hProcess = NULL;
  309. TCHAR tszFileName[_MAX_PATH] ;
  310. DWORD cbNeeded;
  311. bool fReturn = true; // Optimisim ;)
  312. tszFileName[0] = 0 ;
  313. CModuleInfo * lpModuleInfo = NULL;
  314. // Open the process (if we can... security does not
  315. // permit every process in the system).
  316. if (iProcessID)
  317. {
  318. // Only try to open a Process ID if it's not 0
  319. hProcess = OpenProcess(
  320. PROCESS_QUERY_INFORMATION| PROCESS_VM_READ,
  321. FALSE,
  322. iProcessID ) ;
  323. }
  324. if( hProcess != NULL )
  325. {
  326. // Save off our PID (in case we need it later?)
  327. m_iProcessID = iProcessID;
  328. // Now, get a handle to each of the modules
  329. // in our target process...
  330. // Here we call EnumProcessModules to get only the
  331. // first module in the process this is important,
  332. // because this will be the .EXE module for which we
  333. // will retrieve the full path name in a second.
  334. if( g_lpDelayLoad->EnumProcessModules( hProcess, hMod, sizeof( hMod ), &cbNeeded ) )
  335. {
  336. int iNumberOfModules = cbNeeded / sizeof(HMODULE);
  337. bool fProcessNameFound = false;
  338. bool fNew = false;
  339. for(int i=0; i<iNumberOfModules; i++)
  340. {
  341. // Get Full pathname!
  342. if( !g_lpDelayLoad->GetModuleFileNameEx( hProcess, hMod[i], tszFileName, sizeof( tszFileName ) ) )
  343. {
  344. tszFileName[0] = 0 ;
  345. } else {
  346. CUtilityFunctions::UnMungePathIfNecessary(tszFileName);
  347. // We need a full path to the module to do anything useful with it...
  348. // At this point, let's ... party...
  349. if (!fProcessNameFound)
  350. fProcessNameFound = fIsProcessName(tszFileName);
  351. // First, if we were provided a Process name on the commandline, we
  352. // need to look for a match on the 1st module...
  353. if (i == 0 && g_lpProgramOptions->GetProcessName())
  354. {
  355. if (!fModuleNameMatches(g_lpProgramOptions->GetProcessName(), tszFileName))
  356. {
  357. // Bail if this is not a match, and we requested one...
  358. fReturn = false;
  359. goto cleanup;
  360. }
  361. }
  362. // Are we ONLY interested in the process list?
  363. if (g_lpProgramOptions->GetMode(CProgramOptions::PrintTaskListMode))
  364. {
  365. // All we want is process name.. bail before collecting module info...
  366. fReturn = true;
  367. goto cleanup;
  368. }
  369. // If "-MATCH" was specified, look to see if this filename meets our criteria
  370. // before we save this away in our module cache...
  371. if (!g_lpProgramOptions->fDoesModuleMatchOurSearch(tszFileName))
  372. continue;
  373. // Okay, let's go ahead and get a ModuleInfo Object from our cache...
  374. // If pfNew returns TRUE, then this object is new and we'll need
  375. // to populate it with data...
  376. lpModuleInfo = m_lpModuleInfoCache->AddNewModuleInfoObject(tszFileName, &fNew);
  377. if (false == fNew)
  378. {
  379. // We may have the object in the cache... now we need to
  380. // save a pointer to this object in our Process Info list
  381. AddNewModuleInfoObject(lpModuleInfo); // Just do our best...
  382. continue; // We save having to get the module info again for this module...
  383. }
  384. // Not in the cache... so we need to init it, and get the module info...
  385. // Okay, let's create a ModuleInfo object and pass this down
  386. // routines that will populate it full of data...
  387. if (!lpModuleInfo->Initialize(NULL, m_lpOutputFile, NULL))
  388. {
  389. continue; // Hmmm... memory error?
  390. }
  391. // Let's do it!! Populate the ModuleInfo object with data!!!!
  392. if (!lpModuleInfo->GetModuleInfo(tszFileName))
  393. {
  394. // Well, for now we've at least got the path to the module...
  395. // Go ahead and get another module..
  396. continue;
  397. }
  398. // Start obtaining information about the modules...
  399. // We may have the object in the cache... now we need to
  400. // save a pointer to this object in our Process Info list
  401. if (!AddNewModuleInfoObject(lpModuleInfo))
  402. { // Failure adding the node.... This is pretty serious...
  403. continue;
  404. }
  405. }
  406. }
  407. fReturn = true; // Looks good...
  408. }
  409. else
  410. {
  411. fReturn = false;
  412. if (!g_lpProgramOptions->GetProcessName())
  413. {
  414. // Let's not be so hasty... we couldn't enum modules, but to be friendly we can probably put a name
  415. // to the Process (based on the Process ID)...
  416. //
  417. // This Process ID tends to be "System"
  418. //
  419. // On Windows 2000, the Process ID tends to be 8
  420. //
  421. // On Windows NT 4.0, this Process ID tends to be 2
  422. switch (m_iProcessID)
  423. {
  424. case 2:
  425. case 8:
  426. SetProcessName(TEXT("SYSTEM"));
  427. fReturn = true;
  428. break;
  429. default:
  430. // Couldn't enumerate modules...
  431. fReturn = false;
  432. }
  433. }
  434. }
  435. cleanup:
  436. CloseHandle( hProcess ) ;
  437. } else
  438. { // Gotta be able to open the process to look at it...
  439. fReturn = false;
  440. if (!g_lpProgramOptions->GetProcessName())
  441. {
  442. // Let's not be so hasty... we couldn't enum modules, but to be friendly we can probably put a name
  443. // to the Process (based on the Process ID)...
  444. //
  445. // On Windows 2000, the only Process ID we can't open at all tends to be the "System Idle Process"
  446. switch (m_iProcessID)
  447. {
  448. case 0:
  449. SetProcessName(TEXT("[SYSTEM PROCESS]"));
  450. fReturn = true;
  451. break;
  452. default:
  453. // Couldn't enumerate modules...
  454. fReturn = false;
  455. }
  456. }
  457. }
  458. return fReturn;
  459. }
  460. bool CProcessInfo::EnumerateModulesFromFile(DWORD iProcessID, LPTSTR tszProcessName)
  461. {
  462. CModuleInfo * lpModuleInfo;
  463. // I need these near the end when I probe to see if the next module
  464. // is for this process...
  465. enum { BUFFER_SIZE = 128};
  466. char szTempProcessName[BUFFER_SIZE];
  467. char szProcessName[BUFFER_SIZE];
  468. DWORD iTempProcessID;
  469. // Let's save away the Process Name...
  470. // Unfortunately, when reading from the CSV file, the data is MBCS... so I need
  471. // to convert...
  472. CUtilityFunctions::CopyTSTRStringToAnsi(tszProcessName, szProcessName, BUFFER_SIZE);
  473. // Copy the Process ID
  474. m_iProcessID = iProcessID;
  475. // Local buffer for reading data...
  476. char szModulePath[_MAX_PATH+1];
  477. TCHAR tszModulePath[_MAX_PATH+1];
  478. bool fDone = false;
  479. bool fNew = false;
  480. while (!fDone)
  481. {
  482. // Read in the Module Path
  483. if (!m_lpInputFile->ReadString(szModulePath, _MAX_PATH+1))
  484. return true;
  485. CUtilityFunctions::CopyAnsiStringToTSTR(szModulePath, tszModulePath, _MAX_PATH+1);
  486. // If "-MATCH" was specified, look to see if this filename meets our criteria
  487. // before we save this away in our module cache...
  488. if (!g_lpProgramOptions->fDoesModuleMatchOurSearch(tszModulePath))
  489. {
  490. // Okay... read to the start of the next line...
  491. if (!m_lpInputFile->ReadFileLine())
  492. goto cleanup;
  493. goto probe_line; // We save having to get the module info again for this module...
  494. }
  495. // Okay, let's go ahead and get a ModuleInfo Object from our cache...
  496. // If pfNew returns TRUE, then this object is new and we'll need
  497. // to populate it with data...
  498. lpModuleInfo = m_lpModuleInfoCache->AddNewModuleInfoObject(tszModulePath, &fNew);
  499. if (false == fNew)
  500. {
  501. // We may have the object in the cache... now we need to
  502. // save a pointer to this object in our Process Info list
  503. AddNewModuleInfoObject(lpModuleInfo); // Just do our best...
  504. // Okay... read to the start of the next line...
  505. if (!m_lpInputFile->ReadFileLine())
  506. goto cleanup;
  507. goto probe_line; // We save having to get the module info again for this module...
  508. }
  509. // Not in the cache... so we need to init it, and get the module info...
  510. if (!lpModuleInfo->Initialize(m_lpInputFile, m_lpOutputFile, NULL))
  511. {
  512. return false; // Hmmm... memory error?
  513. }
  514. // Let's do it!! Populate the ModuleInfo object with data!!!!
  515. if (!lpModuleInfo->GetModuleInfo(tszModulePath, false, 0, true) )
  516. {
  517. // Well, we tried and failed...
  518. return false;
  519. }
  520. // Start obtaining information about the modules...
  521. if (!AddNewModuleInfoObject(lpModuleInfo))
  522. { // Failure adding the node.... This is pretty serious...
  523. return false;
  524. }
  525. // Okay, let's go ahead and probe to see what's coming...
  526. probe_line:
  527. // Read the first field (should be blank, unless this is a new collection type
  528. if (m_lpInputFile->ReadString())
  529. goto cleanup;
  530. // Read the Process Name...
  531. if (!m_lpInputFile->ReadString(szTempProcessName, BUFFER_SIZE))
  532. goto cleanup;
  533. // Compare the process name to the current process...
  534. if (_stricmp(szTempProcessName, szProcessName))
  535. goto cleanup;
  536. // Read the Process ID
  537. if (!m_lpInputFile->ReadDWORD(&iTempProcessID))
  538. goto cleanup;
  539. // Compare the process ID to the current process ID
  540. if (iTempProcessID != iProcessID)
  541. goto cleanup;
  542. }
  543. cleanup:
  544. // We need to reset out pointer so the functions above us can re-read
  545. // them (they expect to)...
  546. m_lpInputFile->ResetBufferPointerToStart();
  547. return true;
  548. }
  549. bool CProcessInfo::EnumerateModulesForRunningProcessUsingTOOLHELP32(DWORD iProcessID, LPTSTR tszProcessName)
  550. {
  551. BOOL bFlag;
  552. MODULEENTRY32 modentry;
  553. TCHAR tszFileName[_MAX_PATH];
  554. bool fProcessNameFound = false;
  555. bool fProcessNameProvided = false;
  556. bool fReturn = false;
  557. bool fNew = false;
  558. int iNumberOfModules = 0;
  559. HANDLE hSnapShot = INVALID_HANDLE_VALUE;
  560. CModuleInfo * lpModuleInfo = NULL;
  561. // Save off our PID (in case we need it later?)
  562. m_iProcessID = iProcessID;
  563. if (tszProcessName && SetProcessName(tszProcessName))
  564. {
  565. fProcessNameProvided = true;
  566. }
  567. // If we were provided a process name to match, we can do it here...
  568. if ( fProcessNameProvided && g_lpProgramOptions->GetProcessName() )
  569. {
  570. // Let's go ahead and look to see if this is a module name match
  571. fProcessNameFound = fModuleNameMatches(g_lpProgramOptions->GetProcessName(), GetProcessName());
  572. // Quit now if we can...
  573. if (fProcessNameFound == false)
  574. goto cleanup;
  575. }
  576. // If we're doing this for TLIST output... then we already have the process name...
  577. // We're done!
  578. if (g_lpProgramOptions->GetMode(CProgramOptions::PrintTaskListMode))
  579. {
  580. fReturn = true;
  581. goto cleanup;
  582. }
  583. // Get a handle to a Toolhelp snapshot of the systems processes.
  584. hSnapShot = g_lpDelayLoad->CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, iProcessID);
  585. if( hSnapShot == INVALID_HANDLE_VALUE )
  586. {
  587. goto cleanup;
  588. }
  589. // Get the first process' information.
  590. modentry.dwSize = sizeof(MODULEENTRY32) ;
  591. bFlag = g_lpDelayLoad->Module32First( hSnapShot, &modentry ) ;
  592. // While there are modules, keep looping.
  593. while( bFlag )
  594. {
  595. // We have a new module for this process!
  596. iNumberOfModules++;
  597. // Copy the path!
  598. _tcscpy(tszFileName, modentry.szExePath);
  599. //#ifdef _DEBUG
  600. // _tprintf(TEXT("[%d] Module = %s\n"), iNumberOfModules, tszFileName);
  601. //#endif
  602. CUtilityFunctions::UnMungePathIfNecessary(tszFileName);
  603. // If "-MATCH" was specified, look to see if this filename meets our criteria
  604. // before we save this away in our module cache...
  605. if (!g_lpProgramOptions->fDoesModuleMatchOurSearch(tszFileName))
  606. goto getnextmodule;
  607. // Okay, let's go ahead and get a ModuleInfo Object from our cache...
  608. // If pfNew returns TRUE, then this object is new and we'll need
  609. // to populate it with data...
  610. lpModuleInfo = m_lpModuleInfoCache->AddNewModuleInfoObject(tszFileName, &fNew);
  611. if (false == fNew)
  612. {
  613. // We may have the object in the cache... now we need to
  614. // save a pointer to this object in our Process Info list
  615. AddNewModuleInfoObject(lpModuleInfo); // Just do our best...
  616. // We save having to get the module info again for this module...
  617. goto getnextmodule;
  618. }
  619. // Not in the cache... so we need to init it, and get the module info...
  620. // Okay, let's create a ModuleInfo object and pass this down
  621. // routines that will populate it full of data...
  622. if (lpModuleInfo->Initialize(NULL, m_lpOutputFile, NULL))
  623. {
  624. // Let's do it!! Populate the ModuleInfo object with data!!!!
  625. if (lpModuleInfo->GetModuleInfo(tszFileName))
  626. {
  627. // Start obtaining information about the modules...
  628. // We may have the object in the cache... now we need to
  629. // save a pointer to this object in our Process Info list
  630. if (AddNewModuleInfoObject(lpModuleInfo))
  631. {
  632. }
  633. }
  634. }
  635. getnextmodule:
  636. // Get the next Module...
  637. modentry.dwSize = sizeof(MODULEENTRY32) ;
  638. bFlag = g_lpDelayLoad->Module32Next( hSnapShot, &modentry );
  639. }
  640. fReturn = true;
  641. cleanup:
  642. if (hSnapShot != INVALID_HANDLE_VALUE)
  643. CloseHandle(hSnapShot);
  644. return fReturn;
  645. }
  646. bool CProcessInfo::SetProcessName(LPTSTR tszFileName)
  647. {
  648. // Confirm we were given a process name...
  649. if (!tszFileName)
  650. return false;
  651. TCHAR fname[_MAX_FNAME];
  652. TCHAR ext[_MAX_EXT];
  653. TCHAR tszTempFileName[_MAX_FNAME+_MAX_EXT+1];
  654. // Let's extract the filename from the module path
  655. _tsplitpath( tszFileName, NULL, NULL, fname, ext );
  656. // Reconstruct the filename...
  657. _stprintf(tszTempFileName, TEXT("%s%s"), _tcsupr(fname), _tcsupr(ext));
  658. // Let's free anything that's already here...
  659. if (m_tszProcessName)
  660. delete [] m_tszProcessName;
  661. // No conversion necessary... copy over...
  662. m_tszProcessName = new TCHAR[_tcslen(tszTempFileName)+1];
  663. if (!m_tszProcessName)
  664. return false;
  665. _tcscpy(m_tszProcessName, tszTempFileName);
  666. return true;
  667. }
  668. LPTSTR CProcessInfo::GetProcessName()
  669. {
  670. return m_tszProcessName;
  671. }
  672. bool CProcessInfo::GetProcessData()
  673. {
  674. // Is this being collected from a file?
  675. if (g_lpProgramOptions->GetMode(CProgramOptions::InputCSVFileMode))
  676. GetProcessDataFromFile();
  677. return true;
  678. }
  679. bool CProcessInfo::GetProcessDataFromFile()
  680. {
  681. // Read the Process Header Line
  682. if (!m_lpInputFile->ReadFileLine())
  683. return false;
  684. // Currently, we don't actually read the data...
  685. enum { BUFFER_SIZE = 128};
  686. char szProcessName[BUFFER_SIZE];
  687. TCHAR tszProcessName[BUFFER_SIZE];
  688. DWORD iProcessID;
  689. // Read the first field (should be blank, unless this is a new collection type
  690. if (m_lpInputFile->ReadString())
  691. return true;
  692. bool fReturn = true;
  693. while (fReturn == true)
  694. {
  695. // Read the process name...
  696. if (0 == m_lpInputFile->ReadString(szProcessName, BUFFER_SIZE))
  697. break;
  698. if (!m_lpInputFile->ReadDWORD(&iProcessID))
  699. {
  700. fReturn = false;
  701. break;
  702. }
  703. // We need to convert this to Unicode possibly... (it will be copied in EnumModules())
  704. CUtilityFunctions::CopyAnsiStringToTSTR(szProcessName, tszProcessName, BUFFER_SIZE);
  705. // Save the process name...
  706. SetProcessName(tszProcessName);
  707. // Enumerate the modules for the process
  708. if (!EnumerateModules(iProcessID, NULL, tszProcessName))
  709. {
  710. fReturn = false;
  711. break;
  712. }
  713. // Before we read a new line... are we already pointing to the end?
  714. if (m_lpInputFile->EndOfFile())
  715. {
  716. break;
  717. }
  718. // Read the first field (should be blank, unless this is a new collection type
  719. if (m_lpInputFile->ReadString())
  720. break;
  721. }
  722. // We don't expect to find anything...
  723. return fReturn;
  724. }