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.

504 lines
15 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include "CleanupWiz.h"
  5. #include "resource.h"
  6. #include "priv.h"
  7. #include "dblnul.h"
  8. #include <shlwapi.h>
  9. extern HINSTANCE g_hInst;
  10. //#define SILENTMODE_LOGGING
  11. #ifdef SILENTMODE_LOGGING
  12. HANDLE g_hLogFile;
  13. void StartLogging(LPTSTR pszFolderPath)
  14. {
  15. TCHAR szLogFile[MAX_PATH];
  16. StrCpyN(szLogFile, pszFolderPath, ARRAYSIZE(szLogFile));
  17. PathAppend(szLogFile, TEXT("log.txt"));
  18. g_hLogFile = CreateFile(szLogFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  19. }
  20. void StopLogging()
  21. {
  22. if (INVALID_HANDLE_VALUE != g_hLogFile)
  23. {
  24. CloseHandle(g_hLogFile);
  25. }
  26. }
  27. void WriteLog(LPCTSTR pszTemplate, LPCTSTR pszParam1, LPCTSTR pszParam2)
  28. {
  29. if (INVALID_HANDLE_VALUE != g_hLogFile)
  30. {
  31. TCHAR szBuffer[1024];
  32. DWORD cbWritten;
  33. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), pszTemplate, pszParam1, pszParam2);
  34. if (WriteFile(g_hLogFile, szBuffer, sizeof(TCHAR) * lstrlen(szBuffer), &cbWritten, NULL))
  35. {
  36. FlushFileBuffers(g_hLogFile);
  37. }
  38. }
  39. }
  40. #define STARTLOGGING(psz) StartLogging(psz)
  41. #define STOPLOGGING StopLogging()
  42. #define WRITELOG(pszTemplate, psz1, psz2) WriteLog(pszTemplate, psz1, psz2)
  43. #else
  44. #define STARTLOGGING(psz)
  45. #define STOPLOGGING
  46. #define WRITELOG(pszTemplate, psz1, psz2)
  47. #endif
  48. DWORD CCleanupWiz::_LoadUnloadHive(HKEY hKey, LPCTSTR pszSubKey, LPCTSTR pszHive)
  49. {
  50. DWORD dwErr;
  51. BOOLEAN bWasEnabled;
  52. NTSTATUS status;
  53. status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &bWasEnabled);
  54. if ( NT_SUCCESS(status) )
  55. {
  56. if (pszHive)
  57. {
  58. dwErr = RegLoadKey(hKey, pszSubKey, pszHive);
  59. }
  60. else
  61. {
  62. dwErr = RegUnLoadKey(hKey, pszSubKey);
  63. }
  64. RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, bWasEnabled, FALSE, &bWasEnabled);
  65. }
  66. else
  67. {
  68. dwErr = RtlNtStatusToDosError(status);
  69. }
  70. return dwErr;
  71. }
  72. HRESULT CCleanupWiz::_HideRegItemsFromNameSpace(LPCTSTR pszDestPath, HKEY hkey)
  73. {
  74. DWORD dwIndex = 0;
  75. TCHAR szCLSID[39];
  76. while (ERROR_SUCCESS == RegEnumKey(hkey, dwIndex++, szCLSID, ARRAYSIZE(szCLSID)))
  77. {
  78. CLSID clsid;
  79. GUIDFromString(szCLSID, &clsid);
  80. if (CLSID_MyComputer != clsid &&
  81. CLSID_MyDocuments != clsid &&
  82. CLSID_NetworkPlaces != clsid &&
  83. CLSID_RecycleBin != clsid)
  84. {
  85. BOOL fWasVisible;
  86. _HideRegItem(&clsid, TRUE, &fWasVisible);
  87. if (fWasVisible)
  88. {
  89. HKEY hkeyCLSID;
  90. if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, TEXT("CLSID"), &hkeyCLSID))
  91. {
  92. HKEY hkeySub;
  93. if (ERROR_SUCCESS == RegOpenKey(hkeyCLSID, szCLSID, &hkeySub))
  94. {
  95. TCHAR szName[260];
  96. LONG cbName = sizeof(szName);
  97. if (ERROR_SUCCESS == RegQueryValue(hkeySub, NULL, szName, &cbName))
  98. {
  99. _CreateFakeRegItem(pszDestPath, szName, szCLSID);
  100. }
  101. RegCloseKey(hkeySub);
  102. }
  103. RegCloseKey(hkeyCLSID);
  104. }
  105. }
  106. }
  107. }
  108. return S_OK;
  109. }
  110. HRESULT CCleanupWiz::_GetDesktopFolderBySid(LPCTSTR pszDestPath, LPCTSTR pszSid, LPTSTR pszBuffer, DWORD cchBuffer)
  111. {
  112. TCHAR szKey[MAX_PATH];
  113. TCHAR szProfilePath[MAX_PATH];
  114. DWORD dwSize;
  115. DWORD dwErr;
  116. // Start by getting the user's ProfilePath from the registry
  117. StrCpyN(szKey, REGSTR_PROFILELIST, ARRAYSIZE(szKey));
  118. StrCatBuff(szKey, pszSid, ARRAYSIZE(szKey));
  119. dwSize = sizeof(szProfilePath);
  120. dwErr = SHGetValue(HKEY_LOCAL_MACHINE,
  121. szKey,
  122. TEXT("ProfileImagePath"),
  123. NULL,
  124. szProfilePath,
  125. &dwSize);
  126. if ( ERROR_SUCCESS == dwErr)
  127. {
  128. // Load the user's hive
  129. PathAppend(szProfilePath, TEXT("ntuser.dat"));
  130. dwErr = _LoadUnloadHive(HKEY_USERS, pszSid, szProfilePath);
  131. if ( dwErr == ERROR_SUCCESS || ERROR_SHARING_VIOLATION == dwErr) // sharing violation means the hive is already open
  132. {
  133. HKEY hkey;
  134. StrCpyN(szKey, pszSid, ARRAYSIZE(szKey));
  135. PathAppend(szKey, REGSTR_SHELLFOLDERS);
  136. dwErr = RegOpenKeyEx(HKEY_USERS,
  137. szKey,
  138. 0,
  139. KEY_QUERY_VALUE,
  140. &hkey);
  141. if ( dwErr == ERROR_SUCCESS )
  142. {
  143. dwSize = cchBuffer;
  144. dwErr = RegQueryValueEx(hkey, REGSTR_DESKTOP, NULL, NULL, (LPBYTE)pszBuffer, &dwSize);
  145. if ( dwErr == ERROR_SUCCESS )
  146. {
  147. // todo: confirm that this doesn't overflow
  148. PathAppend(pszBuffer, TEXT("*"));
  149. }
  150. RegCloseKey(hkey);
  151. }
  152. StrCpyN(szKey, pszSid, ARRAYSIZE(szKey));
  153. PathAppend(szKey, REGSTR_DESKTOPNAMESPACE);
  154. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_USERS, szKey, 0, KEY_READ, &hkey))
  155. {
  156. _HideRegItemsFromNameSpace(pszDestPath, hkey);
  157. RegCloseKey(hkey);
  158. }
  159. _LoadUnloadHive(HKEY_USERS, pszSid, NULL);
  160. }
  161. }
  162. return HRESULT_FROM_WIN32(dwErr);
  163. }
  164. HRESULT CCleanupWiz::_AppendDesktopFolderName(LPTSTR pszBuffer)
  165. {
  166. TCHAR szDesktop[MAX_PATH];
  167. if (SHGetSpecialFolderPath(NULL, szDesktop, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE))
  168. {
  169. PathStripPath(szDesktop); // get just the localized word "Desktop"
  170. PathAppend(pszBuffer, szDesktop);
  171. }
  172. else
  173. {
  174. PathAppend(pszBuffer, DESKTOP_DIR); // default to "Desktop"
  175. }
  176. return S_OK;
  177. }
  178. HRESULT CCleanupWiz::_GetDesktopFolderByRegKey(LPCTSTR pszRegKey, LPCTSTR pszRegValue, LPTSTR szBuffer, DWORD cchBuffer)
  179. {
  180. HRESULT hr = E_FAIL;
  181. DWORD cb = cchBuffer * sizeof(TCHAR);
  182. if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, pszRegKey, REGSTR_PROFILESDIR, NULL, (void*)szBuffer, &cb))
  183. {
  184. TCHAR szAppend[MAX_PATH];
  185. cb = sizeof(szAppend);
  186. if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, pszRegKey, pszRegValue, NULL, (void*)szAppend, &cb))
  187. {
  188. PathAppend(szBuffer, szAppend);
  189. _AppendDesktopFolderName(szBuffer);
  190. PathAppend(szBuffer, TEXT("*"));
  191. hr = S_OK;
  192. }
  193. }
  194. return hr;
  195. }
  196. HRESULT CCleanupWiz::_MoveDesktopItems(LPCTSTR pszFrom, LPCTSTR pszTo)
  197. {
  198. WRITELOG(TEXT("**** MoveDesktopItems: %s %s **** "), pszFrom, pszTo);
  199. SHFILEOPSTRUCT fo;
  200. fo.hwnd = NULL;
  201. fo.wFunc = FO_MOVE;
  202. fo.pFrom = pszFrom;
  203. fo.pTo = pszTo;
  204. fo.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS | FOF_NOERRORUI | FOF_RENAMEONCOLLISION;
  205. int iRet = SHFileOperation(&fo);
  206. return HRESULT_FROM_WIN32(iRet);
  207. }
  208. HRESULT CCleanupWiz::_SilentProcessUserBySid(LPCTSTR pszDestPath, LPCTSTR pszSid)
  209. {
  210. WRITELOG(TEXT("**** SilentProcessUserBySid: %s **** "), pszSid, TEXT(""));
  211. HRESULT hr;
  212. if (!pszSid || !*pszSid || !pszDestPath || !*pszDestPath)
  213. {
  214. return E_INVALIDARG;
  215. }
  216. TCHAR szTo[MAX_PATH + 1];
  217. TCHAR szFrom[MAX_PATH + 1];
  218. StrCpyN(szTo, pszDestPath, ARRAYSIZE(szTo) - 1);
  219. hr = _GetDesktopFolderBySid(pszDestPath, pszSid, szFrom, ARRAYSIZE(szFrom));
  220. if (SUCCEEDED(hr))
  221. {
  222. szFrom[lstrlen(szFrom) + 1] = 0;
  223. szTo[lstrlen(szTo) + 1] = 0;
  224. hr = _MoveDesktopItems(szFrom, szTo);
  225. }
  226. return hr;
  227. }
  228. HRESULT CCleanupWiz::_SilentProcessUserByRegKey(LPCTSTR pszDestPath, LPCTSTR pszRegKey, LPCTSTR pszRegValue)
  229. {
  230. HRESULT hr;
  231. if (!pszRegKey || !*pszRegKey || !pszRegValue || !*pszRegValue || !pszDestPath || !*pszDestPath)
  232. {
  233. return E_INVALIDARG;
  234. }
  235. TCHAR szTo[MAX_PATH + 1];
  236. TCHAR szFrom[MAX_PATH + 1];
  237. StrCpyN(szTo, pszDestPath, ARRAYSIZE(szTo) - 1);
  238. hr = _GetDesktopFolderByRegKey(pszRegKey, pszRegValue, szFrom, ARRAYSIZE(szFrom));
  239. if (SUCCEEDED(hr))
  240. {
  241. szFrom[lstrlen(szFrom) + 1] = 0;
  242. szTo[lstrlen(szTo) + 1] = 0;
  243. hr = _MoveDesktopItems(szFrom, szTo);
  244. }
  245. return hr;
  246. }
  247. HRESULT CCleanupWiz::_SilentProcessUsers(LPCTSTR pszDestPath)
  248. {
  249. HRESULT hr = E_FAIL;
  250. HKEY hkey;
  251. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"), &hkey))
  252. {
  253. TCHAR szSid[MAX_PATH];
  254. DWORD dwIndex = 0;
  255. while (ERROR_SUCCESS == RegEnumKey(hkey, dwIndex++, szSid, ARRAYSIZE(szSid)))
  256. {
  257. _SilentProcessUserBySid(pszDestPath, szSid);
  258. }
  259. RegCloseKey(hkey);
  260. hr = S_OK;
  261. }
  262. return hr;
  263. }
  264. HRESULT CCleanupWiz::_RunSilent()
  265. {
  266. // if we're in silent mode, try to get the special folder name out of the registry, else default to normal name
  267. DWORD dwType = REG_SZ;
  268. DWORD cb = sizeof(_szFolderName);
  269. if (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_OEM_PATH, REGSTR_OEM_TITLEVAL, &dwType, _szFolderName, &cb))
  270. {
  271. LoadString(g_hInst, IDS_ARCHIVEFOLDER_FIRSTBOOT, _szFolderName, MAX_PATH);
  272. }
  273. // assemble the name of the directory we should write to
  274. TCHAR szPath[MAX_PATH];
  275. SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, szPath);
  276. PathAppend(szPath, _szFolderName);
  277. // Create the directory
  278. SHCreateDirectoryEx(NULL, szPath, NULL);
  279. STARTLOGGING(szPath);
  280. // Move regitems of All Users
  281. HKEY hkey;
  282. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_DESKTOPNAMESPACE, 0, KEY_READ, &hkey))
  283. {
  284. _HideRegItemsFromNameSpace(szPath, hkey);
  285. RegCloseKey(hkey);
  286. }
  287. // Move desktop items of All Users
  288. _SilentProcessUserByRegKey(szPath, REGSTR_PROFILELIST, REGSTR_ALLUSERS);
  289. // move desktop items of Default User
  290. _SilentProcessUserByRegKey(szPath, REGSTR_PROFILELIST, REGSTR_DEFAULTUSER);
  291. // Move desktop items of each normal users
  292. _SilentProcessUsers(szPath);
  293. STOPLOGGING;
  294. return S_OK;
  295. }
  296. BOOL _ShouldPlaceIEDesktopIcon()
  297. {
  298. BOOL fRetVal = TRUE;
  299. DWORD dwData;
  300. DWORD cbData = sizeof(dwData);
  301. if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_OCMANAGER, REGSTR_IEACCESS, NULL, &dwData, &cbData)) &&
  302. (dwData == 0))
  303. {
  304. fRetVal = FALSE;
  305. }
  306. return fRetVal;
  307. }
  308. BOOL _ShouldUseMSNInternetAccessIcon()
  309. {
  310. BOOL fRetVal = FALSE;
  311. TCHAR szBuffer[4];
  312. DWORD cch = sizeof(szBuffer);
  313. if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_MSNCODES, REGSTR_MSN_IAONLY, NULL, szBuffer, &cch)) &&
  314. (!StrCmpI(szBuffer, TEXT("yes"))))
  315. {
  316. fRetVal = TRUE;
  317. }
  318. return fRetVal;
  319. }
  320. HRESULT _AddIEIconToDesktop()
  321. {
  322. DWORD dwData = 0;
  323. TCHAR szCLSID[MAX_GUID_STRING_LEN];
  324. TCHAR szBuffer[MAX_PATH];
  325. HRESULT hr = SHStringFromGUID(CLSID_Internet, szCLSID, ARRAYSIZE(szCLSID));
  326. if (SUCCEEDED(hr))
  327. {
  328. for (int i = 0; i < 2; i ++)
  329. {
  330. wsprintf(szBuffer, REGSTR_PATH_HIDDEN_DESKTOP_ICONS, (i == 0) ? REGSTR_VALUE_STARTPANEL : REGSTR_VALUE_CLASSICMENU);
  331. SHRegSetUSValue(szBuffer, szCLSID, REG_DWORD, &dwData, sizeof(DWORD), SHREGSET_FORCE_HKLM);
  332. }
  333. }
  334. return hr;
  335. }
  336. HRESULT _AddWMPIconToDesktop()
  337. {
  338. // first set this registry value so if the WMP shortcut creator kicks in after us (it may not, due to timing concerns) it will not delete our shortcut
  339. SHRegSetUSValue(REGSTR_WMP_PATH_SETUP, REGSTR_WMP_REGVALUE, REG_SZ, REGSTR_YES, sizeof(TCHAR) * (ARRAYSIZE(REGSTR_YES) + 1), SHREGSET_FORCE_HKLM);
  340. HRESULT hr;
  341. TCHAR szBuffer[MAX_PATH];
  342. TCHAR szSourcePath[MAX_PATH];
  343. TCHAR szDestPath[MAX_PATH];
  344. // we get docs and settings\all users\start menu\programs
  345. hr = SHGetSpecialFolderPath(NULL, szSourcePath, CSIDL_COMMON_PROGRAMS, FALSE);
  346. if (SUCCEEDED(hr))
  347. {
  348. // strip it down to docs and settings\all users, using szDestPath as a temp buffer
  349. StrCpyN(szDestPath, szSourcePath, ARRAYSIZE(szDestPath));
  350. PathRemoveFileSpec(szSourcePath); // remove Programs
  351. PathRemoveFileSpec(szSourcePath); // remove Start Menu
  352. // now copy "start menu\programs" to szBuffer
  353. StrCpyN(szBuffer, szDestPath + lstrlen(szSourcePath), ARRAYSIZE(szBuffer));
  354. // load "Default user" into szDestPath
  355. LoadString(g_hInst, IDS_DEFAULTUSER, szDestPath, ARRAYSIZE(szDestPath));
  356. PathRemoveFileSpec(szSourcePath); // remove All Users
  357. // now szSourcePath is docs and settings
  358. PathAppend(szSourcePath, szDestPath);
  359. // now szSourcePath is docs and settings\Default User
  360. // sanity check, localizers may have inappropriately localized Default User on a system where it shouldn't be localized
  361. if (!PathIsDirectory(szSourcePath))
  362. {
  363. PathRemoveFileSpec(szSourcePath);
  364. PathAppend(szSourcePath, DEFAULT_USER); // if so, remove what they gave us and just add the English "Default User", which is what it is on most machines
  365. }
  366. PathAppend(szSourcePath, szBuffer);
  367. // now szSourcePath is docs and settings\Default User\start menu\programs
  368. hr = SHGetSpecialFolderPath(NULL, szDestPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
  369. if (SUCCEEDED(hr))
  370. {
  371. LoadString(g_hInst, IDS_WMP, szBuffer, ARRAYSIZE(szBuffer));
  372. PathAppend(szSourcePath, szBuffer);
  373. PathAppend(szDestPath, szBuffer);
  374. CopyFile(szSourcePath, szDestPath, TRUE);
  375. }
  376. }
  377. return hr;
  378. }
  379. HRESULT _AddMSNIconToDesktop(BOOL fUseMSNExplorerIcon)
  380. {
  381. HRESULT hr = E_FAIL;
  382. TCHAR szBuffer[MAX_PATH];
  383. TCHAR szSourcePath[MAX_PATH];
  384. TCHAR szDestPath[MAX_PATH];
  385. if ((SUCCEEDED(SHGetSpecialFolderPath(NULL, szSourcePath, CSIDL_COMMON_PROGRAMS, FALSE))) &&
  386. (SUCCEEDED(SHGetSpecialFolderPath(NULL, szDestPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE))))
  387. {
  388. if (fUseMSNExplorerIcon)
  389. {
  390. LoadString(g_hInst, IDS_MSN, szBuffer, ARRAYSIZE(szBuffer)); // MSN Explorer
  391. }
  392. else
  393. {
  394. LoadString(g_hInst, IDS_MSN_ALT, szBuffer, ARRAYSIZE(szBuffer)); // Get Online With MSN
  395. }
  396. PathAppend(szSourcePath, szBuffer);
  397. PathAppend(szDestPath, szBuffer);
  398. CopyFile(szSourcePath, szDestPath, TRUE);
  399. hr = S_OK;
  400. }
  401. return hr;
  402. }
  403. void CreateDesktopIcons()
  404. {
  405. BOOL fIEDesktopIcon = _ShouldPlaceIEDesktopIcon();
  406. _AddWMPIconToDesktop();
  407. if (fIEDesktopIcon)
  408. {
  409. _AddIEIconToDesktop();
  410. }
  411. _AddMSNIconToDesktop(fIEDesktopIcon || !_ShouldUseMSNInternetAccessIcon());
  412. }