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.

1052 lines
25 KiB

  1. /*++
  2. Copyright (c) 1994-1998 Microsoft Corporation
  3. Module Name:
  4. common.c
  5. Abstract:
  6. This module contains common apis used by tlist & kill.
  7. Author:
  8. Wesley Witt (wesw) 20-May-1994
  9. Environment:
  10. User Mode
  11. --*/
  12. #include "pch.h"
  13. #pragma hdrstop
  14. //
  15. // global variables
  16. //
  17. PUCHAR CommonLargeBuffer;
  18. ULONG CommonLargeBufferSize = 64*1024;
  19. //
  20. // prototypes
  21. //
  22. BOOL CALLBACK
  23. EnumWindowsProc(
  24. HWND hwnd,
  25. LPARAM lParam
  26. );
  27. BOOL CALLBACK
  28. EnumWindowStationsFunc(
  29. LPSTR lpstr,
  30. LPARAM lParam
  31. );
  32. BOOL CALLBACK
  33. EnumDesktopsFunc(
  34. LPSTR lpstr,
  35. LPARAM lParam
  36. );
  37. DWORD
  38. GetServiceProcessInfo(
  39. LPENUM_SERVICE_STATUS_PROCESS* ppInfo
  40. )
  41. /*++
  42. Routine Description:
  43. Provides an API for getting a list of process information for Win 32
  44. services that are running at the time of the API call.
  45. Arguments:
  46. ppInfo - address of a pointer to return the information.
  47. *ppInfo points to memory allocated with malloc.
  48. Return Value:
  49. Number of ENUM_SERVICE_STATUS_PROCESS structures pointed at by *ppInfo.
  50. --*/
  51. {
  52. DWORD dwNumServices = 0;
  53. SC_HANDLE hScm;
  54. typedef
  55. BOOL
  56. (__stdcall * PFN_ENUMSERVICSESTATUSEXA) (
  57. SC_HANDLE hSCManager,
  58. SC_ENUM_TYPE InfoLevel,
  59. DWORD dwServiceType,
  60. DWORD dwServiceState,
  61. LPBYTE lpServices,
  62. DWORD cbBufSize,
  63. LPDWORD pcbBytesNeeded,
  64. LPDWORD lpServicesReturned,
  65. LPDWORD lpResumeHandle,
  66. LPCSTR pszGroupName);
  67. PFN_ENUMSERVICSESTATUSEXA p_EnumServicesStatusEx;
  68. HINSTANCE hAdv = LoadLibrary("advapi32.dll");
  69. // Initialize the output parmeter.
  70. *ppInfo = NULL;
  71. if (hAdv)
  72. {
  73. p_EnumServicesStatusEx = (PFN_ENUMSERVICSESTATUSEXA)
  74. GetProcAddress(hAdv, "EnumServicesStatusExA");
  75. if (!p_EnumServicesStatusEx)
  76. {
  77. return 0;
  78. }
  79. } else {
  80. return 0;
  81. }
  82. // Connect to the service controller.
  83. //
  84. hScm = OpenSCManager(
  85. NULL,
  86. NULL,
  87. SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
  88. if (hScm) {
  89. LPENUM_SERVICE_STATUS_PROCESS pInfo = NULL;
  90. DWORD cbInfo = 4 * 1024;
  91. DWORD cbExtraNeeded = 0;
  92. DWORD dwErr;
  93. DWORD dwResume;
  94. DWORD cLoop = 0;
  95. const DWORD cLoopMax = 2;
  96. // First pass through the loop allocates from an initial guess. (4K)
  97. // If that isn't sufficient, we make another pass and allocate
  98. // what is actually needed. (We only go through the loop a
  99. // maximum of two times.)
  100. //
  101. do {
  102. free (pInfo);
  103. cbInfo += cbExtraNeeded;
  104. pInfo = (LPENUM_SERVICE_STATUS_PROCESS)malloc(cbInfo);
  105. if (!pInfo) {
  106. dwErr = ERROR_OUTOFMEMORY;
  107. break;
  108. }
  109. dwErr = ERROR_SUCCESS;
  110. dwResume = 0;
  111. if (!p_EnumServicesStatusEx(
  112. hScm,
  113. SC_ENUM_PROCESS_INFO,
  114. SERVICE_WIN32,
  115. SERVICE_ACTIVE,
  116. (LPBYTE)pInfo,
  117. cbInfo,
  118. &cbExtraNeeded,
  119. &dwNumServices,
  120. &dwResume,
  121. NULL)) {
  122. dwErr = GetLastError();
  123. }
  124. }
  125. while ((ERROR_MORE_DATA == dwErr) && (++cLoop < cLoopMax));
  126. if ((ERROR_SUCCESS == dwErr) && dwNumServices) {
  127. *ppInfo = pInfo;
  128. } else {
  129. free (pInfo);
  130. dwNumServices = 0;
  131. }
  132. CloseServiceHandle(hScm);
  133. }
  134. return dwNumServices;
  135. }
  136. DWORD
  137. GetTaskListEx(
  138. PTASK_LIST pTask,
  139. DWORD dwNumTasks,
  140. BOOL fThreadInfo,
  141. DWORD dwNumServices,
  142. const ENUM_SERVICE_STATUS_PROCESS* pServiceInfo
  143. )
  144. /*++
  145. Routine Description:
  146. Provides an API for getting a list of tasks running at the time of the
  147. API call. This function uses internal NT apis and data structures. This
  148. api is MUCH faster that the non-internal version that uses the registry.
  149. Arguments:
  150. pTask - Array of TASK_LIST structures to fill.
  151. dwNumTasks - Maximum number of tasks that the pTask array can hold.
  152. fThreadInfo - TRUE if thread information is desired.
  153. dwNumServices - Maximum number of entries in pServiceInfo.
  154. pServiceInfo - Array of service status structures to reference
  155. for supporting services in processes.
  156. Return Value:
  157. Number of tasks placed into the pTask array.
  158. --*/
  159. {
  160. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  161. NTSTATUS status;
  162. ANSI_STRING pname;
  163. PCHAR p;
  164. ULONG TotalOffset;
  165. ULONG totalTasks = 0;
  166. retry:
  167. if (CommonLargeBuffer == NULL) {
  168. CommonLargeBuffer = VirtualAlloc (NULL,
  169. CommonLargeBufferSize,
  170. MEM_COMMIT,
  171. PAGE_READWRITE);
  172. if (CommonLargeBuffer == NULL) {
  173. return 0;
  174. }
  175. }
  176. status = NtQuerySystemInformation(
  177. SystemProcessInformation,
  178. CommonLargeBuffer,
  179. CommonLargeBufferSize,
  180. NULL
  181. );
  182. if (status == STATUS_INFO_LENGTH_MISMATCH) {
  183. CommonLargeBufferSize += 8192;
  184. VirtualFree (CommonLargeBuffer, 0, MEM_RELEASE);
  185. CommonLargeBuffer = NULL;
  186. goto retry;
  187. }
  188. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) CommonLargeBuffer;
  189. TotalOffset = 0;
  190. while (TRUE) {
  191. pname.Buffer = NULL;
  192. if ( ProcessInfo->ImageName.Buffer ) {
  193. RtlUnicodeStringToAnsiString(&pname,(PUNICODE_STRING)&ProcessInfo->ImageName,TRUE);
  194. if (pname.Buffer) {
  195. p = strrchr(pname.Buffer,'\\');
  196. if ( p ) {
  197. p++;
  198. }
  199. else {
  200. p = pname.Buffer;
  201. }
  202. } else {
  203. p = "";
  204. }
  205. }
  206. else {
  207. p = "System Process";
  208. }
  209. strncpy( pTask->ProcessName, p, PROCESS_SIZE );
  210. pTask->ProcessName[PROCESS_SIZE-1] = '\0';
  211. pTask->flags = 0;
  212. pTask->dwProcessId = (DWORD)(DWORD_PTR)ProcessInfo->UniqueProcessId;
  213. pTask->dwInheritedFromProcessId = (DWORD)(DWORD_PTR)ProcessInfo->InheritedFromUniqueProcessId;
  214. pTask->CreateTime.QuadPart = (ULONGLONG)ProcessInfo->CreateTime.QuadPart;
  215. pTask->PeakVirtualSize = ProcessInfo->PeakVirtualSize;
  216. pTask->VirtualSize = ProcessInfo->VirtualSize;
  217. pTask->PageFaultCount = ProcessInfo->PageFaultCount;
  218. pTask->PeakWorkingSetSize = ProcessInfo->PeakWorkingSetSize;
  219. pTask->WorkingSetSize = ProcessInfo->WorkingSetSize;
  220. pTask->NumberOfThreads = ProcessInfo->NumberOfThreads;
  221. if (fThreadInfo) {
  222. if (pTask->pThreadInfo = malloc(pTask->NumberOfThreads * sizeof(THREAD_INFO))) {
  223. UINT nThread = pTask->NumberOfThreads;
  224. PTHREAD_INFO pThreadInfo = pTask->pThreadInfo;
  225. PSYSTEM_THREAD_INFORMATION pSysThreadInfo =
  226. (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
  227. while (nThread--) {
  228. pThreadInfo->ThreadState = pSysThreadInfo->ThreadState;
  229. pThreadInfo->UniqueThread = pSysThreadInfo->ClientId.UniqueThread;
  230. pThreadInfo++;
  231. pSysThreadInfo++;
  232. }
  233. }
  234. } else {
  235. pTask->pThreadInfo = NULL;
  236. }
  237. pTask->MtsPackageNames[0] = 0;
  238. // Initialize the ServiceNames if this task hosts any.
  239. //
  240. *pTask->ServiceNames = 0;
  241. if (dwNumServices)
  242. {
  243. // For each service with this process id, append it's service
  244. // name to the buffer. Separate each with a comma.
  245. //
  246. BOOL fFirstTime = TRUE;
  247. DWORD iSvc;
  248. size_t cchRemain = SERVICENAMES_SIZE - 1;
  249. size_t cch;
  250. for (iSvc = 0; iSvc < dwNumServices; iSvc++) {
  251. if (pTask->dwProcessId == pServiceInfo[iSvc].ServiceStatusProcess.dwProcessId) {
  252. cch = strlen(pServiceInfo[iSvc].lpServiceName);
  253. if (fFirstTime) {
  254. fFirstTime = FALSE;
  255. strncpy(
  256. pTask->ServiceNames,
  257. pServiceInfo[iSvc].lpServiceName,
  258. cchRemain);
  259. // strncpy may not terminate the string if
  260. // cchRemain <= cch so we do it regardless.
  261. //
  262. pTask->ServiceNames[cchRemain] = 0;
  263. } else if (cchRemain > 1) { // ensure room for the comma
  264. strncat(
  265. pTask->ServiceNames,
  266. ",",
  267. cchRemain--);
  268. strncat(
  269. pTask->ServiceNames,
  270. pServiceInfo[iSvc].lpServiceName,
  271. cchRemain);
  272. }
  273. // Counts are unsigned so we have to check before
  274. // subtracting.
  275. //
  276. if (cchRemain < cch) {
  277. // No more room for any more.
  278. break;
  279. } else {
  280. cchRemain -= cch;
  281. }
  282. }
  283. }
  284. }
  285. pTask++;
  286. totalTasks++;
  287. if (totalTasks == dwNumTasks) {
  288. break;
  289. }
  290. if (ProcessInfo->NextEntryOffset == 0) {
  291. break;
  292. }
  293. TotalOffset += ProcessInfo->NextEntryOffset;
  294. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&CommonLargeBuffer[TotalOffset];
  295. }
  296. return totalTasks;
  297. }
  298. DWORD
  299. GetTaskList(
  300. PTASK_LIST pTask,
  301. DWORD dwNumTasks
  302. )
  303. {
  304. return GetTaskListEx(pTask, dwNumTasks, FALSE, 0, NULL);
  305. }
  306. void
  307. AddMtsPackageNames(
  308. PTASK_LIST Tasks,
  309. DWORD NumTasks
  310. )
  311. {
  312. HRESULT Hr;
  313. IMtsGrp* MtsGroup;
  314. long Packages;
  315. long i;
  316. if ((Hr = CoInitialize(NULL)) != S_OK) {
  317. return;
  318. }
  319. if ((Hr = CoCreateInstance(&CLSID_MtsGrp, NULL, CLSCTX_ALL,
  320. &IID_IMtsGrp, (void **)&MtsGroup)) != S_OK) {
  321. goto Uninit;
  322. }
  323. if ((Hr = MtsGroup->lpVtbl->Refresh(MtsGroup)) != S_OK ||
  324. (Hr = MtsGroup->lpVtbl->get_Count(MtsGroup, &Packages)) != S_OK) {
  325. goto ReleaseGroup;
  326. }
  327. for (i = 0; i < Packages; i++) {
  328. IUnknown* Unk;
  329. IMtsEvents* Events;
  330. BSTR Name;
  331. DWORD Pid;
  332. DWORD TaskIdx;
  333. if ((Hr = MtsGroup->lpVtbl->Item(MtsGroup, i, &Unk)) != S_OK) {
  334. continue;
  335. }
  336. Hr = Unk->lpVtbl->QueryInterface(Unk, &IID_IMtsEvents,
  337. (void **)&Events);
  338. Unk->lpVtbl->Release(Unk);
  339. if (Hr != S_OK) {
  340. continue;
  341. }
  342. Hr = Events->lpVtbl->GetProcessID(Events, (PLONG)&Pid);
  343. if (Hr == S_OK) {
  344. Hr = Events->lpVtbl->get_PackageName(Events, &Name);
  345. }
  346. Events->lpVtbl->Release(Events);
  347. if (Hr != S_OK) {
  348. continue;
  349. }
  350. for (TaskIdx = 0; TaskIdx < NumTasks; TaskIdx++) {
  351. if (Tasks[TaskIdx].dwProcessId == Pid) {
  352. break;
  353. }
  354. }
  355. if (TaskIdx < NumTasks) {
  356. PSTR Str;
  357. int Conv;
  358. Str = Tasks[TaskIdx].MtsPackageNames +
  359. strlen(Tasks[TaskIdx].MtsPackageNames);
  360. if (Str > Tasks[TaskIdx].MtsPackageNames) {
  361. *Str++ = ',';
  362. }
  363. Conv = WideCharToMultiByte(
  364. CP_ACP,
  365. 0,
  366. Name,
  367. -1,
  368. Str,
  369. MTS_PACKAGE_NAMES_SIZE -
  370. (DWORD)(Str - Tasks[TaskIdx].MtsPackageNames) - 2,
  371. NULL,
  372. NULL
  373. );
  374. SysFreeString(Name);
  375. if (Conv == 0 && Str > Tasks[TaskIdx].MtsPackageNames &&
  376. *(Str - 1) == ',') {
  377. *(Str - 1) = 0;
  378. }
  379. }
  380. }
  381. ReleaseGroup:
  382. MtsGroup->lpVtbl->Release(MtsGroup);
  383. Uninit:
  384. CoUninitialize();
  385. return;
  386. }
  387. BOOL
  388. DetectOrphans(
  389. PTASK_LIST pTask,
  390. DWORD dwNumTasks
  391. )
  392. {
  393. DWORD i, j;
  394. BOOL Result = FALSE;
  395. for (i=0; i<dwNumTasks; i++) {
  396. if (pTask[i].dwInheritedFromProcessId != 0) {
  397. for (j=0; j<dwNumTasks; j++) {
  398. if (i != j && pTask[i].dwInheritedFromProcessId == pTask[j].dwProcessId) {
  399. if (pTask[i].CreateTime.QuadPart <= pTask[j].CreateTime.QuadPart) {
  400. pTask[i].dwInheritedFromProcessId = 0;
  401. Result = TRUE;
  402. }
  403. break;
  404. }
  405. }
  406. }
  407. }
  408. return Result;
  409. }
  410. BOOL
  411. EnableDebugPriv(
  412. VOID
  413. )
  414. /*++
  415. Routine Description:
  416. Changes the tlist process's privilige so that kill works properly.
  417. Arguments:
  418. Return Value:
  419. TRUE - success
  420. FALSE - failure
  421. --*/
  422. {
  423. HANDLE hToken;
  424. LUID DebugValue;
  425. TOKEN_PRIVILEGES tkp;
  426. //
  427. // Retrieve a handle of the access token
  428. //
  429. if (!OpenProcessToken(GetCurrentProcess(),
  430. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  431. &hToken)) {
  432. printf("OpenProcessToken failed with %d\n", GetLastError());
  433. return FALSE;
  434. }
  435. //
  436. // Enable the SE_DEBUG_NAME privilege or disable
  437. // all privileges, depending on the fEnable flag.
  438. //
  439. if (!LookupPrivilegeValue((LPSTR) NULL,
  440. SE_DEBUG_NAME,
  441. &DebugValue)) {
  442. printf("LookupPrivilegeValue failed with %d\n", GetLastError());
  443. return FALSE;
  444. }
  445. tkp.PrivilegeCount = 1;
  446. tkp.Privileges[0].Luid = DebugValue;
  447. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  448. if (!AdjustTokenPrivileges(
  449. hToken,
  450. FALSE,
  451. &tkp,
  452. sizeof(TOKEN_PRIVILEGES),
  453. (PTOKEN_PRIVILEGES) NULL,
  454. (PDWORD) NULL)) {
  455. //
  456. // The return value of AdjustTokenPrivileges be texted
  457. //
  458. printf("AdjustTokenPrivileges failed with %d\n", GetLastError());
  459. return FALSE;
  460. }
  461. return TRUE;
  462. }
  463. BOOL
  464. KillProcess(
  465. PTASK_LIST tlist,
  466. BOOL fForce
  467. )
  468. {
  469. HANDLE hProcess, hProcess1;
  470. HDESK hdeskSave;
  471. HDESK hdesk;
  472. HWINSTA hwinsta;
  473. HWINSTA hwinstaSave;
  474. if (fForce || !tlist->hwnd) {
  475. hProcess1 = OpenProcess( PROCESS_ALL_ACCESS, FALSE, tlist->dwProcessId );
  476. if (hProcess1) {
  477. hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, tlist->dwProcessId );
  478. if (hProcess == NULL) {
  479. CloseHandle(hProcess1);
  480. return FALSE;
  481. }
  482. if (!TerminateProcess( hProcess, 1 )) {
  483. CloseHandle( hProcess );
  484. CloseHandle( hProcess1 );
  485. return FALSE;
  486. }
  487. CloseHandle( hProcess );
  488. CloseHandle( hProcess1 );
  489. return TRUE;
  490. }
  491. }
  492. //
  493. // save the current windowstation
  494. //
  495. hwinstaSave = GetProcessWindowStation();
  496. //
  497. // save the current desktop
  498. //
  499. hdeskSave = GetThreadDesktop( GetCurrentThreadId() );
  500. //
  501. // open the windowstation
  502. //
  503. hwinsta = OpenWindowStation( tlist->lpWinsta, FALSE, MAXIMUM_ALLOWED );
  504. if (!hwinsta) {
  505. return FALSE;
  506. }
  507. //
  508. // change the context to the new windowstation
  509. //
  510. SetProcessWindowStation( hwinsta );
  511. //
  512. // open the desktop
  513. //
  514. hdesk = OpenDesktop( tlist->lpDesk, 0, FALSE, MAXIMUM_ALLOWED );
  515. if (!hdesk) {
  516. return FALSE;
  517. }
  518. //
  519. // change the context to the new desktop
  520. //
  521. SetThreadDesktop( hdesk );
  522. //
  523. // kill the process
  524. //
  525. PostMessage( tlist->hwnd, WM_CLOSE, 0, 0 );
  526. //
  527. // restore the previous desktop
  528. //
  529. if (hdesk != hdeskSave) {
  530. SetThreadDesktop( hdeskSave );
  531. CloseDesktop( hdesk );
  532. }
  533. //
  534. // restore the context to the previous windowstation
  535. //
  536. if (hwinsta != hwinstaSave) {
  537. SetProcessWindowStation( hwinstaSave );
  538. CloseWindowStation( hwinsta );
  539. }
  540. return TRUE;
  541. }
  542. VOID
  543. GetWindowTitles(
  544. PTASK_LIST_ENUM te
  545. )
  546. {
  547. //
  548. // enumerate all windows and try to get the window
  549. // titles for each task
  550. //
  551. EnumWindowStations( EnumWindowStationsFunc, (LPARAM)te );
  552. }
  553. BOOL CALLBACK
  554. EnumWindowStationsFunc(
  555. LPSTR lpstr,
  556. LPARAM lParam
  557. )
  558. /*++
  559. Routine Description:
  560. Callback function for windowstation enumeration.
  561. Arguments:
  562. lpstr - windowstation name
  563. lParam - ** not used **
  564. Return Value:
  565. TRUE - continues the enumeration
  566. --*/
  567. {
  568. PTASK_LIST_ENUM te = (PTASK_LIST_ENUM)lParam;
  569. HWINSTA hwinsta;
  570. HWINSTA hwinstaSave;
  571. //
  572. // open the windowstation
  573. //
  574. hwinsta = OpenWindowStation( lpstr, FALSE, MAXIMUM_ALLOWED );
  575. if (!hwinsta) {
  576. return FALSE;
  577. }
  578. //
  579. // save the current windowstation
  580. //
  581. hwinstaSave = GetProcessWindowStation();
  582. //
  583. // change the context to the new windowstation
  584. //
  585. SetProcessWindowStation( hwinsta );
  586. te->lpWinsta = _strdup( lpstr );
  587. //
  588. // enumerate all the desktops for this windowstation
  589. //
  590. EnumDesktops( hwinsta, EnumDesktopsFunc, lParam );
  591. //
  592. // restore the context to the previous windowstation
  593. //
  594. if (hwinsta != hwinstaSave) {
  595. SetProcessWindowStation( hwinstaSave );
  596. CloseWindowStation( hwinsta );
  597. }
  598. //
  599. // continue the enumeration
  600. //
  601. return TRUE;
  602. }
  603. BOOL CALLBACK
  604. EnumMessageWindows(
  605. WNDENUMPROC lpEnumFunc,
  606. LPARAM lParam
  607. )
  608. /*++
  609. Routine Description:
  610. Enumarates message windows (which are not enumarated by EnumWindows)
  611. Arguments:
  612. lpEnumFunc - Callback function
  613. lParam - Caller data
  614. Return Value:
  615. TRUE
  616. --*/
  617. {
  618. HWND hwnd = NULL;
  619. do {
  620. hwnd = FindWindowEx(HWND_MESSAGE, hwnd, NULL, NULL);
  621. if (hwnd != NULL) {
  622. if (!(*lpEnumFunc)(hwnd, lParam)) {
  623. break;
  624. }
  625. }
  626. } while (hwnd != NULL);
  627. return TRUE;
  628. }
  629. BOOL CALLBACK
  630. EnumDesktopsFunc(
  631. LPSTR lpstr,
  632. LPARAM lParam
  633. )
  634. /*++
  635. Routine Description:
  636. Callback function for desktop enumeration.
  637. Arguments:
  638. lpstr - desktop name
  639. lParam - ** not used **
  640. Return Value:
  641. TRUE - continues the enumeration
  642. --*/
  643. {
  644. PTASK_LIST_ENUM te = (PTASK_LIST_ENUM)lParam;
  645. HDESK hdeskSave;
  646. HDESK hdesk;
  647. //
  648. // open the desktop
  649. //
  650. hdesk = OpenDesktop( lpstr, 0, FALSE, MAXIMUM_ALLOWED );
  651. if (!hdesk) {
  652. return FALSE;
  653. }
  654. //
  655. // save the current desktop
  656. //
  657. hdeskSave = GetThreadDesktop( GetCurrentThreadId() );
  658. //
  659. // change the context to the new desktop
  660. //
  661. SetThreadDesktop( hdesk );
  662. te->lpDesk = _strdup( lpstr );
  663. //
  664. // enumerate all windows in the new desktop
  665. //
  666. ((PTASK_LIST_ENUM)lParam)->bFirstLoop = TRUE;
  667. EnumWindows( (WNDENUMPROC)EnumWindowsProc, lParam );
  668. EnumMessageWindows( (WNDENUMPROC)EnumWindowsProc, lParam );
  669. ((PTASK_LIST_ENUM)lParam)->bFirstLoop = FALSE;
  670. EnumWindows( (WNDENUMPROC)EnumWindowsProc, lParam );
  671. EnumMessageWindows( (WNDENUMPROC)EnumWindowsProc, lParam );
  672. //
  673. // restore the previous desktop
  674. //
  675. if (hdesk != hdeskSave) {
  676. SetThreadDesktop( hdeskSave );
  677. CloseDesktop( hdesk );
  678. }
  679. return TRUE;
  680. }
  681. BOOL CALLBACK
  682. EnumWindowsProc(
  683. HWND hwnd,
  684. LPARAM lParam
  685. )
  686. /*++
  687. Routine Description:
  688. Callback function for window enumeration.
  689. Arguments:
  690. hwnd - window handle
  691. lParam - pte
  692. Return Value:
  693. TRUE - continues the enumeration
  694. --*/
  695. {
  696. DWORD pid = 0;
  697. DWORD i;
  698. CHAR buf[TITLE_SIZE];
  699. PTASK_LIST_ENUM te = (PTASK_LIST_ENUM)lParam;
  700. PTASK_LIST tlist = te->tlist;
  701. DWORD numTasks = te->numtasks;
  702. //
  703. // Use try/except block when enumerating windows,
  704. // as a window may be destroyed by another thread
  705. // when being enumerated.
  706. //
  707. try {
  708. //
  709. // get the processid for this window
  710. //
  711. if (!GetWindowThreadProcessId( hwnd, &pid )) {
  712. return TRUE;
  713. }
  714. if ((GetWindow( hwnd, GW_OWNER )) ||
  715. (!(GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE)) && te->bFirstLoop) {
  716. //
  717. // not a top level window
  718. //
  719. return TRUE;
  720. }
  721. //
  722. // look for the task in the task list for this window
  723. // If this is the second time let invisible windows through if we don't
  724. // have a window already
  725. //
  726. for (i=0; i<numTasks; i++) {
  727. if ((tlist[i].dwProcessId == pid) && (te->bFirstLoop || (tlist[i].hwnd == 0))) {
  728. tlist[i].hwnd = hwnd;
  729. tlist[i].lpWinsta = te->lpWinsta;
  730. tlist[i].lpDesk = te->lpDesk;
  731. //
  732. // we found the task no lets try to get the
  733. // window text
  734. //
  735. if (GetWindowText( tlist[i].hwnd, buf, sizeof(buf) )) {
  736. //
  737. // go it, so lets save it
  738. //
  739. strcpy( tlist[i].WindowTitle, buf );
  740. }
  741. break;
  742. }
  743. }
  744. } except(EXCEPTION_EXECUTE_HANDLER) {
  745. }
  746. //
  747. // continue the enumeration
  748. //
  749. return TRUE;
  750. }
  751. BOOL
  752. MatchPattern(
  753. PUCHAR String,
  754. PUCHAR Pattern
  755. )
  756. {
  757. INT c, p, l;
  758. for (; ;) {
  759. switch (p = *Pattern++) {
  760. case 0: // end of pattern
  761. return *String ? FALSE : TRUE; // if end of string TRUE
  762. case '*':
  763. while (*String) { // match zero or more char
  764. if (MatchPattern (String++, Pattern))
  765. return TRUE;
  766. }
  767. return MatchPattern (String, Pattern);
  768. case '?':
  769. if (*String++ == 0) // match any one char
  770. return FALSE; // not end of string
  771. break;
  772. case '[':
  773. if ( (c = *String++) == 0) // match char set
  774. return FALSE; // syntax
  775. c = toupper(c);
  776. l = 0;
  777. while (p = *Pattern++) {
  778. if (p == ']') // if end of char set, then
  779. return FALSE; // no match found
  780. if (p == '-') { // check a range of chars?
  781. p = *Pattern; // get high limit of range
  782. if (p == 0 || p == ']')
  783. return FALSE; // syntax
  784. if (c >= l && c <= p)
  785. break; // if in range, move on
  786. }
  787. l = p;
  788. if (c == p) // if char matches this element
  789. break; // move on
  790. }
  791. while (p && p != ']') // got a match in char set
  792. p = *Pattern++; // skip to end of set
  793. break;
  794. default:
  795. c = *String++;
  796. if (toupper(c) != p) // check for exact char
  797. return FALSE; // not a match
  798. break;
  799. }
  800. }
  801. }
  802. BOOL
  803. EmptyProcessWorkingSet(
  804. DWORD pid
  805. )
  806. {
  807. HANDLE hProcess;
  808. SIZE_T dwMinimumWorkingSetSize;
  809. SIZE_T dwMaximumWorkingSetSize;
  810. hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid );
  811. if (hProcess == NULL) {
  812. return FALSE;
  813. }
  814. if (!GetProcessWorkingSetSize(
  815. hProcess,
  816. &dwMinimumWorkingSetSize,
  817. &dwMaximumWorkingSetSize
  818. )) {
  819. CloseHandle( hProcess );
  820. return FALSE;
  821. }
  822. SetProcessWorkingSetSize( hProcess, 0xffffffff, 0xffffffff );
  823. CloseHandle( hProcess );
  824. return TRUE;
  825. }
  826. BOOL
  827. EmptySystemWorkingSet(
  828. VOID
  829. )
  830. {
  831. SYSTEM_FILECACHE_INFORMATION info;
  832. NTSTATUS status;
  833. info.MinimumWorkingSet = 0xffffffff;
  834. info.MaximumWorkingSet = 0xffffffff;
  835. if (!NT_SUCCESS (status = NtSetSystemInformation(
  836. SystemFileCacheInformation,
  837. &info,
  838. sizeof (info)))) {
  839. return FALSE;
  840. }
  841. return TRUE;
  842. }