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.

1214 lines
39 KiB

  1. #include "pch.hxx"
  2. #include <regutil.h>
  3. #include "msident.h"
  4. #include <initguid.h>
  5. #include <ourguid.h>
  6. #include "strings.h"
  7. #include "util.h"
  8. #include "migerror.h"
  9. // Sections of INF corresponding to versions
  10. const LPCTSTR c_szSects[] = { c_szVERnone, c_szVER1_0, c_szVER1_1, c_szVER4_0, c_szVER5B1, c_szVER5_0, c_szVERnone, c_szVERnone, c_szVERnone };
  11. void SetUrlDllDefault(BOOL fMailTo);
  12. /****************************************************************************
  13. NAME: NTReboot
  14. ****************************************************************************/
  15. BOOL NTReboot()
  16. {
  17. HANDLE hToken;
  18. TOKEN_PRIVILEGES tkp;
  19. // get a token from this process
  20. if (OpenProcessToken(GetCurrentProcess(),
  21. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
  22. {
  23. // get the LUID for the shutdown privilege
  24. LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid );
  25. tkp.PrivilegeCount = 1;
  26. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  27. //get the shutdown privilege for this proces
  28. if (AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0))
  29. // shutdown the system and force all applications to close
  30. if (!ExitWindowsEx( EWX_REBOOT, 0 ) )
  31. return TRUE;
  32. }
  33. return TRUE;
  34. }
  35. /****************************************************************************
  36. NAME: Reboot
  37. ****************************************************************************/
  38. // Based on Advpack code...
  39. void Reboot(BOOL bAsk)
  40. {
  41. UINT id;
  42. id = bAsk ? MsgBox(NULL, IDS_RESTARTYESNO, MB_ICONINFORMATION, MB_YESNO) : IDYES;
  43. if (IDYES == id)
  44. if (VER_PLATFORM_WIN32_WINDOWS == si.osv.dwPlatformId)
  45. // By default (all platforms), we assume powerdown is possible
  46. ExitWindowsEx( EWX_REBOOT, 0 );
  47. else
  48. NTReboot();
  49. }
  50. /****************************************************************************
  51. NAME: OKDespiteDependencies
  52. SYNOPSIS: Make sure the user is aware that uninstalling us will break
  53. apps that use us
  54. ****************************************************************************/
  55. BOOL OKDespiteDependencies(void)
  56. {
  57. WORD wVerGold[4] = {4,72,2106,0};
  58. WORD wVerSP1[4] = {4,72,3110,0};
  59. BOOL fGold;
  60. BOOL fSP1;
  61. BOOL fOK = TRUE;
  62. WORD wVerPrev[4];
  63. WORD wVer[4];
  64. TCHAR szExe[MAX_PATH];
  65. HKEY hkey;
  66. DWORD cb, dwDisable;
  67. int iRet;
  68. LOG("Checking Product dependencies...");
  69. switch (si.saApp)
  70. {
  71. case APP_WAB:
  72. break;
  73. case APP_OE:
  74. if (si.fPrompt)
  75. {
  76. DWORD dwVerInfoSize, dwVerHnd;
  77. LPSTR lpInfo, lpVersion;
  78. LPWORD lpwTrans;
  79. UINT uLen;
  80. TCHAR szGet[MAX_PATH];
  81. // What version would we return to?
  82. GetVers(NULL, wVerPrev);
  83. // Is that good enough for SP1?
  84. if (fSP1 = GoodEnough(wVerPrev, wVerSP1))
  85. {
  86. // Yep, must be good enough for 4.01 too
  87. fGold = TRUE;
  88. }
  89. else
  90. fGold = GoodEnough(wVerPrev, wVerGold);
  91. // Is OL Installed?
  92. if (GetExePath(c_szOutlookExe, szExe, ARRAYSIZE(szExe), FALSE))
  93. {
  94. // Reg entry exists, does the EXE it points to?
  95. if(0xFFFFFFFF != GetFileAttributes(szExe))
  96. {
  97. LOG("Found Outlook...");
  98. // Figure out the version
  99. if (dwVerInfoSize = GetFileVersionInfoSize(szExe, &dwVerHnd))
  100. {
  101. if (lpInfo = (LPSTR)GlobalAlloc(GPTR, dwVerInfoSize))
  102. {
  103. if (GetFileVersionInfo(szExe, 0, dwVerInfoSize, lpInfo))
  104. {
  105. if (VerQueryValue(lpInfo, "\\VarFileInfo\\Translation", (LPVOID *)&lpwTrans, &uLen) &&
  106. uLen >= (2 * sizeof(WORD)))
  107. {
  108. // set up buffer for calls to VerQueryValue()
  109. wnsprintf(szGet, ARRAYSIZE(szGet), "\\StringFileInfo\\%04X%04X\\FileVersion", lpwTrans[0], lpwTrans[1]);
  110. if (VerQueryValue(lpInfo, szGet, (LPVOID *)&lpVersion, &uLen) && uLen)
  111. {
  112. ConvertStrToVer(lpVersion, wVer);
  113. // Check for OL98
  114. if (8 == wVer[0] && 5 == wVer[1])
  115. {
  116. LOG2("98");
  117. fOK = fGold;
  118. }
  119. else if (wVer[0] >= 9)
  120. {
  121. LOG2("2000+");
  122. fOK = fSP1;
  123. // Allow for future OLs to disable this check
  124. if (!fOK && ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, si.pszVerInfo, 0, KEY_QUERY_VALUE, &hkey))
  125. {
  126. dwDisable = 0;
  127. cb = sizeof(dwDisable);
  128. if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szDisableOLCheck, 0, NULL, (LPBYTE)&dwDisable, &cb))
  129. {
  130. if (dwDisable > 0)
  131. {
  132. LOG2("...Disabled via reg");
  133. fOK = TRUE;
  134. }
  135. }
  136. RegCloseKey(hkey);
  137. }
  138. }
  139. else
  140. {
  141. LOG2("97");
  142. }
  143. if (fOK)
  144. {
  145. LOG2("...OK to uninstall");
  146. }
  147. else
  148. {
  149. LOG2("...Not safe to uninstall");
  150. // Potentially have a problem - ask user
  151. iRet = MsgBox(NULL, IDS_WARN_OL, MB_ICONEXCLAMATION, MB_YESNO | MB_DEFBUTTON2);
  152. if (IDYES == iRet)
  153. fOK = TRUE;
  154. }
  155. }
  156. }
  157. }
  158. GlobalFree((HGLOBAL)lpInfo);
  159. }
  160. }
  161. }
  162. }
  163. // Is MS Phone Installed?
  164. if (fOK && GetExePath(c_szPhoneExe, szExe, ARRAYSIZE(szExe), FALSE))
  165. {
  166. // Reg entry exists, does the EXE it points to?
  167. if(0xFFFFFFFF != GetFileAttributes(szExe))
  168. {
  169. LOG("Found MSPhone...");
  170. fOK = fSP1;
  171. // Allow for future Phones to disable this check
  172. if (!fOK && ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, si.pszVerInfo, 0, KEY_QUERY_VALUE, &hkey))
  173. {
  174. dwDisable = 0;
  175. cb = sizeof(dwDisable);
  176. if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szDisablePhoneCheck, 0, NULL, (LPBYTE)&dwDisable, &cb))
  177. {
  178. if (dwDisable > 0)
  179. {
  180. LOG2("...Disabled via reg...");
  181. fOK = TRUE;
  182. }
  183. }
  184. RegCloseKey(hkey);
  185. }
  186. if (fOK)
  187. {
  188. LOG2("OK to uninstall");
  189. }
  190. else
  191. {
  192. LOG2("Not safe to uninstall");
  193. // Potentially have a problem - ask user
  194. iRet = MsgBox(NULL, IDS_WARN_PHONE, MB_ICONEXCLAMATION, MB_YESNO | MB_DEFBUTTON2);
  195. if (IDYES == iRet)
  196. {
  197. fOK = TRUE;
  198. }
  199. }
  200. }
  201. }
  202. }
  203. break;
  204. default:
  205. break;
  206. }
  207. return fOK;
  208. }
  209. /*++
  210. Routine Description:
  211. There is a significant difference between the Win3.1 and Win32
  212. behavior of RegDeleteKey when the key in question has subkeys.
  213. The Win32 API does not allow you to delete a key with subkeys,
  214. while the Win3.1 API deletes a key and all its subkeys.
  215. This routine is a recursive worker that enumerates the subkeys
  216. of a given key, applies itself to each one, then deletes itself.
  217. It specifically does not attempt to deal rationally with the
  218. case where the caller may not have access to some of the subkeys
  219. of the key to be deleted. In this case, all the subkeys which
  220. the caller can delete will be deleted, but the api will still
  221. return ERROR_ACCESS_DENIED.
  222. Arguments:
  223. hKey - Supplies a handle to an open registry key.
  224. lpszSubKey - Supplies the name of a subkey which is to be deleted
  225. along with all of its subkeys.
  226. Return Value:
  227. ERROR_SUCCESS - entire subtree successfully deleted.
  228. ERROR_ACCESS_DENIED - given subkey could not be deleted.
  229. --*/
  230. LONG RegDeleteKeyRecursive(HKEY hKey, LPCTSTR lpszSubKey)
  231. {
  232. DWORD i;
  233. HKEY Key;
  234. LONG Status;
  235. DWORD ClassLength=0;
  236. DWORD SubKeys;
  237. DWORD MaxSubKey;
  238. DWORD MaxClass;
  239. DWORD Values;
  240. DWORD MaxValueName;
  241. DWORD MaxValueData;
  242. DWORD SecurityLength;
  243. FILETIME LastWriteTime;
  244. LPTSTR NameBuffer;
  245. //
  246. // First open the given key so we can enumerate its subkeys
  247. //
  248. Status = RegOpenKeyEx(hKey,
  249. lpszSubKey,
  250. 0,
  251. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
  252. &Key);
  253. if (Status != ERROR_SUCCESS)
  254. {
  255. //
  256. // possibly we have delete access, but not enumerate/query.
  257. // So go ahead and try the delete call, but don't worry about
  258. // any subkeys. If we have any, the delete will fail anyway.
  259. //
  260. return(RegDeleteKey(hKey,lpszSubKey));
  261. }
  262. //
  263. // Use RegQueryInfoKey to determine how big to allocate the buffer
  264. // for the subkey names.
  265. //
  266. Status = RegQueryInfoKey(Key,
  267. NULL,
  268. &ClassLength,
  269. 0,
  270. &SubKeys,
  271. &MaxSubKey,
  272. &MaxClass,
  273. &Values,
  274. &MaxValueName,
  275. &MaxValueData,
  276. &SecurityLength,
  277. &LastWriteTime);
  278. if ((Status != ERROR_SUCCESS) &&
  279. (Status != ERROR_MORE_DATA) &&
  280. (Status != ERROR_INSUFFICIENT_BUFFER))
  281. {
  282. RegCloseKey(Key);
  283. return(Status);
  284. }
  285. if (!MemAlloc((void **)&NameBuffer, sizeof(TCHAR) * (MaxSubKey + 1)))
  286. {
  287. RegCloseKey(Key);
  288. return(ERROR_NOT_ENOUGH_MEMORY);
  289. }
  290. //
  291. // Enumerate subkeys and apply ourselves to each one.
  292. //
  293. i = 0;
  294. do {
  295. Status = RegEnumKey(Key,
  296. i,
  297. NameBuffer,
  298. MaxSubKey+1);
  299. if (Status == ERROR_SUCCESS)
  300. {
  301. Status = RegDeleteKeyRecursive(Key,NameBuffer);
  302. }
  303. if (Status != ERROR_SUCCESS)
  304. {
  305. //
  306. // Failed to delete the key at the specified index. Increment
  307. // the index and keep going. We could probably bail out here,
  308. // since the api is going to fail, but we might as well keep
  309. // going and delete everything we can.
  310. //
  311. ++i;
  312. }
  313. } while ( (Status != ERROR_NO_MORE_ITEMS) &&
  314. (i < SubKeys) );
  315. MemFree(NameBuffer);
  316. RegCloseKey(Key);
  317. return(RegDeleteKey(hKey,lpszSubKey));
  318. }
  319. // v1 store struct
  320. typedef struct tagCACHEFILEHDR
  321. {
  322. DWORD dwMagic;
  323. DWORD ver;
  324. DWORD cMsg;
  325. DWORD cbValid;
  326. DWORD dwFlags;
  327. DWORD verBlob;
  328. DWORD dwReserved[14];
  329. } CACHEFILEHDR;
  330. /*******************************************************************
  331. NAME: HandleInterimOE
  332. SYNOPSIS: Tries to unmangle a machine that has had an
  333. intermediate, non-gold version on it
  334. ********************************************************************/
  335. void HandleInterimOE(SETUPVER sv, SETUPVER svReal)
  336. {
  337. switch(sv)
  338. {
  339. case VER_5_0_B1:
  340. LPCTSTR pszRoot = NULL;
  341. LPTSTR pszStore;
  342. LPTSTR pszCmd;
  343. LPCTSTR pszOption;
  344. TCHAR szStorePath [MAX_PATH];
  345. TCHAR szStoreExpanded[MAX_PATH];
  346. TCHAR szExePath [MAX_PATH];
  347. TCHAR szTemp [2*MAX_PATH + 20];
  348. HKEY hkeySrc, hkeyT;
  349. DWORD cb, dwType, dw;
  350. STARTUPINFO sti;
  351. PROCESS_INFORMATION pi;
  352. // Find the OE5 Beta1 store root
  353. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegRoot, 0, KEY_QUERY_VALUE, &hkeySrc))
  354. {
  355. cb = sizeof(szStorePath);
  356. if (ERROR_SUCCESS == RegQueryValueEx(hkeySrc, c_szRegStoreRootDir, 0, &dwType, (LPBYTE)szStorePath, &cb))
  357. {
  358. ZeroMemory(szStoreExpanded, ARRAYSIZE(szStoreExpanded));
  359. ExpandEnvironmentStrings(szStorePath, szStoreExpanded, ARRAYSIZE(szStoreExpanded));
  360. switch (svReal)
  361. {
  362. case VER_1_0:
  363. case VER_1_1:
  364. BOOL fContinue;
  365. BOOL fRet;
  366. dwType = REG_SZ;
  367. pszStore= szStoreExpanded;
  368. pszRoot = c_szRegRoot_V1;
  369. pszOption = c_szV1;
  370. HANDLE hndl;
  371. HANDLE hFile;
  372. WIN32_FIND_DATA fd;
  373. CACHEFILEHDR cfh;
  374. // Downgrade .idx files
  375. StrCpyN(szTemp, szStoreExpanded, ARRAYSIZE(szTemp));
  376. cb = lstrlen(szTemp);
  377. if ('\\' != *CharPrev(szTemp, szTemp+cb))
  378. szTemp[cb++] = '\\';
  379. StrCpyN(&szTemp[cb], c_szMailSlash, ARRAYSIZE(szTemp)-cb);
  380. cb += 5; // lstrlen(c_szMailSlash)
  381. StrCpyN(&szTemp[cb], c_szStarIDX, ARRAYSIZE(szTemp)-cb);
  382. hndl = FindFirstFile(szTemp, &fd);
  383. fContinue = (INVALID_HANDLE_VALUE != hndl);
  384. if (fContinue)
  385. {
  386. while (fContinue)
  387. {
  388. // Skip directories
  389. if (0 == (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  390. {
  391. // Append the filename to the path
  392. StrCpyN(&szTemp[cb], fd.cFileName, ARRAYSIZE(szTemp)-cb);
  393. // Open the file
  394. hFile = CreateFile(szTemp, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  395. if (hFile != INVALID_HANDLE_VALUE)
  396. {
  397. fRet = ReadFile(hFile, &cfh, sizeof(CACHEFILEHDR), &dw, NULL);
  398. Assert(dw == sizeof(CACHEFILEHDR));
  399. if (fRet)
  400. {
  401. // Reset the version to be low, so v1 will attempt to repair it
  402. cfh.verBlob = 1;
  403. dw = SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
  404. Assert(dw == 0);
  405. fRet = WriteFile(hFile, &cfh, sizeof(CACHEFILEHDR), &dw, NULL);
  406. Assert(fRet);
  407. Assert(dw == sizeof(CACHEFILEHDR));
  408. }
  409. CloseHandle(hFile);
  410. }
  411. }
  412. fContinue = FindNextFile(hndl, &fd);
  413. }
  414. FindClose(hndl);
  415. }
  416. break;
  417. case VER_4_0:
  418. pszStore = szStorePath;
  419. pszRoot = c_szRegFlat;
  420. pszOption = c_szV4;
  421. break;
  422. }
  423. // If we are going to v1 or v4...
  424. if (pszRoot)
  425. {
  426. dw= (DWORD)E_FAIL;
  427. // Reverse migrate the store
  428. // BUGBUG: 45426 - neilbren
  429. // Should key off InstallRoot but can't seem to keep that setting around
  430. // Try to find the path to oemig50.exe
  431. if (GetModuleFileName(NULL, szTemp, ARRAYSIZE(szTemp)))
  432. {
  433. // Strip exe name and slash
  434. PathRemoveFileSpec(szTemp);
  435. // Add slash and exe name
  436. wnsprintf(szExePath, ARRAYSIZE(szExePath), c_szPathFileFmt, szTemp, c_szMigrationExe);
  437. pszCmd = szExePath;
  438. }
  439. // Otherwise, just try local directory
  440. else
  441. {
  442. pszCmd = (LPTSTR)c_szMigrationExe;
  443. }
  444. // Form the command
  445. wnsprintf(szTemp, ARRAYSIZE(szTemp), c_szMigFmt, pszCmd, pszOption, pszStore);
  446. // Zero startup info
  447. ZeroMemory(&sti, sizeof(STARTUPINFO));
  448. sti.cb = sizeof(STARTUPINFO);
  449. // run oemig50.exe
  450. if (CreateProcess(NULL, szTemp, NULL, NULL, FALSE, 0, NULL, NULL, &sti, &pi))
  451. {
  452. // Wait for the process to finish
  453. WaitForSingleObject(pi.hProcess, INFINITE);
  454. // Get the Exit Process Code
  455. GetExitCodeProcess(pi.hProcess, &dw);
  456. // Close the Thread
  457. CloseHandle(pi.hThread);
  458. // Close the Process
  459. CloseHandle(pi.hProcess);
  460. }
  461. // Patch up the store root for version we are returning to
  462. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, pszRoot, 0, KEY_SET_VALUE, &hkeyT))
  463. {
  464. RegSetValueEx(hkeyT, c_szRegStoreRootDir, 0, dwType, (LPBYTE)pszStore, (lstrlen(pszStore) + 1) * sizeof(TCHAR));
  465. RegCloseKey(hkeyT);
  466. }
  467. }
  468. }
  469. RegCloseKey(hkeySrc);
  470. }
  471. break;
  472. }
  473. }
  474. /*******************************************************************
  475. NAME: ConfigureOldVer
  476. SYNOPSIS: Calls into INF to config older version
  477. ********************************************************************/
  478. void ConfigureOldVer()
  479. {
  480. TCHAR szSectionName[128];
  481. TCHAR szInfFile[MAX_PATH];
  482. BOOL bUser = (TIME_USER == si.stTime);
  483. SETUPVER sv, svInterim;
  484. GetVerInfo(&sv, NULL);
  485. // Patch up User or Machine
  486. if (sv < VER_MAX)
  487. {
  488. wnsprintf(szInfFile, ARRAYSIZE(szInfFile), c_szFileEntryFmt, si.szInfDir, si.pszInfFile);
  489. wnsprintf(szSectionName, ARRAYSIZE(szSectionName), bUser ? c_szUserRevertFmt : c_szMachineRevertFmt, c_szSects[sv]);
  490. (*si.pfnRunSetup)(NULL, szInfFile, szSectionName, si.szInfDir, si.szAppName, NULL,
  491. RSC_FLAG_INF | (bUser ? 0 : RSC_FLAG_NGCONV) | OE_QUIET, 0);
  492. }
  493. // Handle interim builds (user only)
  494. if (bUser && InterimBuild(&svInterim))
  495. {
  496. switch(si.saApp)
  497. {
  498. case APP_OE:
  499. HandleInterimOE(svInterim, sv);
  500. break;
  501. }
  502. }
  503. }
  504. /*******************************************************************
  505. NAME: SelectNewClient
  506. ********************************************************************/
  507. void SelectNewClient(LPCTSTR pszClient)
  508. {
  509. BOOL fMail;
  510. BOOL fNone = TRUE;
  511. SETUPVER sv;
  512. PFN_ISETDEFCLIENT pfn;
  513. if (!lstrcmpi(pszClient, c_szNews))
  514. {
  515. pfn = ISetDefaultNewsHandler;
  516. fMail = FALSE;
  517. }
  518. else
  519. {
  520. pfn = ISetDefaultMailHandler;
  521. fMail = TRUE;
  522. }
  523. // If we went IMN to 5.0, we will show up as NOT_HANDLED as our subkeys are gone by now
  524. if ((HANDLED_CURR == DefaultClientSet(pszClient)) || (NOT_HANDLED == DefaultClientSet(pszClient)))
  525. {
  526. GetVerInfo(&sv, NULL);
  527. switch (sv)
  528. {
  529. case VER_4_0:
  530. // If prev ver was 4.0x, could have been Outlook News Reader
  531. if (FValidClient(pszClient, c_szMOE))
  532. {
  533. (*pfn)(c_szMOE, 0);
  534. fNone = FALSE;
  535. }
  536. else if (FValidClient(pszClient, c_szOutlook))
  537. {
  538. (*pfn)(c_szOutlook, 0);
  539. fNone = FALSE;
  540. }
  541. break;
  542. case VER_1_0:
  543. // If prev ver was 1.0, IMN may or may not be around (cool, eh?)
  544. if (FValidClient(pszClient, c_szIMN))
  545. {
  546. (*pfn)(c_szIMN, 0);
  547. fNone = FALSE;
  548. }
  549. break;
  550. }
  551. }
  552. if (fNone)
  553. {
  554. (*pfn)(_T(""), 0);
  555. SetUrlDllDefault(fMail);
  556. }
  557. }
  558. /*******************************************************************
  559. NAME: SelectNewClients
  560. ********************************************************************/
  561. void SelectNewClients()
  562. {
  563. switch (si.saApp)
  564. {
  565. case APP_OE:
  566. SelectNewClient(c_szNews);
  567. SelectNewClient(c_szMail);
  568. break;
  569. case APP_WAB:
  570. default:
  571. break;
  572. }
  573. }
  574. /*******************************************************************
  575. NAME: UpdateVersionInfo
  576. ********************************************************************/
  577. void UpdateVersionInfo()
  578. {
  579. HKEY hkeyT;
  580. DWORD dwType, cb;
  581. TCHAR szT[50]={0};
  582. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, si.pszVerInfo, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkeyT))
  583. {
  584. cb = sizeof(szT);
  585. if (CALLER_IE == si.caller)
  586. {
  587. RegQueryValueEx(hkeyT, c_szRegPrevVer, NULL, &dwType, (LPBYTE)szT, &cb);
  588. RegSetValueEx(hkeyT, c_szRegCurrVer, 0, REG_SZ, (LPBYTE)szT, (lstrlen(szT) + 1) * sizeof(TCHAR));
  589. }
  590. else
  591. // Special case OS installs that can uninstall OE
  592. // As there is no rollback, current version should become nothing
  593. RegSetValueEx(hkeyT, c_szRegCurrVer, 0, REG_SZ, (LPBYTE)c_szBLDnone, (lstrlen(c_szBLDnone) + 1) * sizeof(TCHAR));
  594. RegSetValueEx(hkeyT, c_szRegPrevVer, 0, REG_SZ, (LPBYTE)c_szBLDnone, (lstrlen(c_szBLDnone) + 1) * sizeof(TCHAR));
  595. RegCloseKey(hkeyT);
  596. }
  597. }
  598. /*******************************************************************
  599. NAME: PreRollback
  600. ********************************************************************/
  601. void PreRollback()
  602. {
  603. switch (si.saApp)
  604. {
  605. case APP_OE:
  606. RegisterExes(FALSE);
  607. break;
  608. case APP_WAB:
  609. default:
  610. break;
  611. }
  612. }
  613. /*******************************************************************
  614. NAME: CreateWinLinks
  615. SYNOPSIS: Generates special files in Windows Directory
  616. ********************************************************************/
  617. void CreateWinLinks()
  618. {
  619. UINT uLen, cb;
  620. TCHAR szPath[MAX_PATH];
  621. TCHAR szDesc[CCHMAX_STRINGRES];
  622. HANDLE hFile;
  623. StrCpyN(szPath, si.szWinDir, ARRAYSIZE(szPath));
  624. uLen = lstrlen(szPath);
  625. // generate the link description
  626. cb = LoadString(g_hInstance, IDS_OLD_MAIL, szDesc, ARRAYSIZE(szDesc));
  627. // ---- MAIL
  628. StrCpyN(&szPath[uLen], szDesc, ARRAYSIZE(szPath)-uLen);
  629. cb += uLen;
  630. StrCpyN(&szPath[cb], c_szMailGuid, ARRAYSIZE(szPath)-cb);
  631. // create the link target
  632. hFile = CreateFile(szPath, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
  633. NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  634. if (hFile != INVALID_HANDLE_VALUE)
  635. CloseHandle(hFile);
  636. // ---- NEWS
  637. cb = LoadString(g_hInstance, IDS_OLD_NEWS, szDesc, ARRAYSIZE(szDesc));
  638. // generate the path to the link target
  639. StrCpyN(&szPath[uLen], szDesc, ARRAYSIZE(szPath)-uLen);
  640. cb += uLen;
  641. StrCpyN(&szPath[cb], c_szNewsGuid, ARRAYSIZE(szPath)-cb);
  642. // create the link target
  643. hFile = CreateFile(szPath, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
  644. NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  645. if (hFile != INVALID_HANDLE_VALUE)
  646. CloseHandle(hFile);
  647. }
  648. /*******************************************************************
  649. NAME: PostRollback
  650. ********************************************************************/
  651. void PostRollback()
  652. {
  653. SETUPVER sv;
  654. GetVerInfo(&sv, NULL);
  655. switch (si.saApp)
  656. {
  657. case APP_OE:
  658. if (VER_1_0 == sv)
  659. CreateWinLinks();
  660. break;
  661. case APP_WAB:
  662. default:
  663. break;
  664. }
  665. }
  666. #if 0
  667. /*******************************************************************
  668. NAME: RemoveJIT
  669. ********************************************************************/
  670. void RemoveJIT()
  671. {
  672. HKEY hkey;
  673. DWORD cb, dw;
  674. TCHAR szPath[MAX_PATH], szExpanded[MAX_PATH];
  675. LPTSTR pszPath;
  676. switch (si.saApp)
  677. {
  678. case APP_OE:
  679. // WAB
  680. wnsprintf(szPath, ARRAYSIZE(szPath), c_szPathFileFmt, c_szRegUninstall, c_szRegUninstallWAB);
  681. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szPath, 0, KEY_QUERY_VALUE, &hkey))
  682. {
  683. cb = sizeof(szPath);
  684. if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szQuietUninstall, 0, &dw, (LPBYTE)szPath, &cb))
  685. {
  686. STARTUPINFO sti;
  687. PROCESS_INFORMATION pi;
  688. if (REG_EXPAND_SZ == dw)
  689. {
  690. ZeroMemory(szExpanded, ARRAYSIZE(szExpanded));
  691. ExpandEnvironmentStrings(szPath, szExpanded, ARRAYSIZE(szExpanded));
  692. pszPath = szExpanded;
  693. }
  694. else
  695. pszPath = szPath;
  696. ZeroMemory(&sti, sizeof(STARTUPINFO));
  697. sti.cb = sizeof(STARTUPINFO);
  698. if (CreateProcess(NULL, pszPath, NULL, NULL, FALSE, 0, NULL, NULL, &sti, &pi))
  699. {
  700. WaitForSingleObject(pi.hProcess, INFINITE);
  701. GetExitCodeProcess(pi.hProcess, &dw);
  702. CloseHandle(pi.hThread);
  703. CloseHandle(pi.hProcess);
  704. }
  705. }
  706. RegCloseKey(hkey);
  707. }
  708. break;
  709. case APP_WAB:
  710. default:
  711. break;
  712. }
  713. }
  714. #endif
  715. /*******************************************************************
  716. NAME: RequiredIE
  717. SYNOPSIS: Requires IE5 for uninstall
  718. ********************************************************************/
  719. BOOL RequiredIE()
  720. {
  721. HKEY hkey;
  722. TCHAR szVer[VERLEN];
  723. BOOL fOK = FALSE;
  724. DWORD cb;
  725. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szIEKey, 0, KEY_READ, &hkey))
  726. {
  727. cb = ARRAYSIZE(szVer);
  728. if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szValueVersion, 0, NULL, (LPBYTE)szVer, &cb))
  729. {
  730. WORD wVer[4];
  731. WORD wVerOE[4] = {5,0,0,0};
  732. ConvertStrToVer(szVer, wVer);
  733. if (!(fOK = GoodEnough(wVer, wVerOE)))
  734. LOG("[WARNING]: Insufficient IE for uninstall");
  735. }
  736. RegCloseKey(hkey);
  737. }
  738. return fOK;
  739. }
  740. /*******************************************************************
  741. NAME: UnInstallMachine
  742. SYNOPSIS: Handles Application uninstallation
  743. ********************************************************************/
  744. BOOL UnInstallMachine()
  745. {
  746. HRESULT hr = E_FAIL;
  747. TCHAR szArgs[2 * MAX_PATH];
  748. TCHAR szInfFile[MAX_PATH];
  749. UINT uID;
  750. // Require at least IE 5 to uninstall
  751. if (!RequiredIE() && (si.fPrompt ? (IDNO == MsgBox(NULL, IDS_WARN_OLDIE, MB_ICONEXCLAMATION, MB_YESNO | MB_DEFBUTTON2)) : TRUE))
  752. {
  753. LOG("[ERROR] Setup canceled");
  754. return FALSE;
  755. }
  756. switch (si.saApp)
  757. {
  758. case APP_OE:
  759. uID = IDS_UNINSTALL_OE;
  760. break;
  761. case APP_WAB:
  762. uID = IDS_UNINSTALL_WAB;
  763. break;
  764. default:
  765. return FALSE;
  766. }
  767. // Make sure the user really wants to uninstall and there is nothing preventing it
  768. if (IDNO == MsgBox(NULL, uID, MB_YESNO, MB_ICONEXCLAMATION ) ||
  769. !OKDespiteDependencies())
  770. {
  771. LOG("[ERROR] Setup canceled");
  772. return FALSE;
  773. }
  774. // We'll need to move files around and write to HKLM, so require admin privs
  775. if (!IsNTAdmin())
  776. {
  777. LOG("[ERROR] User does not have administrative privileges")
  778. MsgBox(NULL, IDS_NO_ADMIN_PRIVILEGES, MB_ICONSTOP, MB_OK);
  779. return FALSE;
  780. }
  781. // Update version info in the reg
  782. UpdateVersionInfo();
  783. wnsprintf(szInfFile, ARRAYSIZE(szInfFile), c_szFileEntryFmt, si.szInfDir, si.pszInfFile);
  784. if (CALLER_IE == si.caller)
  785. {
  786. // Do any housework before the uninstall
  787. PreRollback();
  788. // UnRegister OCXs (immediately)
  789. (*si.pfnRunSetup)(NULL, szInfFile, c_szUnRegisterOCX, si.szInfDir, si.szAppName, NULL, RSC_FLAG_INF | RSC_FLAG_NGCONV | OE_QUIET, 0);
  790. // Return files to original state
  791. wnsprintf(szArgs, ARRAYSIZE(szArgs), c_szLaunchExFmt, szInfFile, c_szMachineInstallSectionEx, c_szEmpty, ALINF_ROLLBACK | ALINF_NGCONV | OE_QUIET);
  792. hr = (*si.pfnLaunchEx)(NULL, NULL, szArgs, 0);
  793. // Keys off current
  794. PostRollback();
  795. // Patch up Old version so that it runs (keys off current)
  796. ConfigureOldVer();
  797. }
  798. else
  799. {
  800. // Set up the per user stub
  801. (*si.pfnRunSetup)(NULL, szInfFile, c_szGenInstallSection, si.szInfDir, si.szAppName, NULL, RSC_FLAG_INF | RSC_FLAG_NGCONV | OE_QUIET, 0);
  802. }
  803. // Figure out who will be the default handlers now that app is gone
  804. SelectNewClients();
  805. // Uninstall JIT'd in items
  806. // RemoveJIT();
  807. // To simplify matters, we always want our stubs to run (not very ZAW like)
  808. if (si.fPrompt)
  809. Reboot(TRUE);
  810. // Special case Memphis uninstall - no bits to return to, so just remove the icons now
  811. if (CALLER_IE != si.caller)
  812. {
  813. UnInstallUser();
  814. // Destory uninstalling user's installed info in case they install an older version without
  815. // rebooting first
  816. UpdateStubInfo(FALSE);
  817. }
  818. return TRUE;
  819. }
  820. /*******************************************************************
  821. NAME: CleanupPerUser
  822. SYNOPSIS: Handles per user cleanup
  823. ********************************************************************/
  824. void CleanupPerUser()
  825. {
  826. switch (si.saApp)
  827. {
  828. case APP_WAB:
  829. // Backwards migrate the connection settings
  830. BackMigrateConnSettings();
  831. break;
  832. default:
  833. break;
  834. }
  835. }
  836. /*******************************************************************
  837. NAME: UnInstallUser
  838. SYNOPSIS: Handles User uninstallation (icons etc)
  839. ********************************************************************/
  840. void UnInstallUser()
  841. {
  842. // Remove desktop and quicklaunch links
  843. HandleLinks(FALSE);
  844. // Call into the correct per user stub
  845. if (CALLER_IE == si.caller)
  846. ConfigureOldVer();
  847. // Handle any per user uninstall cleanup
  848. CleanupPerUser();
  849. if (IsXPSP1OrLater())
  850. {
  851. DeleteKeyRecursively(HKEY_CURRENT_USER, "Software\\Microsoft\\Active Setup\\Installed Components\\>{881dd1c5-3dcf-431b-b061-f3f88e8be88a}");
  852. }
  853. }
  854. /*******************************************************************
  855. NAME: BackMigrateConnSettings
  856. SYNOPSIS: OE4.1 or the versions before that did not have the
  857. connection setting type InternetConnectionSetting. So while
  858. downgrading from OE5 to OE4.1 or prior, we migrate
  859. InternetConnectionSetting to LAN for every account in every identity
  860. *******************************************************************/
  861. void BackMigrateConnSettings()
  862. {
  863. HKEY hKeyAccounts = NULL;
  864. DWORD dwAcctSubKeys = 0;
  865. LONG retval;
  866. DWORD index = 0;
  867. LPTSTR lpszAccountName = NULL;
  868. HKEY hKeyAccountName = NULL;
  869. DWORD memsize = 0;
  870. DWORD dwValue;
  871. DWORD cbData = sizeof(DWORD);
  872. DWORD cbMaxAcctSubKeyLen;
  873. DWORD DataType;
  874. DWORD dwConnSettingsMigrated = 0;
  875. //This setting is in \\HKCU\Software\Microsoft\InternetAccountManager\Accounts
  876. retval = RegOpenKey(HKEY_CURRENT_USER, c_szIAMAccounts, &hKeyAccounts);
  877. if (ERROR_SUCCESS != retval)
  878. goto exit;
  879. retval = RegQueryValueEx(hKeyAccounts, c_szConnSettingsMigrated, NULL, &DataType,
  880. (LPBYTE)&dwConnSettingsMigrated, &cbData);
  881. if ((retval != ERROR_FILE_NOT_FOUND) && (retval != ERROR_SUCCESS || dwConnSettingsMigrated == 0))
  882. goto exit;
  883. retval = RegQueryInfoKey(hKeyAccounts, NULL, NULL, NULL, &dwAcctSubKeys,
  884. &cbMaxAcctSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
  885. if (ERROR_SUCCESS != retval)
  886. goto exit;
  887. memsize = sizeof(TCHAR) * cbMaxAcctSubKeyLen;
  888. if (!MemAlloc((LPVOID*)&lpszAccountName, memsize))
  889. {
  890. lpszAccountName = NULL;
  891. goto exit;
  892. }
  893. ZeroMemory(lpszAccountName, memsize);
  894. while (index < dwAcctSubKeys)
  895. {
  896. retval = RegEnumKey(hKeyAccounts, index, lpszAccountName, memsize);
  897. index++;
  898. if (ERROR_SUCCESS != retval)
  899. continue;
  900. retval = RegOpenKey(hKeyAccounts, lpszAccountName, &hKeyAccountName);
  901. if (ERROR_SUCCESS != retval)
  902. continue;
  903. cbData = sizeof(DWORD);
  904. retval = RegQueryValueEx(hKeyAccountName, c_szConnectionType, NULL, &DataType, (LPBYTE)&dwValue, &cbData);
  905. if (ERROR_SUCCESS != retval)
  906. {
  907. RegCloseKey(hKeyAccountName);
  908. continue;
  909. }
  910. if (dwValue == CONNECTION_TYPE_INETSETTINGS)
  911. {
  912. dwValue = CONNECTION_TYPE_LAN;
  913. retval = RegSetValueEx(hKeyAccountName, c_szConnectionType, 0, REG_DWORD, (const BYTE *)&dwValue,
  914. sizeof(DWORD));
  915. }
  916. RegCloseKey(hKeyAccountName);
  917. }
  918. //Set this to zero so, when we upgrade when we do forward migration based on this key value
  919. dwConnSettingsMigrated = 0;
  920. RegSetValueEx(hKeyAccounts, c_szConnSettingsMigrated, 0, REG_DWORD, (const BYTE*)&dwConnSettingsMigrated,
  921. sizeof(DWORD));
  922. exit:
  923. SafeMemFree(lpszAccountName);
  924. if (hKeyAccounts)
  925. RegCloseKey(hKeyAccounts);
  926. }
  927. const char c_szMailToHandler[] = "rundll32.exe url.dll,MailToProtocolHandler %l";
  928. const char c_szNewsHandler[] = "rundll32.exe url.dll,NewsProtocolHandler %l";
  929. const char c_szDefIcon[] = "DefaultIcon";
  930. const char c_szURLProtocol[] = "URL Protocol";
  931. const char c_szEditFlags[] = "EditFlags";
  932. const char c_szSysDirExpand[] = "%SystemRoot%\\System32";
  933. const char c_szUrlDllIconFmt[] = "%s\\url.dll,%d";
  934. void SetUrlDllDefault(BOOL fMailTo)
  935. {
  936. char sz[MAX_PATH], szIcon[MAX_PATH];
  937. HKEY hkey, hkeyT;
  938. DWORD dw, type;
  939. int cch;
  940. if (si.osv.dwPlatformId == VER_PLATFORM_WIN32_NT)
  941. {
  942. StrCpyN(sz, c_szSysDirExpand, ARRAYSIZE(sz));
  943. type = REG_EXPAND_SZ;
  944. }
  945. else
  946. {
  947. GetSystemDirectory(sz, ARRAYSIZE(sz));
  948. type = REG_SZ;
  949. }
  950. wnsprintf(szIcon, ARRAYSIZE(szIcon), c_szUrlDllIconFmt, sz, fMailTo ? 2 : 1);
  951. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CLASSES_ROOT, fMailTo ? c_szURLMailTo : c_szURLNews, 0, NULL,
  952. REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, &dw))
  953. {
  954. cch = LoadString(g_hInstance, fMailTo ? IDS_URLDLLMAILTONAME : IDS_URLDLLNEWSNAME, sz, ARRAYSIZE(sz)) + 1;
  955. RegSetValueEx(hkey, NULL, 0, REG_SZ, (LPBYTE)sz, cch);
  956. dw = 2;
  957. RegSetValueEx(hkey, c_szEditFlags, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
  958. RegSetValueEx(hkey, c_szURLProtocol, 0, REG_SZ, (LPBYTE)c_szEmpty, 1);
  959. if (ERROR_SUCCESS == RegCreateKeyEx(hkey, c_szDefIcon, 0, NULL,
  960. REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkeyT, &dw))
  961. {
  962. RegSetValueEx(hkeyT, NULL, 0, type, (LPBYTE)szIcon, lstrlen(szIcon) + 1);
  963. RegCloseKey(hkeyT);
  964. }
  965. // c_szRegOpen[1] to skip over slash needed elsewhere
  966. if (ERROR_SUCCESS == RegCreateKeyEx(hkey, &c_szRegOpen[1], 0, NULL,
  967. REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkeyT, &dw))
  968. {
  969. if (fMailTo)
  970. RegSetValueEx(hkeyT, NULL, 0, REG_SZ, (LPBYTE)c_szMailToHandler, sizeof(c_szMailToHandler));
  971. else
  972. RegSetValueEx(hkeyT, NULL, 0, REG_SZ, (LPBYTE)c_szNewsHandler, sizeof(c_szNewsHandler));
  973. RegCloseKey(hkeyT);
  974. }
  975. RegCloseKey(hkey);
  976. }
  977. }