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.

565 lines
14 KiB

  1. // DelayLoad.cpp: implementation of the CDelayLoad class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "DelayLoad.h"
  5. #include "UtilityFunctions.h"
  6. #include "stdlib.h"
  7. //////////////////////////////////////////////////////////////////////
  8. // Construction/Destruction
  9. //////////////////////////////////////////////////////////////////////
  10. CDelayLoad::CDelayLoad()
  11. {
  12. // DBGHELP
  13. m_hDBGHELP = NULL;
  14. m_fDBGHELPInitialized = false;
  15. m_fDBGHELPInitializedAttempted = false;
  16. m_lpfMakeSureDirectoryPathExists = NULL;
  17. // PSAPI
  18. m_hPSAPI = NULL;
  19. m_fPSAPIInitialized = false;
  20. m_fPSAPIInitializedAttempted = false;
  21. m_lpfEnumProcesses = NULL;
  22. m_lpfEnumProcessModules = NULL;
  23. m_lpfGetModuleFileNameEx = NULL;
  24. m_lpfEnumDeviceDrivers = NULL;
  25. m_lpfGetDeviceDriverFileName = NULL;
  26. // TOOLHELP32
  27. m_hTOOLHELP32 = NULL;
  28. m_fTOOLHELP32Initialized = false;
  29. m_fTOOLHELP32InitializedAttempted = false;
  30. m_lpfCreateToolhelp32Snapshot = NULL;
  31. m_lpfProcess32First = NULL;
  32. m_lpfProcess32Next = NULL;
  33. m_lpfModule32First = NULL;
  34. m_lpfModule32Next = NULL;
  35. // SYMSRV
  36. m_hSYMSRV = NULL;
  37. m_fSYMSRVInitialized = false;
  38. m_fSYMSRVInitializedAttempted = false;
  39. m_tszSymSrvDLL = NULL;
  40. m_lpfSymbolServer = NULL;
  41. m_lpfSymbolServerClose = NULL;
  42. }
  43. CDelayLoad::~CDelayLoad()
  44. {
  45. if (m_hDBGHELP)
  46. FreeLibrary(m_hDBGHELP);
  47. if (m_hPSAPI)
  48. FreeLibrary(m_hPSAPI);
  49. if (m_hTOOLHELP32)
  50. FreeLibrary(m_hTOOLHELP32);
  51. if (m_hSYMSRV)
  52. FreeLibrary(m_hSYMSRV);
  53. if (m_tszSymSrvDLL)
  54. {
  55. delete [] m_tszSymSrvDLL;
  56. }
  57. }
  58. bool CDelayLoad::Initialize_DBGHELP()
  59. {
  60. m_fDBGHELPInitialized = false;
  61. m_fDBGHELPInitializedAttempted = true;
  62. // Load library on DBGHELP.DLL and get the procedures explicitly.
  63. m_hDBGHELP = LoadLibrary( TEXT("DBGHELP.DLL") );
  64. if( m_hDBGHELP == NULL )
  65. {
  66. // This is fatal, since we need this for cases where we are searching
  67. // for DBG files, and creation of directories...
  68. _tprintf(TEXT("\nERROR: Unable to load DBGHELP.DLL, which is required for proper operation.\n"));
  69. _tprintf(TEXT("You should ensure that a copy of this DLL is on your system path, or in the\n"));
  70. _tprintf(TEXT("same directory as this utility.\n"));
  71. goto exit;
  72. } else
  73. {
  74. // Get procedure addresses.
  75. m_lpfMakeSureDirectoryPathExists = (PfnMakeSureDirectoryPathExists) GetProcAddress( m_hDBGHELP, "MakeSureDirectoryPathExists");
  76. if( (m_lpfMakeSureDirectoryPathExists == NULL) )
  77. {
  78. // Consider this fatal
  79. _tprintf(TEXT("\nWARNING: The version of DBGHELP.DLL being loaded doesn't have required\n"));
  80. _tprintf(TEXT("functions!. Please update this module with a newer version and try again.\n"));
  81. FreeLibrary( m_hDBGHELP ) ;
  82. m_hDBGHELP = NULL;
  83. goto exit;
  84. }
  85. }
  86. m_fDBGHELPInitialized = true;
  87. exit:
  88. return m_fDBGHELPInitialized;
  89. }
  90. BOOL CDelayLoad::MakeSureDirectoryPathExists(LPTSTR DirPath)
  91. {
  92. // If we've never initialized DBGHELP, do so now...
  93. if (!m_fDBGHELPInitializedAttempted)
  94. {
  95. // Initialize the DLL if needed...
  96. if (FALSE == Initialize_DBGHELP())
  97. return FALSE;
  98. }
  99. // If we've attempted, but we failed... then bail now...
  100. if (!m_fDBGHELPInitialized)
  101. {
  102. return FALSE;
  103. }
  104. if (!m_lpfMakeSureDirectoryPathExists)
  105. return FALSE;
  106. // This API normally takes ASCII strings only...
  107. char szDirPath[_MAX_PATH];
  108. CUtilityFunctions::CopyTSTRStringToAnsi(DirPath, szDirPath, _MAX_PATH);
  109. // Invoke and return...
  110. return m_lpfMakeSureDirectoryPathExists(szDirPath);
  111. }
  112. // PSAPI.DLL - APIs
  113. bool CDelayLoad::Initialize_PSAPI()
  114. {
  115. m_fPSAPIInitialized = false;
  116. m_fPSAPIInitializedAttempted = true;
  117. // Load library on DBGHELP.DLL and get the procedures explicitly.
  118. m_hPSAPI = LoadLibrary( TEXT("PSAPI.DLL") );
  119. if( m_hPSAPI == NULL )
  120. {
  121. // This may/may not be fatal... we can always fall back to TOOLHELP32 for Win2000/Win98
  122. goto exit;
  123. } else
  124. {
  125. // Get procedure addresses.
  126. m_lpfEnumProcesses = (PfnEnumProcesses) GetProcAddress( m_hPSAPI, "EnumProcesses" ) ;
  127. m_lpfEnumProcessModules = (PfnEnumProcessModules) GetProcAddress( m_hPSAPI, "EnumProcessModules" );
  128. #ifdef UNICODE
  129. m_lpfGetModuleFileNameEx =(PfnGetModuleFileNameEx) GetProcAddress(m_hPSAPI, "GetModuleFileNameExW" );
  130. m_lpfGetDeviceDriverFileName = (PfnGetDeviceDriverFileName) GetProcAddress(m_hPSAPI, "GetDeviceDriverFileNameW");
  131. #else
  132. m_lpfGetModuleFileNameEx =(PfnGetModuleFileNameEx) GetProcAddress(m_hPSAPI, "GetModuleFileNameExA" );
  133. m_lpfGetDeviceDriverFileName = (PfnGetDeviceDriverFileName) GetProcAddress(m_hPSAPI, "GetDeviceDriverFileNameA");
  134. #endif
  135. m_lpfEnumDeviceDrivers = (PfnEnumDeviceDrivers) GetProcAddress(m_hPSAPI, "EnumDeviceDrivers" );
  136. if( m_lpfEnumProcesses == NULL ||
  137. m_lpfEnumProcessModules == NULL ||
  138. m_lpfGetModuleFileNameEx == NULL ||
  139. m_lpfEnumDeviceDrivers == NULL ||
  140. m_lpfGetDeviceDriverFileName == NULL
  141. )
  142. {
  143. _tprintf(TEXT("The version of PSAPI.DLL being loaded doesn't have required functions!.\n"));
  144. FreeLibrary( m_hPSAPI ) ;
  145. m_hPSAPI = NULL;
  146. goto exit;
  147. }
  148. }
  149. m_fPSAPIInitialized = true;
  150. exit:
  151. return m_fPSAPIInitialized;
  152. }
  153. DWORD CDelayLoad::GetModuleFileNameEx(HANDLE hHandle, HMODULE hModule, LPTSTR lpFilename, DWORD nSize)
  154. {
  155. // If we've never initialized PSAPI, do so now...
  156. if (!m_fPSAPIInitializedAttempted)
  157. {
  158. // Initialize the DLL if needed...
  159. if (FALSE == Initialize_PSAPI())
  160. return FALSE;
  161. }
  162. // If we've attempted, but we failed... then bail now...
  163. if (!m_fPSAPIInitialized)
  164. {
  165. return FALSE;
  166. }
  167. if (!m_lpfGetModuleFileNameEx)
  168. return FALSE;
  169. return m_lpfGetModuleFileNameEx(hHandle, hModule, lpFilename, nSize);
  170. }
  171. BOOL CDelayLoad::EnumProcessModules(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded)
  172. {
  173. // If we've never initialized PSAPI, do so now...
  174. if (!m_fPSAPIInitializedAttempted)
  175. {
  176. // Initialize the DLL if needed...
  177. if (FALSE == Initialize_PSAPI())
  178. return FALSE;
  179. }
  180. // If we've attempted, but we failed... then bail now...
  181. if (!m_fPSAPIInitialized)
  182. {
  183. return FALSE;
  184. }
  185. if (!m_lpfEnumProcessModules)
  186. return FALSE;
  187. return m_lpfEnumProcessModules(hProcess, lphModule, cb, lpcbNeeded);
  188. }
  189. BOOL CDelayLoad::EnumProcesses(DWORD *lpidProcess, DWORD cb, DWORD *cbNeeded)
  190. {
  191. // If we've never initialized PSAPI, do so now...
  192. if (!m_fPSAPIInitializedAttempted)
  193. {
  194. // Initialize the DLL if needed...
  195. if (FALSE == Initialize_PSAPI())
  196. return FALSE;
  197. }
  198. // If we've attempted, but we failed... then bail now...
  199. if (!m_fPSAPIInitialized)
  200. {
  201. return FALSE;
  202. }
  203. if (!m_lpfEnumProcesses)
  204. return FALSE;
  205. return m_lpfEnumProcesses(lpidProcess, cb, cbNeeded);
  206. }
  207. BOOL CDelayLoad::EnumDeviceDrivers(LPVOID *lpImageBase, DWORD cb, LPDWORD lpcbNeeded)
  208. {
  209. // If we've never initialized PSAPI, do so now...
  210. if (!m_fPSAPIInitializedAttempted)
  211. {
  212. // Initialize the DLL if needed...
  213. if (FALSE == Initialize_PSAPI())
  214. return FALSE;
  215. }
  216. // If we've attempted, but we failed... then bail now...
  217. if (!m_fPSAPIInitialized)
  218. {
  219. return FALSE;
  220. }
  221. if (!m_lpfEnumDeviceDrivers)
  222. return FALSE;
  223. return m_lpfEnumDeviceDrivers(lpImageBase, cb, lpcbNeeded);
  224. }
  225. DWORD CDelayLoad::GetDeviceDriverFileName(LPVOID ImageBase, LPTSTR lpFilename, DWORD nSize)
  226. {
  227. // If we've never initialized PSAPI, do so now...
  228. if (!m_fPSAPIInitializedAttempted)
  229. {
  230. // Initialize the DLL if needed...
  231. if (FALSE == Initialize_PSAPI())
  232. return FALSE;
  233. }
  234. // If we've attempted, but we failed... then bail now...
  235. if (!m_fPSAPIInitialized)
  236. {
  237. return FALSE;
  238. }
  239. if (!m_lpfGetDeviceDriverFileName)
  240. return FALSE;
  241. return m_lpfGetDeviceDriverFileName(ImageBase, lpFilename, nSize);
  242. }
  243. // TOOLHELP32.DLL - APIs
  244. bool CDelayLoad::Initialize_TOOLHELP32()
  245. {
  246. m_fTOOLHELP32Initialized = false;
  247. m_fTOOLHELP32InitializedAttempted = true;
  248. // Load library on DBGHELP.DLL and get the procedures explicitly.
  249. m_hTOOLHELP32 = LoadLibrary( TEXT("KERNEL32.DLL") );
  250. if( m_hTOOLHELP32 == NULL )
  251. {
  252. // This may/may not be fatal... we can always fall back to TOOLHELP32 for Win2000/Win98
  253. goto exit;
  254. } else
  255. {
  256. //
  257. // BUG 523 - GREGWI - Unicode version fails to enumerate processes correctly...
  258. // (Code added to enumerate the correct DLL entrypoints in KERNEL32.DLL)
  259. //
  260. // Get procedure addresses based on UNICODE or ANSI
  261. m_lpfCreateToolhelp32Snapshot = (PfnCreateToolhelp32Snapshot) GetProcAddress( m_hTOOLHELP32, "CreateToolhelp32Snapshot" );
  262. #ifdef UNICODE
  263. m_lpfProcess32First = (PfnProcess32First) GetProcAddress( m_hTOOLHELP32, "Process32FirstW" );
  264. m_lpfProcess32Next = (PfnProcess32Next) GetProcAddress( m_hTOOLHELP32, "Process32NextW" );
  265. m_lpfModule32First = (PfnModule32First) GetProcAddress( m_hTOOLHELP32, "Module32FirstW" );
  266. m_lpfModule32Next = (PfnModule32Next) GetProcAddress( m_hTOOLHELP32, "Module32NextW" );
  267. #else
  268. m_lpfProcess32First = (PfnProcess32First) GetProcAddress( m_hTOOLHELP32, "Process32First" );
  269. m_lpfProcess32Next = (PfnProcess32Next) GetProcAddress( m_hTOOLHELP32, "Process32Next" );
  270. m_lpfModule32First = (PfnModule32First) GetProcAddress( m_hTOOLHELP32, "Module32First" );
  271. m_lpfModule32Next = (PfnModule32Next) GetProcAddress( m_hTOOLHELP32, "Module32Next" );
  272. #endif
  273. if (!m_lpfCreateToolhelp32Snapshot ||
  274. !m_lpfProcess32First ||
  275. !m_lpfProcess32Next ||
  276. !m_lpfModule32First ||
  277. !m_lpfModule32Next)
  278. {
  279. // Free our handle to KERNEL32.DLL
  280. FreeLibrary(m_hTOOLHELP32);
  281. m_hTOOLHELP32 = NULL;
  282. goto exit;
  283. }
  284. }
  285. m_fTOOLHELP32Initialized = true;
  286. exit:
  287. return m_fTOOLHELP32Initialized;
  288. }
  289. HANDLE WINAPI CDelayLoad::CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID)
  290. {
  291. // If we've never initialized TOOLHELP32, do so now...
  292. if (!m_fTOOLHELP32InitializedAttempted)
  293. {
  294. // Initialize the DLL if needed...
  295. if (FALSE == Initialize_TOOLHELP32())
  296. return INVALID_HANDLE_VALUE;
  297. }
  298. // If we've attempted, but we failed... then bail now...
  299. if (!m_fTOOLHELP32Initialized)
  300. {
  301. return INVALID_HANDLE_VALUE;
  302. }
  303. if (!m_lpfCreateToolhelp32Snapshot)
  304. return INVALID_HANDLE_VALUE;
  305. return m_lpfCreateToolhelp32Snapshot(dwFlags, th32ProcessID);
  306. }
  307. BOOL WINAPI CDelayLoad::Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
  308. {
  309. // If we've never initialized TOOLHELP32, do so now...
  310. if (!m_fTOOLHELP32InitializedAttempted)
  311. {
  312. // Initialize the DLL if needed...
  313. if (FALSE == Initialize_TOOLHELP32())
  314. return FALSE;
  315. }
  316. // If we've attempted, but we failed... then bail now...
  317. if (!m_fTOOLHELP32Initialized)
  318. {
  319. return FALSE;
  320. }
  321. if (!m_lpfProcess32First)
  322. return FALSE;
  323. return m_lpfProcess32First(hSnapshot, lppe);
  324. }
  325. BOOL WINAPI CDelayLoad::Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
  326. {
  327. // If we've never initialized TOOLHELP32, do so now...
  328. if (!m_fTOOLHELP32InitializedAttempted)
  329. {
  330. // Initialize the DLL if needed...
  331. if (FALSE == Initialize_TOOLHELP32())
  332. return FALSE;
  333. }
  334. // If we've attempted, but we failed... then bail now...
  335. if (!m_fTOOLHELP32Initialized)
  336. {
  337. return FALSE;
  338. }
  339. if (!m_lpfProcess32Next)
  340. return FALSE;
  341. return m_lpfProcess32Next(hSnapshot, lppe);
  342. }
  343. BOOL WINAPI CDelayLoad::Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
  344. {
  345. // If we've never initialized TOOLHELP32, do so now...
  346. if (!m_fTOOLHELP32InitializedAttempted)
  347. {
  348. // Initialize the DLL if needed...
  349. if (FALSE == Initialize_TOOLHELP32())
  350. return FALSE;
  351. }
  352. // If we've attempted, but we failed... then bail now...
  353. if (!m_fTOOLHELP32Initialized)
  354. {
  355. return FALSE;
  356. }
  357. if (!m_lpfModule32First)
  358. return FALSE;
  359. return m_lpfModule32First(hSnapshot, lpme);
  360. }
  361. BOOL WINAPI CDelayLoad::Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
  362. {
  363. // If we've never initialized TOOLHELP32, do so now...
  364. if (!m_fTOOLHELP32InitializedAttempted)
  365. {
  366. // Initialize the DLL if needed...
  367. if (FALSE == Initialize_TOOLHELP32())
  368. return FALSE;
  369. }
  370. // If we've attempted, but we failed... then bail now...
  371. if (!m_fTOOLHELP32Initialized)
  372. {
  373. return FALSE;
  374. }
  375. if (!m_lpfModule32Next)
  376. return FALSE;
  377. return m_lpfModule32Next(hSnapshot, lpme);
  378. }
  379. bool CDelayLoad::Initialize_SYMSRV(LPCTSTR tszSymSrvDLL)
  380. {
  381. m_fSYMSRVInitialized = false;
  382. m_fSYMSRVInitializedAttempted = true;
  383. // If we're loading a new SYMSRV DLL file (SYMSRV.DLL or some other Symbol DLL)
  384. if (m_hSYMSRV)
  385. {
  386. // Compare... is this file the same as the last... if so... don't worry about it...
  387. if (_tcscmp(tszSymSrvDLL, m_tszSymSrvDLL))
  388. {
  389. FreeLibrary(m_hSYMSRV);
  390. m_hSYMSRV = NULL;
  391. delete [] m_tszSymSrvDLL; // Free the previous string...
  392. }
  393. }
  394. // Load library on SYMSRV.DLL and get the procedures explicitly.
  395. m_hSYMSRV = LoadLibrary( tszSymSrvDLL );
  396. if( m_hSYMSRV == NULL )
  397. {
  398. // This is fatal, since we need this for cases where we are searching
  399. // for DBG files, and creation of directories...
  400. _tprintf(TEXT("\nERROR: Unable to load %s, which is required for proper operation.\n"), tszSymSrvDLL);
  401. _tprintf(TEXT("You should ensure that a copy of this DLL is on your system path, or in the\n"));
  402. _tprintf(TEXT("same directory as this utility.\n"));
  403. goto exit;
  404. } else
  405. {
  406. // Get procedure addresses.
  407. m_lpfSymbolServer = (PfnSymbolServer) GetProcAddress( m_hSYMSRV, "SymbolServer");
  408. m_lpfSymbolServerClose = (PfnSymbolServerClose) GetProcAddress( m_hSYMSRV, "SymbolServerClose");
  409. if( (m_lpfSymbolServer == NULL) ||
  410. (m_lpfSymbolServerClose == NULL)
  411. )
  412. {
  413. // Consider this fatal
  414. _tprintf(TEXT("\nWARNING: The version of %s being loaded doesn't have required\n"), tszSymSrvDLL);
  415. _tprintf(TEXT("functions!. Please update this module with a newer version and try again.\n"));
  416. FreeLibrary( m_hSYMSRV ) ;
  417. m_hSYMSRV = NULL;
  418. goto exit;
  419. }
  420. // Copy the provided string
  421. m_tszSymSrvDLL = new TCHAR[_tcslen(tszSymSrvDLL)+1];
  422. if (NULL == m_tszSymSrvDLL)
  423. goto exit;
  424. _tcscpy(m_tszSymSrvDLL, tszSymSrvDLL);
  425. }
  426. m_fSYMSRVInitialized = true;
  427. exit:
  428. return m_fSYMSRVInitialized;
  429. }
  430. BOOL WINAPI CDelayLoad::SymbolServer(LPCSTR params, LPCSTR filename, DWORD num1, DWORD num2, DWORD num3, LPSTR path)
  431. {
  432. /*
  433. // If we've never initialized SYMSRV, do so now...
  434. if (!m_fSYMSRVInitializedAttempted)
  435. {
  436. // Initialize the DLL if needed...
  437. if (FALSE == Initialize_SYMSRV())
  438. return FALSE;
  439. }
  440. */
  441. // If we've attempted, but we failed... then bail now...
  442. if (!m_fSYMSRVInitialized)
  443. {
  444. return FALSE;
  445. }
  446. if (!m_lpfSymbolServer)
  447. return FALSE;
  448. return m_lpfSymbolServer(params, filename, num1, num2, num3, path);
  449. }
  450. BOOL WINAPI CDelayLoad::SymbolServerClose(VOID)
  451. {
  452. /*
  453. // If we've never initialized SYMSRV, do so now...
  454. if (!m_fSYMSRVInitializedAttempted)
  455. {
  456. // Initialize the DLL if needed...
  457. if (FALSE == Initialize_SYMSRV())
  458. return FALSE;
  459. }
  460. */
  461. // If we've attempted, but we failed... then bail now...
  462. if (!m_fSYMSRVInitialized)
  463. {
  464. return FALSE;
  465. }
  466. if (!m_lpfSymbolServerClose)
  467. return FALSE;
  468. return m_lpfSymbolServerClose();
  469. }