Leaked source code of windows server 2003
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.

626 lines
20 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <shlwapi.h>
  5. #include "CleanupWiz.h"
  6. #include "resource.h"
  7. #include "dblnul.h"
  8. extern HINSTANCE g_hInst;
  9. //#define SILENTMODE_LOGGING
  10. #ifdef SILENTMODE_LOGGING
  11. HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
  12. void StartLogging(LPTSTR pszFolderPath)
  13. {
  14. TCHAR szLogFile[MAX_PATH];
  15. if (SUCCEEDED(StringCchCopy(szLogFile, ARRAYSIZE(szLogFile), pszFolderPath)) &&
  16. PathAppend(szLogFile, TEXT("log.txt")))
  17. {
  18. g_hLogFile = CreateFile(szLogFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  19. }
  20. }
  21. void StopLogging()
  22. {
  23. if (INVALID_HANDLE_VALUE != g_hLogFile)
  24. {
  25. CloseHandle(g_hLogFile);
  26. g_hLogFile = INVALID_HANDLE_VALUE;
  27. }
  28. }
  29. void WriteLog(LPCTSTR pszTemplate, LPCTSTR pszParam1, LPCTSTR pszParam2)
  30. {
  31. if (INVALID_HANDLE_VALUE != g_hLogFile)
  32. {
  33. TCHAR szBuffer[1024];
  34. DWORD cbWritten;
  35. if (SUCCEEDED(StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), pszTemplate, pszParam1, pszParam2)) &&
  36. WriteFile(g_hLogFile, szBuffer, sizeof(TCHAR) * lstrlen(szBuffer), &cbWritten, NULL))
  37. {
  38. FlushFileBuffers(g_hLogFile);
  39. }
  40. }
  41. }
  42. #define STARTLOGGING(psz) StartLogging(psz)
  43. #define STOPLOGGING StopLogging()
  44. #define WRITELOG(pszTemplate, psz1, psz2) WriteLog(pszTemplate, psz1, psz2)
  45. #else
  46. #define STARTLOGGING(psz)
  47. #define STOPLOGGING
  48. #define WRITELOG(pszTemplate, psz1, psz2)
  49. #endif
  50. // copied from shell\ext\shgina\cenumusers.cpp
  51. DWORD CCleanupWiz::_LoadUnloadHive(HKEY hKey, LPCTSTR pszSubKey, LPCTSTR pszHive)
  52. {
  53. DWORD dwErr;
  54. BOOLEAN bWasEnabled;
  55. NTSTATUS status;
  56. status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &bWasEnabled);
  57. if ( NT_SUCCESS(status) )
  58. {
  59. if (pszHive)
  60. {
  61. dwErr = RegLoadKey(hKey, pszSubKey, pszHive);
  62. }
  63. else
  64. {
  65. dwErr = RegUnLoadKey(hKey, pszSubKey);
  66. }
  67. RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, bWasEnabled, FALSE, &bWasEnabled);
  68. }
  69. else
  70. {
  71. dwErr = RtlNtStatusToDosError(status);
  72. }
  73. return dwErr;
  74. }
  75. HRESULT CCleanupWiz::_HideRegItemsFromNameSpace(LPCTSTR pszDestPath, HKEY hkey)
  76. {
  77. DWORD dwIndex = 0;
  78. TCHAR szCLSID[39];
  79. while (ERROR_SUCCESS == RegEnumKey(hkey, dwIndex++, szCLSID, ARRAYSIZE(szCLSID)))
  80. {
  81. CLSID clsid;
  82. if (GUIDFromString(szCLSID, &clsid) &&
  83. CLSID_MyComputer != clsid &&
  84. CLSID_MyDocuments != clsid &&
  85. CLSID_NetworkPlaces != clsid &&
  86. CLSID_RecycleBin != clsid)
  87. {
  88. BOOL fWasVisible;
  89. if (SUCCEEDED(_HideRegItem(&clsid, TRUE, &fWasVisible)) &&
  90. fWasVisible)
  91. {
  92. HKEY hkeyCLSID;
  93. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_READ, &hkeyCLSID))
  94. {
  95. HKEY hkeySub;
  96. if (ERROR_SUCCESS == RegOpenKeyEx(hkeyCLSID, szCLSID, 0, KEY_READ, &hkeySub))
  97. {
  98. TCHAR szName[260];
  99. LONG cbName = sizeof(szName);
  100. if (ERROR_SUCCESS == RegQueryValue(hkeySub, NULL, szName, &cbName))
  101. {
  102. _CreateFakeRegItem(pszDestPath, szName, szCLSID);
  103. }
  104. RegCloseKey(hkeySub);
  105. }
  106. RegCloseKey(hkeyCLSID);
  107. }
  108. }
  109. }
  110. }
  111. return S_OK;
  112. }
  113. HRESULT CCleanupWiz::_GetDesktopFolderBySid(LPCTSTR pszDestPath, LPCTSTR pszSid, LPTSTR pszBuffer, DWORD cchBuffer)
  114. {
  115. ASSERT(cchBuffer >= MAX_PATH); // because we do PathAppend on it
  116. HRESULT hr;
  117. TCHAR szKey[MAX_PATH];
  118. TCHAR szProfilePath[MAX_PATH];
  119. DWORD dwSize;
  120. DWORD dwErr;
  121. // Start by getting the user's ProfilePath from the registry
  122. hr = StringCchCopy(szKey, ARRAYSIZE(szKey), c_szRegStrPROFILELIST);
  123. if (SUCCEEDED(hr))
  124. {
  125. if (!PathAppend(szKey, pszSid))
  126. {
  127. hr = E_FAIL;
  128. }
  129. else
  130. {
  131. dwSize = sizeof(szProfilePath);
  132. dwErr = SHGetValue(HKEY_LOCAL_MACHINE,
  133. szKey,
  134. TEXT("ProfileImagePath"),
  135. NULL,
  136. szProfilePath,
  137. &dwSize);
  138. if (ERROR_SUCCESS != dwErr ||
  139. !PathAppend(szProfilePath, TEXT("ntuser.dat")))
  140. {
  141. hr = E_FAIL;
  142. }
  143. else
  144. {
  145. dwErr = _LoadUnloadHive(HKEY_USERS, pszSid, szProfilePath);
  146. if (ERROR_SUCCESS != dwErr &&
  147. ERROR_SHARING_VIOLATION != dwErr) // sharing violation means the hive is already open
  148. {
  149. hr = HRESULT_FROM_WIN32(dwErr);
  150. }
  151. else
  152. {
  153. HKEY hkey;
  154. hr = StringCchCopy(szKey, ARRAYSIZE(szKey), pszSid);
  155. if (SUCCEEDED(hr))
  156. {
  157. if (!PathAppend(szKey, c_szRegStrSHELLFOLDERS))
  158. {
  159. hr = E_FAIL;
  160. }
  161. else
  162. {
  163. dwErr = RegOpenKeyEx(HKEY_USERS,
  164. szKey,
  165. 0,
  166. KEY_QUERY_VALUE,
  167. &hkey);
  168. if ( dwErr != ERROR_SUCCESS )
  169. {
  170. hr = HRESULT_FROM_WIN32(dwErr);
  171. }
  172. else
  173. {
  174. dwSize = cchBuffer;
  175. dwErr = RegQueryValueEx(hkey, c_szRegStrDESKTOP, NULL, NULL, (LPBYTE)pszBuffer, &dwSize);
  176. if ( dwErr == ERROR_SUCCESS )
  177. {
  178. if (!PathAppend(pszBuffer, TEXT("*")))
  179. {
  180. hr = E_FAIL;
  181. }
  182. }
  183. RegCloseKey(hkey);
  184. }
  185. if (SUCCEEDED(hr))
  186. {
  187. hr = StringCchCopy(szKey, ARRAYSIZE(szKey), pszSid);
  188. if (SUCCEEDED(hr))
  189. {
  190. if (!PathAppend(szKey, c_szRegStrDESKTOPNAMESPACE))
  191. {
  192. hr = E_FAIL;
  193. }
  194. else
  195. {
  196. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_USERS, szKey, 0, KEY_READ, &hkey))
  197. {
  198. _HideRegItemsFromNameSpace(pszDestPath, hkey);
  199. RegCloseKey(hkey);
  200. }
  201. }
  202. }
  203. }
  204. }
  205. }
  206. _LoadUnloadHive(HKEY_USERS, pszSid, NULL);
  207. }
  208. }
  209. }
  210. }
  211. return hr;
  212. }
  213. HRESULT CCleanupWiz::_AppendDesktopFolderName(LPTSTR pszBuffer)
  214. {
  215. TCHAR szDesktopPath[MAX_PATH];
  216. LPTSTR pszDesktopName;
  217. if (SHGetSpecialFolderPath(NULL, szDesktopPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE))
  218. {
  219. pszDesktopName = PathFindFileName(szDesktopPath);
  220. }
  221. else
  222. {
  223. pszDesktopName = c_szDESKTOP_DIR;
  224. }
  225. return PathAppend(pszBuffer, pszDesktopName) ? S_OK : E_FAIL;
  226. }
  227. HRESULT CCleanupWiz::_GetDesktopFolderByRegKey(LPCTSTR pszRegKey, LPCTSTR pszRegValue, LPTSTR szBuffer, DWORD cchBuffer)
  228. {
  229. HRESULT hr = E_FAIL;
  230. DWORD cb = cchBuffer * sizeof(TCHAR);
  231. if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, pszRegKey, c_szRegStrPROFILESDIR, NULL, (void*)szBuffer, &cb))
  232. {
  233. TCHAR szAppend[MAX_PATH];
  234. cb = sizeof(szAppend);
  235. if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, pszRegKey, pszRegValue, NULL, (void*)szAppend, &cb))
  236. {
  237. if (PathAppend(szBuffer, szAppend))
  238. {
  239. if (SUCCEEDED(_AppendDesktopFolderName(szBuffer)))
  240. {
  241. if (PathAppend(szBuffer, TEXT("*")))
  242. {
  243. hr = S_OK;
  244. }
  245. }
  246. }
  247. }
  248. }
  249. return hr;
  250. }
  251. HRESULT CCleanupWiz::_MoveDesktopItems(LPCTSTR pszFrom, LPCTSTR pszTo)
  252. {
  253. WRITELOG(TEXT("**** MoveDesktopItems: %s %s **** "), pszFrom, pszTo);
  254. SHFILEOPSTRUCT fo;
  255. fo.hwnd = NULL;
  256. fo.wFunc = FO_MOVE;
  257. fo.pFrom = pszFrom;
  258. fo.pTo = pszTo;
  259. fo.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS | FOF_NOERRORUI | FOF_RENAMEONCOLLISION;
  260. int iRet = SHFileOperation(&fo);
  261. return HRESULT_FROM_WIN32(iRet);
  262. }
  263. HRESULT CCleanupWiz::_SilentProcessUserBySid(LPCTSTR pszDestPath, LPCTSTR pszSid)
  264. {
  265. ASSERT(pszDestPath && *pszDestPath && pszSid && *pszSid);
  266. HRESULT hr;
  267. WRITELOG(TEXT("**** SilentProcessUserBySid: %s **** "), pszSid, TEXT(""));
  268. TCHAR szTo[MAX_PATH + 1];
  269. TCHAR szFrom[MAX_PATH + 1];
  270. hr = StringCchCopy(szTo, ARRAYSIZE(szTo) - 1, pszDestPath);
  271. if (SUCCEEDED(hr))
  272. {
  273. hr = _GetDesktopFolderBySid(pszDestPath, pszSid, szFrom, ARRAYSIZE(szFrom));
  274. if (SUCCEEDED(hr))
  275. {
  276. szFrom[lstrlen(szFrom) + 1] = 0;
  277. szTo[lstrlen(szTo) + 1] = 0;
  278. hr = _MoveDesktopItems(szFrom, szTo);
  279. }
  280. }
  281. return hr;
  282. }
  283. HRESULT CCleanupWiz::_SilentProcessUserByRegKey(LPCTSTR pszDestPath, LPCTSTR pszRegKey, LPCTSTR pszRegValue)
  284. {
  285. ASSERT(pszRegKey && *pszRegKey && pszRegValue && *pszRegValue && pszDestPath && *pszDestPath);
  286. HRESULT hr;
  287. TCHAR szTo[MAX_PATH + 1];
  288. TCHAR szFrom[MAX_PATH + 1];
  289. hr = StringCchCopy(szTo, ARRAYSIZE(szTo) - 1, pszDestPath);
  290. if (SUCCEEDED(hr))
  291. {
  292. hr = _GetDesktopFolderByRegKey(pszRegKey, pszRegValue, szFrom, ARRAYSIZE(szFrom));
  293. if (SUCCEEDED(hr))
  294. {
  295. szFrom[lstrlen(szFrom) + 1] = 0;
  296. szTo[lstrlen(szTo) + 1] = 0;
  297. hr = _MoveDesktopItems(szFrom, szTo);
  298. }
  299. }
  300. return hr;
  301. }
  302. HRESULT CCleanupWiz::_SilentProcessUsers(LPCTSTR pszDestPath)
  303. {
  304. HRESULT hr = E_FAIL;
  305. HKEY hkey;
  306. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegStrPROFILELIST, 0, KEY_READ, &hkey))
  307. {
  308. TCHAR szSid[MAX_PATH];
  309. DWORD dwIndex = 0;
  310. while (ERROR_SUCCESS == RegEnumKey(hkey, dwIndex++, szSid, ARRAYSIZE(szSid)))
  311. {
  312. _SilentProcessUserBySid(pszDestPath, szSid);
  313. }
  314. RegCloseKey(hkey);
  315. hr = S_OK;
  316. }
  317. return hr;
  318. }
  319. HRESULT CCleanupWiz::_RunSilent()
  320. {
  321. HRESULT hr;
  322. // if we're in silent mode, try to get the special folder name out of the registry, else default to normal name
  323. DWORD dwType = REG_SZ;
  324. DWORD cb = sizeof(_szFolderName);
  325. if (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_OEM_PATH, c_szOEM_TITLEVAL, &dwType, _szFolderName, &cb))
  326. {
  327. LoadString(g_hInst, IDS_ARCHIVEFOLDER_FIRSTBOOT, _szFolderName, MAX_PATH);
  328. }
  329. // assemble the name of the directory we should write to
  330. TCHAR szPath[MAX_PATH];
  331. hr = SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, szPath);
  332. if (SUCCEEDED(hr))
  333. {
  334. if (!PathAppend(szPath, _szFolderName))
  335. {
  336. hr = E_FAIL;
  337. }
  338. else
  339. {
  340. SHCreateDirectoryEx(NULL, szPath, NULL);
  341. if (!PathIsDirectory(szPath))
  342. {
  343. hr = E_FAIL;
  344. }
  345. else
  346. {
  347. hr = S_OK;
  348. STARTLOGGING(szPath);
  349. // Move regitems of All Users
  350. HKEY hkey;
  351. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegStrDESKTOPNAMESPACE, 0, KEY_READ, &hkey))
  352. {
  353. hr = E_FAIL;
  354. }
  355. else
  356. {
  357. _HideRegItemsFromNameSpace(szPath, hkey);
  358. RegCloseKey(hkey);
  359. }
  360. // Move desktop items of All Users
  361. if (FAILED(_SilentProcessUserByRegKey(szPath, c_szRegStrPROFILELIST, c_szRegStrALLUSERS)))
  362. {
  363. hr = E_FAIL;
  364. }
  365. // move desktop items of Default User
  366. if (FAILED(_SilentProcessUserByRegKey(szPath, c_szRegStrPROFILELIST, c_szRegStrDEFAULTUSER)))
  367. {
  368. hr = E_FAIL;
  369. }
  370. // Move desktop items of each normal users
  371. if (FAILED(_SilentProcessUsers(szPath)))
  372. {
  373. hr = E_FAIL;
  374. }
  375. STOPLOGGING;
  376. }
  377. }
  378. }
  379. return hr;
  380. }
  381. BOOL _ShouldPlaceIEDesktopIcon()
  382. {
  383. BOOL fRetVal = TRUE;
  384. DWORD dwData;
  385. DWORD cbData = sizeof(dwData);
  386. if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, c_szRegStrPATH_OCMANAGER, c_szRegStrIEACCESS, NULL, &dwData, &cbData)) &&
  387. (dwData == 0))
  388. {
  389. fRetVal = FALSE;
  390. }
  391. return fRetVal;
  392. }
  393. BOOL _ShouldUseMSNInternetAccessIcon()
  394. {
  395. BOOL fRetVal = FALSE;
  396. TCHAR szBuffer[4];
  397. DWORD cbBuffer = sizeof(szBuffer);
  398. if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, c_szRegStrMSNCODES, c_szRegStrMSN_IAONLY, NULL, szBuffer, &cbBuffer)) &&
  399. (!StrCmpI(szBuffer, TEXT("yes"))))
  400. {
  401. fRetVal = TRUE;
  402. }
  403. return fRetVal;
  404. }
  405. HRESULT _AddIEIconToDesktop()
  406. {
  407. DWORD dwData = 0;
  408. TCHAR szCLSID[MAX_GUID_STRING_LEN];
  409. TCHAR szBuffer[MAX_PATH];
  410. HRESULT hr = SHStringFromGUID(CLSID_Internet, szCLSID, ARRAYSIZE(szCLSID));
  411. if (SUCCEEDED(hr))
  412. {
  413. for (int i = 0; i < 2; i ++)
  414. {
  415. hr = StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), REGSTR_PATH_HIDDEN_DESKTOP_ICONS,
  416. (i == 0) ? c_szVALUE_STARTPANEL : c_szVALUE_CLASSICMENU);
  417. if (SUCCEEDED(hr))
  418. {
  419. SHRegSetUSValue(szBuffer, szCLSID, REG_DWORD, &dwData, sizeof(DWORD), SHREGSET_FORCE_HKLM);
  420. }
  421. }
  422. }
  423. return hr;
  424. }
  425. HRESULT _AddWMPIconToDesktop()
  426. {
  427. // 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
  428. SHRegSetUSValue(c_szRegStrWMP_PATH_SETUP, c_szRegStrWMP_REGVALUE, REG_SZ, c_szRegStrYES, sizeof(TCHAR) * (ARRAYSIZE(c_szRegStrYES) + 1), SHREGSET_FORCE_HKLM);
  429. HRESULT hr;
  430. TCHAR szBuffer[MAX_PATH];
  431. TCHAR szSourcePath[MAX_PATH];
  432. TCHAR szDestPath[MAX_PATH];
  433. // we get docs and settings\all users\start menu\programs
  434. hr = SHGetSpecialFolderPath(NULL, szSourcePath, CSIDL_COMMON_PROGRAMS, FALSE);
  435. if (SUCCEEDED(hr))
  436. {
  437. // strip it down to docs and settings\all users, using szDestPath as a temp buffer
  438. hr = StringCchCopy(szDestPath, ARRAYSIZE(szDestPath), szSourcePath);
  439. if (SUCCEEDED(hr))
  440. {
  441. if (!PathRemoveFileSpec(szSourcePath) || // remove Programs
  442. !PathRemoveFileSpec(szSourcePath)) // remove Start Menu
  443. {
  444. hr = E_FAIL;
  445. }
  446. else
  447. {
  448. hr = StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), szDestPath + lstrlen(szSourcePath));
  449. if (SUCCEEDED(hr))
  450. {
  451. // load "Default user" into szDestPath
  452. LoadString(g_hInst, IDS_DEFAULTUSER, szDestPath, ARRAYSIZE(szDestPath));
  453. if (!PathRemoveFileSpec(szSourcePath) || // remove All Users, now szSourcePath is "docs and settings"
  454. !PathAppend(szSourcePath, szDestPath)) // now szSourcePath is "docs and settings\Default User"
  455. {
  456. hr = E_FAIL;
  457. }
  458. else
  459. {
  460. // sanity check, localizers may have inappropriately localized Default User on a system where it shouldn't be localized
  461. if (!PathIsDirectory(szSourcePath))
  462. {
  463. // if so, remove what they gave us and just add the English "Default User", which is what it is on most machines
  464. if (!PathRemoveFileSpec(szSourcePath) ||
  465. !PathAppend(szSourcePath, c_szRegStrDEFAULTUSER))
  466. {
  467. hr = E_FAIL;
  468. }
  469. }
  470. if (SUCCEEDED(hr))
  471. {
  472. if (!PathAppend(szSourcePath, szBuffer))
  473. {
  474. hr = E_FAIL;
  475. }
  476. else
  477. {
  478. // now szSourcePath is docs and settings\Default User\start menu\programs
  479. hr = SHGetSpecialFolderPath(NULL, szDestPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
  480. if (SUCCEEDED(hr))
  481. {
  482. LoadString(g_hInst, IDS_WMP, szBuffer, ARRAYSIZE(szBuffer));
  483. if (!PathAppend(szSourcePath, szBuffer) ||
  484. !PathAppend(szDestPath, szBuffer) ||
  485. !CopyFileEx(szSourcePath, szDestPath, 0, 0, 0, COPY_FILE_FAIL_IF_EXISTS))
  486. {
  487. hr = E_FAIL;
  488. }
  489. else
  490. {
  491. hr = S_OK;
  492. }
  493. }
  494. }
  495. }
  496. }
  497. }
  498. }
  499. }
  500. }
  501. return hr;
  502. }
  503. HRESULT _AddMSNIconToDesktop(BOOL fUseMSNExplorerIcon)
  504. {
  505. HRESULT hr = E_FAIL;
  506. TCHAR szBuffer[MAX_PATH];
  507. TCHAR szSourcePath[MAX_PATH];
  508. TCHAR szDestPath[MAX_PATH];
  509. if ((SUCCEEDED(SHGetSpecialFolderPath(NULL, szSourcePath, CSIDL_COMMON_PROGRAMS, FALSE))) &&
  510. (SUCCEEDED(SHGetSpecialFolderPath(NULL, szDestPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE))))
  511. {
  512. if (fUseMSNExplorerIcon)
  513. {
  514. LoadString(g_hInst, IDS_MSN, szBuffer, ARRAYSIZE(szBuffer)); // MSN Explorer
  515. }
  516. else
  517. {
  518. LoadString(g_hInst, IDS_MSN_ALT, szBuffer, ARRAYSIZE(szBuffer)); // Get Online With MSN
  519. }
  520. if (PathAppend(szSourcePath, szBuffer) &&
  521. PathAppend(szDestPath, szBuffer))
  522. {
  523. if (CopyFileEx(szSourcePath, szDestPath, 0, 0, 0, COPY_FILE_FAIL_IF_EXISTS))
  524. {
  525. hr = S_OK;
  526. }
  527. }
  528. }
  529. return hr;
  530. }
  531. void CreateDesktopIcons()
  532. {
  533. BOOL fIEDesktopIcon = _ShouldPlaceIEDesktopIcon();
  534. _AddWMPIconToDesktop();
  535. if (fIEDesktopIcon)
  536. {
  537. _AddIEIconToDesktop();
  538. }
  539. _AddMSNIconToDesktop(fIEDesktopIcon || !_ShouldUseMSNInternetAccessIcon());
  540. }