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.

1174 lines
28 KiB

  1. /*++
  2. Module Name:
  3. common.c
  4. Abstract:
  5. This module contains common apis used by tlist & kill.
  6. --*/
  7. /******************************************************************************\
  8. * This is a part of the Microsoft Source Code Samples.
  9. * Copyright (C) 1994-1998 Microsoft Corporation.
  10. * All rights reserved.
  11. * This source code is only intended as a supplement to
  12. * Microsoft Development Tools and/or WinHelp documentation.
  13. * See these sources for detailed information regarding the
  14. * Microsoft samples programs.
  15. \******************************************************************************/
  16. #include <windows.h>
  17. #include <winperf.h> // for Windows NT
  18. #include <tchar.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #if 0
  23. #include <tlhelp32.h> // for Windows 95
  24. #endif
  25. #include "common.h"
  26. #include "inetdbgp.h"
  27. //
  28. // RETURNCODETOHRESULT() maps a return code to an HRESULT. If the return
  29. // code is a Win32 error (identified by a zero high word) then it is mapped
  30. // using the standard HRESULT_FROM_WIN32() macro. Otherwise, the return
  31. // code is assumed to already be an HRESULT and is returned unchanged.
  32. //
  33. #define RETURNCODETOHRESULT(rc) \
  34. (((rc) < 0x10000) \
  35. ? HRESULT_FROM_WIN32(rc) \
  36. : (rc))
  37. //
  38. // manifest constants
  39. //
  40. #define INITIAL_SIZE 51200
  41. #define EXTEND_SIZE 25600
  42. #define REGKEY_PERF _T("software\\microsoft\\windows nt\\currentversion\\perflib")
  43. #define REGSUBKEY_COUNTERS _T("Counters")
  44. #define PROCESS_COUNTER _T("process")
  45. #define PROCESSID_COUNTER _T("id process")
  46. #define UNKNOWN_TASK _T("unknown")
  47. #define KILL_VERIFY_TIMEOUT (10*1000)
  48. #define KILL_VERIFY_DELAY 100
  49. typedef struct _SearchWin {
  50. LPCTSTR pExeName;
  51. LPDWORD pdwPid ;
  52. HWND* phwnd;
  53. } SearchWin ;
  54. typedef struct _SearchMod {
  55. LPSTR pExeName;
  56. LPBOOL pfFound;
  57. } SearchMod ;
  58. //
  59. // prototypes
  60. //
  61. BOOL CALLBACK
  62. EnumWindowsProc2(
  63. HWND hwnd,
  64. LPARAM lParam
  65. );
  66. HRESULT
  67. IsDllInProcess(
  68. DWORD dwProcessId,
  69. LPSTR pszName,
  70. LPBOOL pfFound
  71. );
  72. #if 0
  73. //
  74. // Function pointer types for accessing Toolhelp32 functions dynamically.
  75. // By dynamically accessing these functions, we can do so only on Windows
  76. // 95 and still run on Windows NT, which does not have these functions.
  77. //
  78. typedef BOOL (WINAPI *PROCESSWALK)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
  79. typedef HANDLE (WINAPI *CREATESNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);
  80. //
  81. // prototypes
  82. //
  83. BOOL CALLBACK
  84. EnumWindowsProc(
  85. HWND hwnd,
  86. DWORD lParam
  87. );
  88. DWORD
  89. GetTaskList95(
  90. PTASK_LIST pTask,
  91. DWORD dwNumTasks,
  92. LPTSTR pName
  93. )
  94. /*++
  95. Routine Description:
  96. Provides an API for getting a list of tasks running at the time of the
  97. API call. This function uses Toolhelp32to get the task list and is
  98. therefore straight WIN32 calls that anyone can call.
  99. Arguments:
  100. dwNumTasks - maximum number of tasks that the pTask array can hold
  101. Return Value:
  102. Number of tasks placed into the pTask array.
  103. --*/
  104. {
  105. CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
  106. PROCESSWALK pProcess32First = NULL;
  107. PROCESSWALK pProcess32Next = NULL;
  108. HANDLE hKernel = NULL;
  109. HANDLE hProcessSnap = NULL;
  110. PROCESSENTRY32 pe32 = {0};
  111. DWORD dwTaskCount = 0;
  112. // Guarantee to the code later on that we'll enum at least one task.
  113. if (dwNumTasks == 0)
  114. return 0;
  115. // Obtain a module handle to KERNEL so that we can get the addresses of
  116. // the 32-bit Toolhelp functions we need.
  117. hKernel = GetModuleHandle(_T("KERNEL32.DLL"));
  118. if (hKernel)
  119. {
  120. pCreateToolhelp32Snapshot =
  121. (CREATESNAPSHOT)GetProcAddress(hKernel, "CreateToolhelp32Snapshot");
  122. pProcess32First = (PROCESSWALK)GetProcAddress(hKernel,
  123. "Process32First");
  124. pProcess32Next = (PROCESSWALK)GetProcAddress(hKernel,
  125. "Process32Next");
  126. }
  127. // make sure we got addresses of all needed Toolhelp functions.
  128. if (!(pProcess32First && pProcess32Next && pCreateToolhelp32Snapshot))
  129. return 0;
  130. // Take a snapshot of all processes currently in the system.
  131. hProcessSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  132. if (hProcessSnap == (HANDLE)-1)
  133. return 0;
  134. // Walk the snapshot of processes and for each process, get information
  135. // to display.
  136. dwTaskCount = 0;
  137. pe32.dwSize = sizeof(PROCESSENTRY32); // must be filled out before use
  138. if (pProcess32First(hProcessSnap, &pe32))
  139. {
  140. do
  141. {
  142. LPTSTR pCurChar;
  143. // strip path and leave executabe filename splitpath
  144. for (pCurChar = (pe32.szExeFile + lstrlen (pe32.szExeFile));
  145. *pCurChar != _T('\\') && pCurChar != pe32.szExeFile;
  146. --pCurChar)
  147. lstrcpy(pTask -> ProcessName, pCurChar);
  148. pTask -> flags = 0;
  149. pTask -> dwProcessId = pe32.th32ProcessID;
  150. ++dwTaskCount; // keep track of how many tasks we've got so far
  151. ++pTask; // get to next task info block.
  152. }
  153. while (dwTaskCount < dwNumTasks && pProcess32Next(hProcessSnap, &pe32));
  154. }
  155. else
  156. dwTaskCount = 0; // Couldn't walk the list of processes.
  157. // Don't forget to clean up the snapshot object...
  158. CloseHandle (hProcessSnap);
  159. return dwTaskCount;
  160. }
  161. #endif
  162. HRESULT
  163. GetTaskListNT(
  164. PTASK_LIST pTask,
  165. DWORD dwNumTasks,
  166. LPTSTR pName,
  167. LPDWORD pdwNumTasks,
  168. BOOL fKill,
  169. LPSTR pszMandatoryModule
  170. )
  171. /*++
  172. Routine Description:
  173. Provides an API for getting a list of tasks running at the time of the
  174. API call. This function uses the registry performance data to get the
  175. task list and is therefore straight WIN32 calls that anyone can call.
  176. Arguments:
  177. pTask - updated with array of tasks if fKill is FALSE
  178. dwNumTasks - maximum number of tasks that the pTask array can hold
  179. pName - process name to look for
  180. pdwNumTasks - updated with count of tasks in pTask if fKill is FALSE
  181. fKill - TRUE to kill process instead of populating pTask
  182. pszMandatoryModule - if non NULL then this module must be loaded in the process space
  183. for it to be killed.
  184. Return Value:
  185. Status
  186. --*/
  187. {
  188. DWORD rc;
  189. HKEY hKeyNames;
  190. DWORD dwType;
  191. DWORD dwSize;
  192. LPBYTE buf = NULL;
  193. TCHAR szSubKey[1024];
  194. LANGID lid;
  195. LPTSTR p;
  196. LPTSTR p2;
  197. PPERF_DATA_BLOCK pPerf;
  198. PPERF_OBJECT_TYPE pObj;
  199. PPERF_INSTANCE_DEFINITION pInst;
  200. PPERF_COUNTER_BLOCK pCounter;
  201. PPERF_COUNTER_DEFINITION pCounterDef;
  202. DWORD i;
  203. DWORD dwProcessIdTitle;
  204. DWORD dwProcessIdCounter;
  205. TCHAR szProcessName[MAX_PATH];
  206. // DWORD dwLimit = dwNumTasks;
  207. DWORD dwNumMatchTasks = 0;
  208. BOOL fMatch;
  209. HRESULT hres = S_OK;
  210. //
  211. // Look for the list of counters. Always use the neutral
  212. // English version, regardless of the local language. We
  213. // are looking for some particular keys, and we are always
  214. // going to do our looking in English. We are not going
  215. // to show the user the counter names, so there is no need
  216. // to go find the corresponding name in the local language.
  217. //
  218. lid = MAKELANGID( LANG_ENGLISH, SUBLANG_NEUTRAL );
  219. wsprintf( szSubKey, _T("%s\\%03x"), REGKEY_PERF, lid );
  220. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  221. szSubKey,
  222. 0,
  223. KEY_READ,
  224. &hKeyNames
  225. );
  226. if (rc != ERROR_SUCCESS)
  227. {
  228. hres = RETURNCODETOHRESULT( rc );
  229. goto exit;
  230. }
  231. //
  232. // get the buffer size for the counter names
  233. //
  234. rc = RegQueryValueEx( hKeyNames,
  235. REGSUBKEY_COUNTERS,
  236. NULL,
  237. &dwType,
  238. NULL,
  239. &dwSize
  240. );
  241. if (rc != ERROR_SUCCESS)
  242. {
  243. hres = RETURNCODETOHRESULT( rc );
  244. goto exit;
  245. }
  246. //
  247. // allocate the counter names buffer
  248. //
  249. buf = (LPBYTE) malloc( dwSize );
  250. if (buf == NULL)
  251. {
  252. hres = RETURNCODETOHRESULT( GetLastError() );
  253. goto exit;
  254. }
  255. memset( buf, 0, dwSize );
  256. //
  257. // read the counter names from the registry
  258. //
  259. rc = RegQueryValueEx( hKeyNames,
  260. REGSUBKEY_COUNTERS,
  261. NULL,
  262. &dwType,
  263. buf,
  264. &dwSize
  265. );
  266. if (rc != ERROR_SUCCESS)
  267. {
  268. hres = RETURNCODETOHRESULT( GetLastError() );
  269. goto exit;
  270. }
  271. //
  272. // now loop thru the counter names looking for the following counters:
  273. //
  274. // 1. "Process" process name
  275. // 2. "ID Process" process id
  276. //
  277. // the buffer contains multiple null terminated strings and then
  278. // finally null terminated at the end. the strings are in pairs of
  279. // counter number and counter name.
  280. //
  281. p = (LPTSTR)buf;
  282. while (*p)
  283. {
  284. if (p > (LPTSTR)buf)
  285. {
  286. for( p2=p-2; _istdigit(*p2); p2--) ;
  287. }
  288. if (lstrcmpi(p, PROCESS_COUNTER) == 0)
  289. {
  290. //
  291. // look backwards for the counter number
  292. //
  293. for( p2=p-2; _istdigit(*p2); p2--) ;
  294. lstrcpy( szSubKey, p2+1 );
  295. }
  296. else if (lstrcmpi(p, PROCESSID_COUNTER) == 0)
  297. {
  298. //
  299. // look backwards for the counter number
  300. //
  301. for( p2=p-2; _istdigit(*p2); p2--) ;
  302. dwProcessIdTitle = _ttol( p2+1 );
  303. }
  304. //
  305. // next string
  306. //
  307. p += (lstrlen(p) + 1);
  308. }
  309. //
  310. // free the counter names buffer
  311. //
  312. free( buf );
  313. //
  314. // allocate the initial buffer for the performance data
  315. //
  316. dwSize = INITIAL_SIZE;
  317. buf = malloc( dwSize );
  318. if (buf == NULL)
  319. {
  320. hres = RETURNCODETOHRESULT( GetLastError() );
  321. goto exit;
  322. }
  323. memset( buf, 0, dwSize );
  324. while (TRUE)
  325. {
  326. rc = RegQueryValueEx( HKEY_PERFORMANCE_DATA,
  327. szSubKey,
  328. NULL,
  329. &dwType,
  330. buf,
  331. &dwSize
  332. );
  333. pPerf = (PPERF_DATA_BLOCK) buf;
  334. //
  335. // check for success and valid perf data block signature
  336. //
  337. if ((rc == ERROR_SUCCESS) &&
  338. (dwSize > 0) &&
  339. (pPerf)->Signature[0] == (WCHAR)'P' &&
  340. (pPerf)->Signature[1] == (WCHAR)'E' &&
  341. (pPerf)->Signature[2] == (WCHAR)'R' &&
  342. (pPerf)->Signature[3] == (WCHAR)'F' )
  343. {
  344. break;
  345. }
  346. //
  347. // if buffer is not big enough, reallocate and try again
  348. //
  349. if (rc == ERROR_MORE_DATA)
  350. {
  351. dwSize += EXTEND_SIZE;
  352. buf = realloc( buf, dwSize );
  353. memset( buf, 0, dwSize );
  354. }
  355. else
  356. {
  357. goto exit;
  358. }
  359. }
  360. //
  361. // set the perf_object_type pointer
  362. //
  363. pObj = (PPERF_OBJECT_TYPE) ((LPBYTE)pPerf + pPerf->HeaderLength);
  364. //
  365. // loop thru the performance counter definition records looking
  366. // for the process id counter and then save its offset
  367. //
  368. pCounterDef = (PPERF_COUNTER_DEFINITION) ((DWORD_PTR)pObj + pObj->HeaderLength);
  369. for (i=0; i<(DWORD)pObj->NumCounters; i++)
  370. {
  371. if (pCounterDef->CounterNameTitleIndex == dwProcessIdTitle)
  372. {
  373. dwProcessIdCounter = pCounterDef->CounterOffset;
  374. break;
  375. }
  376. pCounterDef++;
  377. }
  378. // dwNumTasks = (DWORD)pObj->NumInstances;
  379. pInst = (PPERF_INSTANCE_DEFINITION) ((LPBYTE)pObj + pObj->DefinitionLength);
  380. //
  381. // loop thru the performance instance data extracting each process name
  382. // and process id
  383. //
  384. for (i=0; i<(DWORD)pObj->NumInstances; i++)
  385. {
  386. //
  387. // pointer to the process name
  388. //
  389. p = (LPTSTR) ((LPBYTE)pInst + pInst->NameOffset);
  390. #if !defined(_UNICODE)
  391. //
  392. // convert it to ascii
  393. //
  394. rc = WideCharToMultiByte( CP_ACP,
  395. 0,
  396. (LPCWSTR)p,
  397. -1,
  398. szProcessName,
  399. sizeof(szProcessName),
  400. NULL,
  401. NULL
  402. );
  403. p = szProcessName;
  404. if (!rc)
  405. {
  406. //
  407. // if we cant convert the string then use a default value
  408. //
  409. p = UNKNOWN_TASK;
  410. }
  411. else
  412. #endif
  413. if ( lstrcmpi( p, pName ) == 0
  414. && (fKill || dwNumMatchTasks < dwNumTasks) )
  415. {
  416. fMatch = TRUE;
  417. }
  418. else
  419. {
  420. fMatch = FALSE;
  421. }
  422. //
  423. // get the process id
  424. //
  425. pCounter = (PPERF_COUNTER_BLOCK) ((LPBYTE)pInst + pInst->ByteLength);
  426. if ( fMatch )
  427. {
  428. if ( fKill )
  429. {
  430. //
  431. // Kill process now, do not update pTask array
  432. //
  433. TASK_LIST task;
  434. BOOL fIsInProcess;
  435. task.dwProcessId = *((LPDWORD) ((LPBYTE)pCounter + dwProcessIdCounter));
  436. if ( pszMandatoryModule == NULL ||
  437. ( SUCCEEDED( hres = IsDllInProcess( task.dwProcessId, pszMandatoryModule, &fIsInProcess ) ) &&
  438. fIsInProcess ) )
  439. {
  440. if ( FAILED(hres = KillProcess( &task, TRUE ) ) )
  441. {
  442. break;
  443. }
  444. }
  445. }
  446. else
  447. {
  448. if (lstrlen(p)+1*sizeof(TCHAR) <= sizeof(pTask->ProcessName))
  449. {
  450. lstrcpy( pTask->ProcessName, p );
  451. #if 0
  452. lstrcat( pTask->ProcessName, _T(".exe") );
  453. #endif
  454. }
  455. else
  456. {
  457. pTask->ProcessName[0] = '\0';
  458. }
  459. pTask->flags = 0;
  460. pTask->dwProcessId = *((LPDWORD) ((LPBYTE)pCounter + dwProcessIdCounter));
  461. if (pTask->dwProcessId == 0)
  462. {
  463. pTask->dwProcessId = (DWORD)-2;
  464. }
  465. pTask++;
  466. }
  467. ++dwNumMatchTasks;
  468. }
  469. //
  470. // next process
  471. //
  472. pInst = (PPERF_INSTANCE_DEFINITION) ((LPBYTE)pCounter + pCounter->ByteLength);
  473. }
  474. exit:
  475. if (buf)
  476. {
  477. free( buf );
  478. }
  479. RegCloseKey( hKeyNames );
  480. RegCloseKey( HKEY_PERFORMANCE_DATA );
  481. *pdwNumTasks = dwNumMatchTasks;
  482. return hres;
  483. }
  484. #if 0
  485. BOOL
  486. EnableDebugPriv95(
  487. VOID
  488. )
  489. /*++
  490. Routine Description:
  491. Changes the process's privilege so that kill works properly.
  492. Arguments:
  493. Return Value:
  494. TRUE - success
  495. FALSE - failure
  496. Comments:
  497. Always returns TRUE
  498. --*/
  499. {
  500. return TRUE;
  501. }
  502. #endif
  503. BOOL
  504. EnableDebugPrivNT(
  505. VOID
  506. )
  507. /*++
  508. Routine Description:
  509. Changes the process's privilege so that kill works properly.
  510. Arguments:
  511. Return Value:
  512. TRUE - success
  513. FALSE - failure
  514. --*/
  515. {
  516. HANDLE hToken;
  517. LUID DebugValue;
  518. TOKEN_PRIVILEGES tkp;
  519. //
  520. // Retrieve a handle of the access token
  521. //
  522. if (!OpenProcessToken(GetCurrentProcess(),
  523. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  524. &hToken))
  525. {
  526. return FALSE;
  527. }
  528. //
  529. // Enable the SE_DEBUG_NAME privilege
  530. //
  531. if (!LookupPrivilegeValue((LPTSTR) NULL,
  532. SE_DEBUG_NAME,
  533. &DebugValue))
  534. {
  535. return FALSE;
  536. }
  537. tkp.PrivilegeCount = 1;
  538. tkp.Privileges[0].Luid = DebugValue;
  539. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  540. AdjustTokenPrivileges(hToken,
  541. FALSE,
  542. &tkp,
  543. sizeof(TOKEN_PRIVILEGES),
  544. (PTOKEN_PRIVILEGES) NULL,
  545. (PDWORD) NULL);
  546. //
  547. // The return value of AdjustTokenPrivileges can't be tested
  548. //
  549. if (GetLastError() != ERROR_SUCCESS)
  550. {
  551. return FALSE;
  552. }
  553. return TRUE;
  554. }
  555. BOOLEAN
  556. EnumModulesCallback(
  557. LPVOID pParam,
  558. PMODULE_INFO pModuleInfo
  559. )
  560. /*++
  561. Routine Description:
  562. Called by module enumerator with info on current module
  563. Arguments:
  564. pParam - as specified in the call to EnumModules()
  565. pModuleInfo - module information
  566. Return Value:
  567. TRUE to continue enumeration, FALSE to stop it
  568. --*/
  569. {
  570. #if defined(VERBOSE_DEBUG)
  571. OutputDebugStringA( pModuleInfo->BaseName );
  572. #endif
  573. if ( !_strcmpi( pModuleInfo->BaseName, ((SearchMod*)pParam)->pExeName ) )
  574. {
  575. *((SearchMod*)pParam)->pfFound = TRUE;
  576. #if defined(VERBOSE_DEBUG)
  577. OutputDebugString( _T("found!") );
  578. #endif
  579. return FALSE; // stop enumeration
  580. }
  581. return TRUE;
  582. }
  583. HRESULT
  584. IsDllInProcess(
  585. DWORD dwProcessId,
  586. LPSTR pszName,
  587. LPBOOL pfFound
  588. )
  589. /*++
  590. Routine Description:
  591. Check if a module ( e.g. DLL ) exists in specified process
  592. Arguments:
  593. dwProcessId - process ID to scan for module pszName
  594. pszName - module name to look for, e.g. "wam.dll"
  595. pfFound - updated with TRUE if pszName found in process dwProcessId
  596. valid only if functions succeed.
  597. Return Value:
  598. Status.
  599. --*/
  600. {
  601. HANDLE hProcess;
  602. HRESULT hres = S_OK;
  603. SearchMod sm;
  604. hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, dwProcessId );
  605. if ( hProcess == NULL )
  606. {
  607. return RETURNCODETOHRESULT( GetLastError() );
  608. }
  609. sm.pExeName = pszName;
  610. sm.pfFound= pfFound;
  611. *pfFound = FALSE;
  612. if ( !EnumModules( hProcess, EnumModulesCallback, (LPVOID)&sm ) )
  613. {
  614. hres = E_FAIL;
  615. }
  616. CloseHandle( hProcess );
  617. return hres;
  618. }
  619. HRESULT
  620. KillProcess(
  621. PTASK_LIST tlist,
  622. BOOL fForce
  623. )
  624. {
  625. HANDLE hProcess;
  626. HRESULT hres = S_OK;
  627. DWORD dwRetry;
  628. hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, tlist->dwProcessId );
  629. if ( hProcess == NULL )
  630. {
  631. #if defined(VERBOSE_DEBUG)
  632. OutputDebugString(_T("KillProcess: can't open process"));
  633. #endif
  634. hres = RETURNCODETOHRESULT( GetLastError() );
  635. }
  636. if ( SUCCEEDED(hres) )
  637. {
  638. if (fForce || !tlist->hwnd)
  639. {
  640. if (!TerminateProcess( hProcess, 1 ))
  641. {
  642. //
  643. // If error code is access denied then this is likely due to debugger being attached to process
  644. // so change error code to reflect that. Otherwise error message would be confusing
  645. //
  646. if ( GetLastError() == ERROR_ACCESS_DENIED )
  647. {
  648. hres = RETURNCODETOHRESULT( ERROR_SERVICE_CANNOT_ACCEPT_CTRL );
  649. }
  650. else
  651. {
  652. hres = RETURNCODETOHRESULT( GetLastError() );
  653. }
  654. #if defined(VERBOSE_DEBUG)
  655. OutputDebugString(_T("TerminateProcess failed"));
  656. #endif
  657. }
  658. else
  659. {
  660. #if defined(VERBOSE_DEBUG)
  661. OutputDebugString(_T("TerminateProcess OK"));
  662. #endif
  663. hres = S_OK;
  664. }
  665. }
  666. else
  667. {
  668. #if defined(VERBOSE_DEBUG)
  669. OutputDebugString(_T("KillProcess: post message"));
  670. #endif
  671. PostMessage( tlist->hwnd, WM_CLOSE, 0, 0 );
  672. if ( WaitForSingleObject( hProcess, 5*1000 ) != WAIT_OBJECT_0 )
  673. {
  674. if (!TerminateProcess( hProcess, 1 ))
  675. {
  676. hres = RETURNCODETOHRESULT( GetLastError() );
  677. }
  678. else
  679. {
  680. //
  681. // Verify process is signaled terminated
  682. //
  683. if ( WaitForSingleObject( hProcess, 1*1000 ) != WAIT_OBJECT_0 )
  684. {
  685. hres = RETURNCODETOHRESULT( GetLastError() );
  686. }
  687. else
  688. {
  689. hres = S_OK;
  690. }
  691. }
  692. }
  693. }
  694. }
  695. CloseHandle( hProcess );
  696. if ( SUCCEEDED( hres ) )
  697. {
  698. for ( dwRetry = 0 ; dwRetry < KILL_VERIFY_TIMEOUT ; )
  699. {
  700. //
  701. // Verify process is really terminated by checking we can't open it anymore
  702. // Necessary because killing process while debugger or system exception window is used
  703. // will cause TerminateProcess() to return TRUE even if process not really terminated.
  704. //
  705. Sleep( KILL_VERIFY_DELAY );
  706. dwRetry += KILL_VERIFY_DELAY;
  707. hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, tlist->dwProcessId );
  708. if ( hProcess == NULL )
  709. {
  710. break;
  711. }
  712. else
  713. {
  714. CloseHandle( hProcess );
  715. }
  716. }
  717. if ( dwRetry >= KILL_VERIFY_TIMEOUT )
  718. {
  719. #if defined(VERBOSE_DEBUG)
  720. OutputDebugString(_T("Can reopen process!"));
  721. #endif
  722. hres = RETURNCODETOHRESULT( ERROR_SERVICE_REQUEST_TIMEOUT );
  723. }
  724. }
  725. #if defined(VERBOSE_DEBUG)
  726. if ( FAILED(hres) )
  727. {
  728. OutputDebugString(_T("KillProcess failed"));
  729. }
  730. #endif
  731. return hres;
  732. }
  733. VOID
  734. GetPidFromTitle(
  735. LPDWORD pdwPid,
  736. HWND* phwnd,
  737. LPCTSTR pExeName
  738. )
  739. /*++
  740. Routine Description:
  741. Callback function for window enumeration.
  742. Arguments:
  743. pdwPid - updated with process ID of window matching window name or 0 if window not found
  744. phwnd - updated with window handle matching searched window name
  745. pExeName - window name to look for. Only the # of char present in this name will be
  746. used during checking for a match ( e.g. "inetinfo.exe" will match "inetinfo.exe - Application error"
  747. Return Value:
  748. None. *pdwPid will be 0 if no match is found
  749. --*/
  750. {
  751. SearchWin sw;
  752. sw.pdwPid = pdwPid;
  753. sw.phwnd = phwnd;
  754. sw.pExeName = pExeName;
  755. *pdwPid = 0;
  756. //
  757. // enumerate all windows
  758. //
  759. EnumWindows( (WNDENUMPROC)EnumWindowsProc2, (LPARAM) &sw );
  760. }
  761. BOOL CALLBACK
  762. EnumWindowsProc2(
  763. HWND hwnd,
  764. LPARAM lParam
  765. )
  766. /*++
  767. Routine Description:
  768. Callback function for window enumeration.
  769. Arguments:
  770. hwnd - window handle
  771. lParam - ptr to SearchWin
  772. Return Value:
  773. TRUE - continues the enumeration
  774. --*/
  775. {
  776. DWORD pid = 0;
  777. DWORD i;
  778. TCHAR buf[TITLE_SIZE];
  779. SearchWin* psw = (SearchWin*)lParam;
  780. //
  781. // get the processid for this window
  782. //
  783. if (!GetWindowThreadProcessId( hwnd, &pid ))
  784. {
  785. #if defined(VERBOSE_DEBUG)
  786. OutputDebugString(_T("can't get pid"));
  787. #endif
  788. return TRUE;
  789. }
  790. if (GetWindowText( hwnd, buf, sizeof(buf)/sizeof(TCHAR) ))
  791. {
  792. if ( lstrlen( buf ) > lstrlen( psw->pExeName ) )
  793. {
  794. buf[lstrlen( psw->pExeName )] = _T('\0');
  795. }
  796. #if defined(VERBOSE_DEBUG)
  797. OutputDebugString(buf);
  798. #endif
  799. if ( !lstrcmpi( psw->pExeName, buf ) )
  800. {
  801. #if defined(VERBOSE_DEBUG)
  802. OutputDebugString(_T("Found it!"));
  803. #endif
  804. *psw->phwnd = hwnd;
  805. *psw->pdwPid = pid;
  806. }
  807. }
  808. return TRUE;
  809. }
  810. #if 0
  811. VOID
  812. GetWindowTitles(
  813. PTASK_LIST_ENUM te
  814. )
  815. {
  816. //
  817. // enumerate all windows
  818. //
  819. EnumWindows( (WNDENUMPROC)EnumWindowsProc, (LPARAM) te );
  820. }
  821. BOOL CALLBACK
  822. EnumWindowsProc(
  823. HWND hwnd,
  824. DWORD lParam
  825. )
  826. /*++
  827. Routine Description:
  828. Callback function for window enumeration.
  829. Arguments:
  830. hwnd - window handle
  831. lParam - ** not used **
  832. Return Value:
  833. TRUE - continues the enumeration
  834. --*/
  835. {
  836. DWORD pid = 0;
  837. DWORD i;
  838. TCHAR buf[TITLE_SIZE];
  839. PTASK_LIST_ENUM te = (PTASK_LIST_ENUM)lParam;
  840. PTASK_LIST tlist = te->tlist;
  841. DWORD numTasks = te->numtasks;
  842. //
  843. // get the processid for this window
  844. //
  845. if (!GetWindowThreadProcessId( hwnd, &pid ))
  846. {
  847. return TRUE;
  848. }
  849. //
  850. // look for the task in the task list for this window
  851. //
  852. for (i=0; i<numTasks; i++)
  853. {
  854. if (tlist[i].dwProcessId == pid)
  855. {
  856. tlist[i].hwnd = hwnd;
  857. //
  858. // we found the task so lets try to get the
  859. // window text
  860. //
  861. if (GetWindowText( tlist[i].hwnd, buf, sizeof(buf)/sizeof(TCHAR) ))
  862. {
  863. //
  864. // got it, so lets save it
  865. //
  866. lstrcpy( tlist[i].WindowTitle, buf );
  867. }
  868. break;
  869. }
  870. }
  871. //
  872. // continue the enumeration
  873. //
  874. return TRUE;
  875. }
  876. #if defined(_UNICODE)
  877. //#define _totupper(a) towupper(a)
  878. #else
  879. //#define _totupper(a) _toupper(a)
  880. #endif
  881. BOOL
  882. MatchPattern(
  883. TCHAR* String,
  884. TCHAR* Pattern
  885. )
  886. {
  887. TCHAR c, p, l;
  888. for (; ;) {
  889. switch (p = *Pattern++) {
  890. case 0: // end of pattern
  891. return *String ? FALSE : TRUE; // if end of string TRUE
  892. case _T('*'):
  893. while (*String) { // match zero or more char
  894. if (MatchPattern (String++, Pattern))
  895. return TRUE;
  896. }
  897. return MatchPattern (String, Pattern);
  898. case _T('?'):
  899. if (*String++ == 0) // match any one char
  900. return FALSE; // not end of string
  901. break;
  902. case _T('['):
  903. if ( (c = *String++) == 0) // match char set
  904. return FALSE; // syntax
  905. c = _totupper(c);
  906. l = 0;
  907. while (p = *Pattern++) {
  908. if (p == _T(']')) // if end of char set, then
  909. return FALSE; // no match found
  910. if (p == _T('-')) { // check a range of chars?
  911. p = *Pattern; // get high limit of range
  912. if (p == 0 || p == _T(']'))
  913. return FALSE; // syntax
  914. if (c >= l && c <= p)
  915. break; // if in range, move on
  916. }
  917. l = p;
  918. if (c == p) // if char matches this element
  919. break; // move on
  920. }
  921. while (p && p != _T(']')) // got a match in char set
  922. p = *Pattern++; // skip to end of set
  923. break;
  924. default:
  925. c = *String++;
  926. if (_totupper(c) != p) // check for exact char
  927. return FALSE; // not a match
  928. break;
  929. }
  930. }
  931. }
  932. #endif