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.

1192 lines
26 KiB

  1. //*************************************************************
  2. // File name: delprof.c
  3. //
  4. // Description: Utility to delete user profiles
  5. //
  6. //
  7. // Microsoft Confidential
  8. // Copyright (c) Microsoft Corporation 1996
  9. // All rights reserved
  10. //
  11. //*************************************************************
  12. #include <windows.h>
  13. #include <tchar.h>
  14. #include <stdio.h>
  15. #include <locale.h>
  16. #include "delprof.h"
  17. #include "userenv.h"
  18. //
  19. // Globals
  20. //
  21. BOOL bQuiet;
  22. BOOL bIgnoreErrors;
  23. BOOL bPromptBeforeDelete;
  24. BOOL bLocalComputer = FALSE;
  25. TCHAR szComputerName[MAX_PATH];
  26. TCHAR szSystemRoot[2*MAX_PATH];
  27. TCHAR szSystemDrive[2*MAX_PATH];
  28. LONG lDays;
  29. HINSTANCE hInst;
  30. LPDELETEITEM lpDeleteList;
  31. LONG lCurrentDateInDays;
  32. //*************************************************************
  33. //
  34. // Usage()
  35. //
  36. // Purpose: prints the usage info
  37. //
  38. // Parameters: void
  39. //
  40. // Return: void
  41. //
  42. // Comments:
  43. //
  44. // History: Date Author Comment
  45. // 5/18/96 ericflo Created
  46. //
  47. //*************************************************************
  48. void Usage (void)
  49. {
  50. TCHAR szTemp[100];
  51. LoadString (hInst, IDS_USAGE1, szTemp, 100);
  52. _tprintf(szTemp);
  53. LoadString (hInst, IDS_USAGE2, szTemp, 100);
  54. _tprintf(szTemp);
  55. LoadString (hInst, IDS_USAGE3, szTemp, 100);
  56. _tprintf(szTemp);
  57. LoadString (hInst, IDS_USAGE4, szTemp, 100);
  58. _tprintf(szTemp);
  59. LoadString (hInst, IDS_USAGE5, szTemp, 100);
  60. _tprintf(szTemp);
  61. LoadString (hInst, IDS_USAGE6, szTemp, 100);
  62. _tprintf(szTemp);
  63. LoadString (hInst, IDS_USAGE7, szTemp, 100);
  64. _tprintf(szTemp);
  65. LoadString (hInst, IDS_USAGE8, szTemp, 100);
  66. _tprintf(szTemp);
  67. LoadString (hInst, IDS_USAGE9, szTemp, 100);
  68. _tprintf(szTemp);
  69. }
  70. //*************************************************************
  71. //
  72. // InitializeGlobals()
  73. //
  74. // Purpose: Initializes the global variables
  75. //
  76. // Parameters: void
  77. //
  78. // Return: void
  79. //
  80. // Comments:
  81. //
  82. // History: Date Author Comment
  83. // 5/18/96 ericflo Created
  84. //
  85. //*************************************************************
  86. void InitializeGlobals (void)
  87. {
  88. OSVERSIONINFO ver;
  89. SYSTEMTIME systime;
  90. //
  91. // Initialize global variables
  92. //
  93. bQuiet = FALSE;
  94. bIgnoreErrors = FALSE;
  95. bPromptBeforeDelete = FALSE;
  96. szComputerName[0] = TEXT('\0');
  97. lDays = 0;
  98. lpDeleteList = NULL;
  99. setlocale(LC_ALL,"");
  100. hInst = GetModuleHandle(TEXT("delprof.exe"));
  101. GetLocalTime (&systime);
  102. lCurrentDateInDays = gdate_dmytoday(systime.wYear, systime.wMonth, systime.wDay);
  103. }
  104. //*************************************************************
  105. //
  106. // CheckGlobals()
  107. //
  108. // Purpose: Checks the global variables
  109. //
  110. // Parameters: void
  111. //
  112. // Return: void
  113. //
  114. // Comments:
  115. //
  116. // History: Date Author Comment
  117. // 5/18/96 ericflo Created
  118. //
  119. //*************************************************************
  120. void CheckGlobals (void)
  121. {
  122. DWORD dwSize;
  123. TCHAR szTemp[MAX_PATH];
  124. //
  125. // If szComputerName is still NULL, fill in the computer name
  126. // we're running on.
  127. //
  128. if (szComputerName[0] == TEXT('\0')) {
  129. szComputerName[0] = TEXT('\\');
  130. szComputerName[1] = TEXT('\\');
  131. dwSize = MAX_PATH - 2;
  132. GetComputerName (szComputerName+2, &dwSize);
  133. bLocalComputer = TRUE;
  134. } else {
  135. //
  136. // Make sure that the computer name starts with \\
  137. //
  138. if (szComputerName[0] != TEXT('\\')) {
  139. szTemp[0] = TEXT('\\');
  140. szTemp[1] = TEXT('\\');
  141. _tcscpy(szTemp+2, szComputerName);
  142. _tcscpy(szComputerName, szTemp);
  143. }
  144. }
  145. //
  146. // If the user has requested to run in Quiet mode,
  147. // then we turn off the prompt on every delete option.
  148. //
  149. if (bQuiet) {
  150. bPromptBeforeDelete = FALSE;
  151. }
  152. }
  153. //*************************************************************
  154. //
  155. // ParseCommandLine()
  156. //
  157. // Purpose: Parses the command line
  158. //
  159. // Parameters: lpCommandLine - Command line
  160. //
  161. // Return: TRUE if successful
  162. // FALSE if an error occurs
  163. //
  164. // Comments:
  165. //
  166. // History: Date Author Comment
  167. // 5/18/96 ericflo Created
  168. //
  169. //*************************************************************
  170. BOOL ParseCommandLine (LPTSTR lpCommandLine)
  171. {
  172. LPTSTR lpTemp;
  173. TCHAR szDays[32];
  174. //
  175. // Check for NULL command line
  176. //
  177. if (!lpCommandLine || !*lpCommandLine)
  178. return TRUE;
  179. //
  180. // Find the executable name
  181. //
  182. while (*lpCommandLine && (_tcsncmp(lpCommandLine, TEXT("delprof"), 7) != 0)) {
  183. lpCommandLine++;
  184. }
  185. if (!*lpCommandLine) {
  186. return TRUE;
  187. }
  188. //
  189. // Find the first argument
  190. //
  191. while (*lpCommandLine && ((*lpCommandLine != TEXT(' ')) &&
  192. (*lpCommandLine != TEXT('/')) &&
  193. (*lpCommandLine != TEXT('-')))) {
  194. lpCommandLine++;
  195. }
  196. //
  197. // Skip white space
  198. //
  199. while (*lpCommandLine && (*lpCommandLine == TEXT(' '))) {
  200. lpCommandLine++;
  201. }
  202. if (!*lpCommandLine) {
  203. return TRUE;
  204. }
  205. //
  206. // We should be at the first argument now.
  207. //
  208. if ((*lpCommandLine != TEXT('/')) && (*lpCommandLine != TEXT('-'))) {
  209. Usage();
  210. return FALSE;
  211. }
  212. while (1) {
  213. //
  214. // Increment the pointer and branch to the correct argument.
  215. //
  216. lpCommandLine++;
  217. switch (*lpCommandLine) {
  218. case TEXT('?'):
  219. Usage();
  220. ExitProcess(0);
  221. break;
  222. case TEXT('Q'):
  223. case TEXT('q'):
  224. bQuiet = TRUE;
  225. lpCommandLine++;
  226. break;
  227. case TEXT('I'):
  228. case TEXT('i'):
  229. bIgnoreErrors = TRUE;
  230. lpCommandLine++;
  231. break;
  232. case TEXT('P'):
  233. case TEXT('p'):
  234. bPromptBeforeDelete = TRUE;
  235. lpCommandLine++;
  236. break;
  237. case TEXT('C'):
  238. case TEXT('c'):
  239. //
  240. // Find the colon
  241. //
  242. lpCommandLine++;
  243. if (*lpCommandLine != TEXT(':')) {
  244. Usage();
  245. return FALSE;
  246. }
  247. //
  248. // Find the first character
  249. //
  250. lpCommandLine++;
  251. if (!*lpCommandLine) {
  252. Usage();
  253. return FALSE;
  254. }
  255. //
  256. // Copy the computer name
  257. //
  258. lpTemp = szComputerName;
  259. while (*lpCommandLine && ((*lpCommandLine != TEXT(' ')) &&
  260. (*lpCommandLine != TEXT('/')))){
  261. *lpTemp++ = *lpCommandLine++;
  262. }
  263. *lpTemp = TEXT('\0');
  264. break;
  265. case TEXT('D'):
  266. case TEXT('d'):
  267. //
  268. // Find the colon
  269. //
  270. lpCommandLine++;
  271. if (*lpCommandLine != TEXT(':')) {
  272. Usage();
  273. return FALSE;
  274. }
  275. //
  276. // Find the first character
  277. //
  278. lpCommandLine++;
  279. if (!*lpCommandLine) {
  280. Usage();
  281. return FALSE;
  282. }
  283. //
  284. // Copy the number of days (in characters)
  285. //
  286. lpTemp = szDays;
  287. while (*lpCommandLine && ((*lpCommandLine != TEXT(' ')) &&
  288. (*lpCommandLine != TEXT('/')) &&
  289. (*lpCommandLine != TEXT('-')))) {
  290. *lpTemp++ = *lpCommandLine++;
  291. }
  292. *lpTemp = TEXT('\0');
  293. //
  294. // Convert the days into a number
  295. //
  296. lDays = _ttol(szDays);
  297. break;
  298. default:
  299. Usage();
  300. return FALSE;
  301. }
  302. //
  303. // Skip white space
  304. //
  305. while (*lpCommandLine && (*lpCommandLine == TEXT(' '))) {
  306. lpCommandLine++;
  307. }
  308. if (!*lpCommandLine) {
  309. return TRUE;
  310. }
  311. //
  312. // We should be at the next argument now.
  313. //
  314. if ((*lpCommandLine != TEXT('/')) && (*lpCommandLine != TEXT('-'))) {
  315. Usage();
  316. return FALSE;
  317. }
  318. }
  319. return TRUE;
  320. }
  321. //*************************************************************
  322. //
  323. // Confirm()
  324. //
  325. // Purpose: Confirm the user really wants to delete the profiles
  326. //
  327. // Parameters: void
  328. //
  329. // Return: TRUE if we should continue
  330. // FALSE if not
  331. //
  332. // Comments:
  333. //
  334. // History: Date Author Comment
  335. // 5/18/96 ericflo Created
  336. //
  337. //*************************************************************
  338. BOOL Confirm ()
  339. {
  340. TCHAR szTemp[100];
  341. TCHAR tChar, tTemp;
  342. //
  343. // If we are prompting for every profile, then don't
  344. // give the general prompt.
  345. //
  346. if (bPromptBeforeDelete) {
  347. return TRUE;
  348. }
  349. //
  350. // If the user is requesting a specific day count,
  351. // give a more appropriate confirmation message.
  352. //
  353. if (lDays > 0) {
  354. LoadString (hInst, IDS_CONFIRMDAYS, szTemp, 100);
  355. _tprintf (szTemp, szComputerName, lDays);
  356. } else {
  357. LoadString (hInst, IDS_CONFIRM, szTemp, 100);
  358. _tprintf (szTemp, szComputerName);
  359. }
  360. tChar = _gettchar();
  361. tTemp = tChar;
  362. while (tTemp != TEXT('\n')) {
  363. tTemp = _gettchar();
  364. }
  365. if ((tChar == TEXT('Y')) || (tChar == TEXT('y'))) {
  366. return TRUE;
  367. }
  368. //
  369. // If the user didn't press Y/y, then we bail.
  370. //
  371. LoadString (hInst, IDS_NO, szTemp, 100);
  372. _tprintf (szTemp);
  373. return FALSE;
  374. }
  375. //*************************************************************
  376. //
  377. // PrintLastError()
  378. //
  379. // Purpose: Displays the last error string to the user
  380. //
  381. // Parameters: lError - error code
  382. //
  383. // Return: void
  384. //
  385. // Comments:
  386. //
  387. // History: Date Author Comment
  388. // 5/18/96 ericflo Created
  389. //
  390. //*************************************************************
  391. void PrintLastError(LONG lError)
  392. {
  393. TCHAR szMessage[MAX_PATH];
  394. FormatMessage(
  395. FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
  396. NULL,
  397. lError,
  398. MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
  399. szMessage,
  400. MAX_PATH,
  401. NULL);
  402. _tprintf (szMessage);
  403. }
  404. //*************************************************************
  405. //
  406. // AddNode()
  407. //
  408. // Purpose: Adds a new node to the link list
  409. //
  410. // Parameters: szSubKey - SubKey
  411. // szProfilePath - Profile Path (or NULL)
  412. // bDir - Directory or file
  413. //
  414. // Return: TRUE if successful
  415. // FALSE if an error occurs
  416. //
  417. // Comments: szProfilePath can be NULL. In this case, we
  418. // are just removing the bogus registry entry.
  419. //
  420. // History: Date Author Comment
  421. // 5/18/96 ericflo Created
  422. //
  423. //*************************************************************
  424. BOOL AddNode (LPTSTR szSubKey, LPTSTR szProfilePath, BOOL bDir)
  425. {
  426. LPDELETEITEM lpItem, lpTemp;
  427. UINT uAlloc = 0;
  428. //
  429. // Create a new node
  430. //
  431. uAlloc = sizeof(DELETEITEM) + (lstrlen(szSubKey) + 1) * sizeof(TCHAR);
  432. if (szProfilePath) {
  433. uAlloc +=(lstrlen(szProfilePath) + 1) * sizeof(TCHAR);
  434. }
  435. lpItem = LocalAlloc (LPTR, uAlloc);
  436. if (!lpItem) {
  437. return FALSE;
  438. }
  439. lpItem->lpSubKey = (LPTSTR)((LPBYTE)lpItem + sizeof(DELETEITEM));
  440. _tcscpy(lpItem->lpSubKey, szSubKey);
  441. if (szProfilePath) {
  442. lpItem->lpProfilePath = lpItem->lpSubKey + lstrlen(szSubKey) + 1;
  443. _tcscpy(lpItem->lpProfilePath, szProfilePath);
  444. } else {
  445. lpItem->lpProfilePath = NULL;
  446. }
  447. lpItem->bDir = bDir;
  448. //
  449. // Add this node to the global lpItemList
  450. //
  451. if (lpDeleteList) {
  452. lpTemp = lpDeleteList;
  453. while (lpTemp->pNext) {
  454. lpTemp = lpTemp->pNext;
  455. }
  456. lpTemp->pNext = lpItem;
  457. } else {
  458. lpDeleteList = lpItem;
  459. }
  460. return TRUE;
  461. }
  462. //*************************************************************
  463. //
  464. // GetProfileDateInDays()
  465. //
  466. // Purpose: Gets the profile date in days.
  467. //
  468. // Parameters: szProfilePath - Profile path
  469. // bDir - Directory or file
  470. //
  471. // Return: age in days.
  472. //
  473. // Comments:
  474. //
  475. // History: Date Author Comment
  476. // 5/18/96 ericflo Created
  477. //
  478. //*************************************************************
  479. LONG GetProfileDateInDays(LPTSTR szProfilePath, BOOL bDir)
  480. {
  481. TCHAR szTemp[MAX_PATH];
  482. HANDLE hFile;
  483. WIN32_FIND_DATA fd;
  484. LONG days;
  485. SYSTEMTIME systime;
  486. FILETIME ft;
  487. if (bDir) {
  488. //
  489. // Tack on ntuser.* to find the registry hive.
  490. //
  491. _tcscpy(szTemp, szProfilePath);
  492. _tcscat(szTemp, TEXT("\\ntuser.*"));
  493. hFile = FindFirstFile (szTemp, &fd);
  494. } else {
  495. //
  496. // szProfilePath points to a file.
  497. //
  498. hFile = FindFirstFile (szProfilePath, &fd);
  499. }
  500. if (hFile != INVALID_HANDLE_VALUE) {
  501. FindClose (hFile);
  502. FileTimeToLocalFileTime (&fd.ftLastWriteTime, &ft);
  503. FileTimeToSystemTime (&ft, &systime);
  504. days = gdate_dmytoday(systime.wYear, systime.wMonth, systime.wDay);
  505. } else {
  506. days = lCurrentDateInDays;
  507. }
  508. return days;
  509. }
  510. //*************************************************************
  511. //
  512. // CheckProfile()
  513. //
  514. // Purpose: Checks if the given profile should be deleted.
  515. // If so, it is added to the list.
  516. //
  517. // Parameters: hKeyLM - Local Machine key
  518. // hKeyUsers - HKEY_USERS key
  519. // lpSid - Sid string (key name)
  520. //
  521. // Return: TRUE if successful
  522. // FALSE if not
  523. //
  524. // Comments:
  525. //
  526. // History: Date Author Comment
  527. // 5/18/96 ericflo Created
  528. //
  529. //*************************************************************
  530. BOOL CheckProfile (HKEY hKeyLM, HKEY hKeyUsers, LPTSTR lpSid)
  531. {
  532. LONG lResult;
  533. HKEY hkey;
  534. TCHAR szSubKey[MAX_PATH];
  535. DWORD dwSize, dwType;
  536. TCHAR szTemp[MAX_PATH];
  537. TCHAR szProfilePath[MAX_PATH];
  538. TCHAR szError[100];
  539. DWORD dwAttribs;
  540. BOOL bDir;
  541. LONG lProfileDateInDays;
  542. //
  543. // Check if the profile is in use
  544. //
  545. lResult = RegOpenKeyEx (hKeyUsers, lpSid, 0, KEY_READ, &hkey);
  546. if (lResult == ERROR_SUCCESS) {
  547. RegCloseKey (hkey);
  548. return TRUE;
  549. }
  550. //
  551. // Open the profile information
  552. //
  553. wsprintf (szSubKey, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%s"),
  554. lpSid);
  555. lResult = RegOpenKeyEx (hKeyLM,
  556. szSubKey,
  557. 0,
  558. KEY_READ,
  559. &hkey);
  560. if (lResult != ERROR_SUCCESS) {
  561. LoadString (hInst, IDS_FAILEDOPENPROFILE, szError, 100);
  562. _tprintf(szError, lpSid);
  563. PrintLastError(lResult);
  564. return FALSE;
  565. }
  566. //
  567. // Query for the ProfileImagePath
  568. //
  569. dwSize = MAX_PATH * sizeof(TCHAR);
  570. lResult = RegQueryValueEx (hkey,
  571. TEXT("ProfileImagePath"),
  572. NULL,
  573. &dwType,
  574. (LPBYTE)szTemp,
  575. &dwSize);
  576. if (lResult != ERROR_SUCCESS) {
  577. LoadString (hInst, IDS_FAILEDPATHQUERY, szError, 100);
  578. _tprintf(szError, lpSid);
  579. PrintLastError(lResult);
  580. RegCloseKey (hkey);
  581. return FALSE;
  582. }
  583. //
  584. // Expand the path.
  585. //
  586. if (_tcsnicmp(TEXT("%SystemRoot%"), szTemp, 12) == 0) {
  587. _stprintf(szProfilePath, TEXT("%s\\%s"), szSystemRoot, szTemp+13);
  588. }
  589. else if (_tcsnicmp(TEXT("%SystemDrive%"), szTemp, 13) == 0) {
  590. _stprintf(szProfilePath, TEXT("%s\\%s"), szSystemDrive, szTemp+14);
  591. }
  592. else if (NULL == _tcschr(szTemp, TEXT('%')) && !bLocalComputer) {
  593. if (TEXT(':') == szTemp[1])
  594. szTemp[1] = TEXT('$');
  595. _stprintf(szProfilePath, TEXT("%s\\%s"), szComputerName, szTemp);
  596. }
  597. else {
  598. LoadString (hInst, IDS_SKIPPROFILE, szError, 100);
  599. _tprintf(szError, szTemp);
  600. goto Exit;
  601. }
  602. //
  603. // Is this a directory or a file?
  604. //
  605. dwAttribs = GetFileAttributes (szProfilePath);
  606. if (dwAttribs == -1) {
  607. AddNode (szSubKey, NULL, FALSE);
  608. goto Exit;
  609. }
  610. bDir = (dwAttribs & FILE_ATTRIBUTE_DIRECTORY) ? TRUE : FALSE;
  611. //
  612. // Check Time/Date stamp. If the profile date is older
  613. // than the amount specified, add it to the delete list.
  614. //
  615. lProfileDateInDays = GetProfileDateInDays(szProfilePath, bDir);
  616. if (lCurrentDateInDays >= lProfileDateInDays) {
  617. if ((lCurrentDateInDays - lProfileDateInDays) >= lDays) {
  618. AddNode (szSubKey, szProfilePath, bDir);
  619. }
  620. }
  621. Exit:
  622. RegCloseKey (hkey);
  623. return TRUE;
  624. }
  625. //*************************************************************
  626. //
  627. // DelProfiles()
  628. //
  629. // Purpose: Deletes the user profiles
  630. //
  631. // Parameters: void
  632. //
  633. // Return: TRUE if successful
  634. // FALSE if an error occurs
  635. //
  636. // Comments:
  637. //
  638. // History: Date Author Comment
  639. // 5/18/96 ericflo Created
  640. //
  641. //*************************************************************
  642. BOOL DelProfiles(void)
  643. {
  644. HKEY hKeyLM = NULL, hKeyUsers = NULL, hKeyProfiles = NULL;
  645. HKEY hKeyCurrentVersion = NULL;
  646. LONG lResult;
  647. BOOL bResult = FALSE, bTemp;
  648. TCHAR szError[100];
  649. DWORD dwIndex = 0, dwNameSize, dwClassSize;
  650. DWORD dwBufferSize;
  651. TCHAR szName[MAX_PATH];
  652. TCHAR szClass[MAX_PATH], szTemp[MAX_PATH];
  653. TCHAR tChar, tTemp;
  654. FILETIME ft;
  655. LPDELETEITEM lpTemp;
  656. LPTSTR pSid, lpEnd;
  657. DWORD lProfileKeyLen;
  658. lProfileKeyLen = lstrlen(TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"))+1;
  659. //
  660. // Open the registry
  661. //
  662. lResult = RegConnectRegistry(szComputerName, HKEY_LOCAL_MACHINE, &hKeyLM);
  663. if (lResult != ERROR_SUCCESS) {
  664. PrintLastError(lResult);
  665. goto Exit;
  666. }
  667. lResult = RegConnectRegistry(szComputerName, HKEY_USERS, &hKeyUsers);
  668. if (lResult != ERROR_SUCCESS) {
  669. PrintLastError(lResult);
  670. goto Exit;
  671. }
  672. //
  673. // Get the value of %SystemRoot% and %SystemDrive% relative to the computer
  674. //
  675. lResult = RegOpenKeyEx(hKeyLM,
  676. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion"),
  677. 0,
  678. KEY_READ,
  679. &hKeyCurrentVersion);
  680. if (lResult != ERROR_SUCCESS) {
  681. PrintLastError(lResult);
  682. goto Exit;
  683. }
  684. dwBufferSize = MAX_PATH * sizeof(TCHAR);
  685. lResult = RegQueryValueEx(hKeyCurrentVersion,
  686. TEXT("SystemRoot"),
  687. NULL,
  688. NULL,
  689. (BYTE *) szTemp,
  690. &dwBufferSize);
  691. if (lResult != ERROR_SUCCESS) {
  692. PrintLastError(lResult);
  693. goto Exit;
  694. }
  695. if (!bLocalComputer) {
  696. szTemp[1] = TEXT('$');
  697. _tcscpy(szSystemRoot, szComputerName); lstrcat(szSystemRoot, TEXT("\\"));
  698. _tcscpy(szSystemDrive, szComputerName); lstrcat(szSystemDrive, TEXT("\\"));
  699. lpEnd = szSystemDrive+lstrlen(szSystemDrive);
  700. _tcsncpy(lpEnd, szTemp, 2);
  701. lpEnd = szSystemRoot+lstrlen(szSystemRoot);
  702. _tcscpy(lpEnd, szTemp);
  703. }
  704. else {
  705. _tcsncpy(szSystemDrive, szTemp, 2);
  706. _tcscpy(szSystemRoot, szTemp);
  707. }
  708. //
  709. // Open the ProfileList key
  710. //
  711. lResult = RegOpenKeyEx (hKeyLM,
  712. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"),
  713. 0,
  714. KEY_ALL_ACCESS,
  715. &hKeyProfiles);
  716. if (lResult != ERROR_SUCCESS) {
  717. LoadString (hInst, IDS_FAILEDPROFILELIST, szError, 100);
  718. _tprintf(szError);
  719. PrintLastError(lResult);
  720. goto Exit;
  721. }
  722. //
  723. // Enumerate the profiles
  724. //
  725. dwNameSize = dwClassSize = MAX_PATH;
  726. lResult = RegEnumKeyEx(hKeyProfiles,
  727. dwIndex,
  728. szName,
  729. &dwNameSize,
  730. NULL,
  731. szClass,
  732. &dwClassSize,
  733. &ft);
  734. while (lResult == ERROR_SUCCESS) {
  735. //
  736. // Hand the profile info off to CheckProfile
  737. // to determine if the profile should be deleted or not.
  738. //
  739. if (!CheckProfile (hKeyLM, hKeyUsers, szName)) {
  740. if (!bIgnoreErrors) {
  741. goto Exit;
  742. }
  743. }
  744. //
  745. // Reset for the next loop
  746. //
  747. dwIndex++;
  748. dwNameSize = dwClassSize = MAX_PATH;
  749. lResult = RegEnumKeyEx(hKeyProfiles,
  750. dwIndex,
  751. szName,
  752. &dwNameSize,
  753. NULL,
  754. szClass,
  755. &dwClassSize,
  756. &ft);
  757. }
  758. //
  759. // Check for errors
  760. //
  761. if (lResult != ERROR_NO_MORE_ITEMS) {
  762. LoadString (hInst, IDS_FAILEDENUM, szError, 100);
  763. _tprintf(szError);
  764. PrintLastError(lResult);
  765. goto Exit;
  766. }
  767. //
  768. // Remove profiles
  769. //
  770. lpTemp = lpDeleteList;
  771. while (lpTemp) {
  772. if (lpTemp->lpProfilePath) {
  773. //
  774. // Prompt before deleting the profile (if approp).
  775. //
  776. if (bPromptBeforeDelete) {
  777. while (1) {
  778. LoadString (hInst, IDS_DELETEPROMPT, szError, 100);
  779. _tprintf (szError, lpTemp->lpProfilePath);
  780. tChar = _gettchar();
  781. tTemp = tChar;
  782. while (tTemp != TEXT('\n')) {
  783. tTemp = _gettchar();
  784. }
  785. if ((tChar == TEXT('N')) || (tChar == TEXT('n'))) {
  786. goto LoopAgain;
  787. }
  788. if ((tChar == TEXT('A')) || (tChar == TEXT('a'))) {
  789. bPromptBeforeDelete = FALSE;
  790. break;
  791. }
  792. if ((tChar == TEXT('Y')) || (tChar == TEXT('y'))) {
  793. break;
  794. }
  795. }
  796. }
  797. //
  798. // Delete the profile
  799. //
  800. LoadString (hInst, IDS_DELETING, szError, 100);
  801. _tprintf (szError, lpTemp->lpProfilePath);
  802. pSid = lpTemp->lpSubKey+lProfileKeyLen;
  803. bTemp = DeleteProfile(pSid, lpTemp->lpProfilePath, ((bLocalComputer)? NULL:szComputerName));
  804. if (bTemp) {
  805. LoadString (hInst, IDS_SUCCESS, szError, 100);
  806. _tprintf (szError, lpTemp->lpProfilePath);
  807. } else {
  808. LoadString (hInst, IDS_FAILED, szError, 100);
  809. _tprintf (szError, lpTemp->lpProfilePath);
  810. PrintLastError(GetLastError());
  811. }
  812. } else {
  813. //
  814. // If there isn't a profile path, then we are just
  815. // cleaning up the bogus registry entry.
  816. //
  817. bTemp = TRUE;
  818. //
  819. // Clean up the registry.
  820. //
  821. RegDeleteKey (hKeyLM, lpTemp->lpSubKey);
  822. }
  823. //
  824. // Did the clean up fail?
  825. //
  826. if (!bTemp) {
  827. if (!bIgnoreErrors) {
  828. goto Exit;
  829. }
  830. }
  831. LoopAgain:
  832. lpTemp = lpTemp->pNext;
  833. }
  834. //
  835. // Success
  836. //
  837. bResult = TRUE;
  838. Exit:
  839. if (hKeyCurrentVersion)
  840. RegCloseKey(hKeyCurrentVersion);
  841. if (hKeyProfiles)
  842. RegCloseKey(hKeyProfiles);
  843. if (hKeyLM)
  844. RegCloseKey(hKeyLM);
  845. if (hKeyUsers)
  846. RegCloseKey(hKeyUsers);
  847. if (lpDeleteList) {
  848. do {
  849. lpTemp = lpDeleteList->pNext;
  850. LocalFree (lpDeleteList);
  851. lpDeleteList = lpTemp;
  852. } while (lpDeleteList);
  853. }
  854. return bResult;
  855. }
  856. //*************************************************************
  857. //
  858. // main()
  859. //
  860. // Purpose: main entry point
  861. //
  862. // Parameters: argc - number of arguments
  863. // argv - arguments
  864. //
  865. // Return: 0 if successful
  866. // 1 if an error occurs
  867. //
  868. // Comments:
  869. //
  870. // History: Date Author Comment
  871. // 5/18/96 ericflo Created
  872. //
  873. //*************************************************************
  874. int __cdecl main( int argc, char *argv[])
  875. {
  876. //
  877. // Initialize the globals
  878. //
  879. InitializeGlobals();
  880. //
  881. // Parse the command line
  882. //
  883. if (!ParseCommandLine(GetCommandLine())) {
  884. return 1;
  885. }
  886. //
  887. // Check the globals variables
  888. //
  889. CheckGlobals();
  890. //
  891. // Confirmation
  892. //
  893. if (!bQuiet) {
  894. if (!Confirm()) {
  895. return 1;
  896. }
  897. }
  898. //
  899. // Remove the profiles
  900. //
  901. if (!DelProfiles()) {
  902. return 1;
  903. }
  904. return 0;
  905. }