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.

752 lines
27 KiB

  1. #ifndef __cplusplus
  2. #error Install stub code must be C++!
  3. #endif
  4. #ifndef HINST_THISDLL
  5. #error HINST_THISDLL must be defined!
  6. #endif
  7. #ifndef ARRAYSIZE
  8. #define ARRAYSIZE(a) (sizeof(a)/sizeof((a)[0]))
  9. #endif
  10. #include <ccstock.h>
  11. #include <stubres.h>
  12. #include <trayp.h>
  13. #ifdef __cplusplus
  14. extern "C" {
  15. #endif
  16. #include <runonce.c> // shared runonce code for ShellExecuteRegApp()
  17. #ifdef __cplusplus
  18. };
  19. #endif
  20. BOOL CheckWebViewShell();
  21. /* This code runs the install/uninstall stubs recorded in the local-machine
  22. * part of the registry, iff the current user has not had them run in his
  23. * context yet. Used for populating the user's profile with things like
  24. * links to applications.
  25. */
  26. //---------------------------------------------------------------------------
  27. BOOL ProfilesEnabled(void)
  28. {
  29. BOOL fEnabled = FALSE;
  30. if (staticIsOS(OS_NT)) {
  31. fEnabled = TRUE;
  32. }
  33. else {
  34. HKEY hkeyLogon;
  35. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Network\\Logon"), 0,
  36. KEY_QUERY_VALUE, &hkeyLogon) == ERROR_SUCCESS) {
  37. DWORD fProfiles, cbData = sizeof(fProfiles), dwType;
  38. if (RegQueryValueEx(hkeyLogon, TEXT("UserProfiles"), NULL, &dwType,
  39. (LPBYTE)&fProfiles, &cbData) == ERROR_SUCCESS) {
  40. if (dwType == REG_DWORD || (dwType == REG_BINARY && cbData == sizeof(DWORD)))
  41. fEnabled = fProfiles;
  42. }
  43. RegCloseKey(hkeyLogon);
  44. }
  45. }
  46. return fEnabled;
  47. }
  48. // ---------------------------------------------------------------------------
  49. // %%Function: GetVersionFromString
  50. //
  51. // Snarfed from urlmon\download\helpers.cxx.
  52. //
  53. // converts version in text format (a,b,c,d) into two dwords (a,b), (c,d)
  54. // The printed version number is of format a.b.d (but, we don't care)
  55. // ---------------------------------------------------------------------------
  56. HRESULT
  57. GetVersionFromString(LPCTSTR szBuf, LPDWORD pdwFileVersionMS, LPDWORD pdwFileVersionLS)
  58. {
  59. LPCTSTR pch = szBuf;
  60. TCHAR ch;
  61. USHORT n = 0;
  62. USHORT a = 0;
  63. USHORT b = 0;
  64. USHORT c = 0;
  65. USHORT d = 0;
  66. enum HAVE { HAVE_NONE, HAVE_A, HAVE_B, HAVE_C, HAVE_D } have = HAVE_NONE;
  67. *pdwFileVersionMS = 0;
  68. *pdwFileVersionLS = 0;
  69. if (!pch) // default to zero if none provided
  70. return S_OK;
  71. if (lstrcmp(pch, TEXT("-1,-1,-1,-1")) == 0) {
  72. *pdwFileVersionMS = 0xffffffff;
  73. *pdwFileVersionLS = 0xffffffff;
  74. }
  75. for (ch = *pch++;;ch = *pch++) {
  76. if ((ch == ',') || (ch == '\0')) {
  77. switch (have) {
  78. case HAVE_NONE:
  79. a = n;
  80. have = HAVE_A;
  81. break;
  82. case HAVE_A:
  83. b = n;
  84. have = HAVE_B;
  85. break;
  86. case HAVE_B:
  87. c = n;
  88. have = HAVE_C;
  89. break;
  90. case HAVE_C:
  91. d = n;
  92. have = HAVE_D;
  93. break;
  94. case HAVE_D:
  95. return E_INVALIDARG; // invalid arg
  96. }
  97. if (ch == '\0') {
  98. // all done convert a,b,c,d into two dwords of version
  99. *pdwFileVersionMS = ((a << 16)|b);
  100. *pdwFileVersionLS = ((c << 16)|d);
  101. return S_OK;
  102. }
  103. n = 0; // reset
  104. } else if ( (ch < '0') || (ch > '9'))
  105. return E_INVALIDARG; // invalid arg
  106. else
  107. n = n*10 + (ch - '0');
  108. } /* end forever */
  109. // NEVERREACHED
  110. }
  111. // Reg keys and values for install/uninstall stub list. Each subkey under
  112. // HKLM\Software\InstalledComponents is a component identifier (GUID).
  113. // Each subkey has values "Path" for the EXE to run to install or uninstall;
  114. // IsInstalled (dword) indicating whether the component has been installed
  115. // or uninstalled; and an optional Revision (dword) used to refresh a
  116. // component without changing its GUID. Locale (string) is used to describe
  117. // the language/locale for the component; this string is not interpreted by
  118. // the install stub code, it is just compared between the HKLM and HKCU keys.
  119. // If it's different between the two, the stub is re-run.
  120. //
  121. // HKCU\Software\InstalledComponents contains similar GUID subkeys, but the
  122. // only values under each subkey are the optional Revision and Locale values,
  123. // and an optional DontAsk value (also DWORD). Presence of the subkey indicates
  124. // that the component is installed for that user.
  125. //
  126. // If the DontAsk value is present under an HKCU subkey and is non-zero, that
  127. // means that the user has decided to keep their settings for that component
  128. // on all machines, even those that have had the component uninstalled, and
  129. // that they don't want to be asked if they want to run the uninstall stub
  130. // every time they log on. This implies that for that user, the uninstall
  131. // stub will never be run for that component unless the user somehow clears
  132. // the flag.
  133. //
  134. // NOTE: mslocusr.dll also knows these registry paths.
  135. const TCHAR c_szRegInstalledComponentsKey[] = TEXT("Software\\Microsoft\\Active Setup\\Installed Components");
  136. const TCHAR c_szRegInstallStubValue[] = TEXT("StubPath");
  137. const TCHAR c_szRegIsInstalledValue[] = TEXT("IsInstalled");
  138. const TCHAR c_szRegInstallSequenceValue[] = TEXT("Version");
  139. const TCHAR c_szRegDontAskValue[] = TEXT("DontAsk");
  140. const TCHAR c_szRegLocaleValue[] = TEXT("Locale");
  141. UINT ConfirmUninstall(LPCTSTR pszDescription)
  142. {
  143. /* The only case where the user wouldn't want settings cleaned up on
  144. * uninstall would be if they'd roamed to a machine that had had this
  145. * component uninstalled. If user profiles aren't enabled (which is
  146. * the case on a fair number of customers' machines), they're certainly
  147. * not roaming, so there's not much point in asking them. Just pretend
  148. * they said YES, they want to clean up the settings.
  149. */
  150. if (!ProfilesEnabled())
  151. return IDYES;
  152. /* FEATURE - change to a dialog with a checkbox for
  153. * the don't-ask value.
  154. */
  155. TCHAR szTitle[MAX_PATH];
  156. #ifdef USERSTUB
  157. LoadString(HINST_THISDLL, IDS_DESKTOP, szTitle, ARRAYSIZE(szTitle));
  158. #else
  159. MLLoadString(IDS_DESKTOP, szTitle, ARRAYSIZE(szTitle));
  160. #endif
  161. TCHAR szMessageTemplate[MAX_PATH];
  162. LPTSTR pszMessage = NULL;
  163. int cchMessage;
  164. #ifdef USERSTUB
  165. LoadString(HINST_THISDLL, IDS_UNINSTALL, szMessageTemplate, ARRAYSIZE(szMessageTemplate));
  166. #else
  167. MLLoadString(IDS_UNINSTALL, szMessageTemplate, ARRAYSIZE(szMessageTemplate));
  168. #endif
  169. cchMessage = (lstrlen(szMessageTemplate)+lstrlen(pszDescription)+4)*sizeof(TCHAR);
  170. pszMessage = (LPTSTR)LocalAlloc(LPTR, cchMessage);
  171. if (pszMessage)
  172. {
  173. #ifdef USERSTUB
  174. wsprintf(pszMessage, szMessageTemplate, pszDescription);
  175. #else
  176. wnsprintf(pszMessage, cchMessage, szMessageTemplate, pszDescription);
  177. #endif
  178. }
  179. else
  180. {
  181. pszMessage = szMessageTemplate;
  182. }
  183. // due to build in UNICODE the following call is broken under win95, user wsprintf above
  184. //if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING |
  185. // FORMAT_MESSAGE_ARGUMENT_ARRAY,
  186. // (LPVOID)szMessageTemplate,
  187. // 0,
  188. // 0,
  189. // (LPTSTR)&pszMessage,
  190. // 0, /* min chars to allocate */
  191. // (va_list *)&pszDescription)) {
  192. // pszMessage = szMessageTemplate;
  193. //}
  194. UINT idRet = MessageBox(NULL, pszMessage, szTitle,
  195. MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 | MB_SETFOREGROUND | MB_TOPMOST);
  196. if (pszMessage != szMessageTemplate)
  197. LocalFree(pszMessage);
  198. return idRet;
  199. }
  200. HWND hwndProgress = NULL;
  201. BOOL fTriedProgressDialog = FALSE;
  202. INT_PTR ProgressDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  203. {
  204. switch (message) {
  205. case WM_INITDIALOG:
  206. return TRUE;
  207. case WM_SETCURSOR:
  208. SetCursor(LoadCursor(NULL, IDC_WAIT));
  209. return TRUE;
  210. default:
  211. return FALSE;
  212. }
  213. return TRUE;
  214. }
  215. void SetProgressInfo(HWND hwndProgress, LPCTSTR pszFriendlyName, BOOL fInstalling)
  216. {
  217. HWND hwndInstalling = GetDlgItem(hwndProgress, IDC_RUNNING_INSTALL_STUB);
  218. HWND hwndUninstalling = GetDlgItem(hwndProgress, IDC_RUNNING_UNINSTALL_STUB);
  219. ShowWindow(hwndInstalling, fInstalling ? SW_SHOW : SW_HIDE);
  220. EnableWindow(hwndInstalling, fInstalling);
  221. ShowWindow(hwndUninstalling, fInstalling ? SW_HIDE : SW_SHOW);
  222. EnableWindow(hwndUninstalling, !fInstalling);
  223. SetDlgItemText(hwndProgress, IDC_INSTALL_STUB_NAME, pszFriendlyName);
  224. }
  225. void IndicateProgress(LPCTSTR pszFriendlyName, BOOL fInstalling)
  226. {
  227. if (hwndProgress == NULL && !fTriedProgressDialog) {
  228. hwndProgress = CreateDialog(HINST_THISDLL, MAKEINTRESOURCE(IDD_InstallStubProgress),
  229. NULL, ProgressDialogProc);
  230. }
  231. if (hwndProgress != NULL) {
  232. SetProgressInfo(hwndProgress, pszFriendlyName, fInstalling);
  233. if (!fTriedProgressDialog) {
  234. ShowWindow(hwndProgress, SW_RESTORE);
  235. SetForegroundWindow(hwndProgress);
  236. }
  237. }
  238. fTriedProgressDialog = TRUE;
  239. }
  240. void CleanupProgressDialog(void)
  241. {
  242. if (hwndProgress != NULL) {
  243. DestroyWindow(hwndProgress);
  244. hwndProgress = NULL;
  245. }
  246. }
  247. BOOL RunOneInstallStub( HKEY hklmList, HKEY hkcuList, LPCTSTR pszKeyName,
  248. LPCTSTR pszCurrentUsername, int iPass )
  249. {
  250. BOOL bNextPassNeeded = FALSE;
  251. /* See if this component is installed or an uninstall tombstone. */
  252. HKEY hkeyComponent;
  253. DWORD err = RegOpenKeyEx(hklmList, pszKeyName, 0, KEY_QUERY_VALUE,
  254. &hkeyComponent);
  255. if (err == ERROR_SUCCESS) {
  256. TCHAR szCmdLine[MAX_PATH];
  257. DWORD fIsInstalled;
  258. DWORD dwType;
  259. DWORD cbData = sizeof(fIsInstalled);
  260. HKEY hkeyUser = NULL;
  261. /* Must have the stub path; if not there, skip this entry. */
  262. cbData = sizeof(szCmdLine);
  263. if (SHQueryValueEx(hkeyComponent, c_szRegInstallStubValue,
  264. NULL, &dwType, (LPBYTE)szCmdLine,
  265. &cbData) != ERROR_SUCCESS || ((dwType != REG_SZ) && (dwType != REG_EXPAND_SZ)) ) {
  266. RegCloseKey(hkeyComponent);
  267. return bNextPassNeeded;
  268. }
  269. TCHAR szDescription[MAX_PATH];
  270. LPTSTR pszDescription = szDescription;
  271. cbData = sizeof(szDescription);
  272. if (SHQueryValueEx(hkeyComponent, TEXT(""),
  273. NULL, &dwType, (LPBYTE)szDescription,
  274. &cbData) != ERROR_SUCCESS || dwType != REG_SZ) {
  275. pszDescription = szCmdLine;
  276. }
  277. if (RegQueryValueEx(hkeyComponent, c_szRegIsInstalledValue,
  278. NULL, &dwType, (LPBYTE)&fIsInstalled,
  279. &cbData) != ERROR_SUCCESS ||
  280. (dwType != REG_DWORD && (dwType != REG_BINARY || cbData != sizeof(DWORD))))
  281. fIsInstalled = TRUE;
  282. /* If it's installed, check the user's profile, and if the
  283. * component (or its current revision) isn't installed there,
  284. * run it.
  285. */
  286. if (fIsInstalled) {
  287. DWORD dwRevisionHi, dwRevisionLo;
  288. DWORD dwUserRevisionHi = 0;
  289. DWORD dwUserRevisionLo = 0;
  290. BOOL fSetRevision;
  291. TCHAR szRevision[24], szUserRevision[24]; /* 65535,65535,65535,65535\0 */
  292. TCHAR szLocale[10], szUserLocale[10]; /* usually not very big strings */
  293. TCHAR szInstallUsername[128+1]; /* 128 is the win95 system username limit */
  294. DWORD fIsCloneUser;
  295. cbData = sizeof(fIsCloneUser);
  296. if (RegQueryValueEx(hkeyComponent, TEXT("CloneUser"),
  297. NULL, &dwType, (LPBYTE)&fIsCloneUser,
  298. &cbData) != ERROR_SUCCESS ||
  299. (dwType != REG_DWORD && (dwType != REG_BINARY || cbData != sizeof(DWORD))))
  300. fIsCloneUser = FALSE;
  301. cbData = sizeof(szRevision);
  302. if (RegQueryValueEx(hkeyComponent, c_szRegInstallSequenceValue,
  303. NULL, &dwType, (LPBYTE)szRevision,
  304. &cbData) != ERROR_SUCCESS ||
  305. dwType != REG_SZ ||
  306. FAILED(GetVersionFromString(szRevision, &dwRevisionHi, &dwRevisionLo))) {
  307. fSetRevision = FALSE;
  308. dwRevisionHi = 0;
  309. dwRevisionLo = 0;
  310. }
  311. else {
  312. fSetRevision = TRUE;
  313. }
  314. cbData = sizeof(szLocale);
  315. err = RegQueryValueEx(hkeyComponent, c_szRegLocaleValue,
  316. NULL, &dwType, (LPBYTE)szLocale,
  317. &cbData);
  318. if (err != ERROR_SUCCESS || dwType != REG_SZ) {
  319. szLocale[0] = '\0';
  320. }
  321. err = RegOpenKeyEx(hkcuList, pszKeyName, 0,
  322. KEY_QUERY_VALUE | KEY_SET_VALUE, &hkeyUser);
  323. if (err == ERROR_SUCCESS) {
  324. cbData = sizeof(szUserRevision);
  325. if (RegQueryValueEx(hkeyUser, c_szRegInstallSequenceValue,
  326. NULL, &dwType, (LPBYTE)szUserRevision,
  327. &cbData) != ERROR_SUCCESS ||
  328. dwType != REG_SZ ||
  329. FAILED(GetVersionFromString(szUserRevision, &dwUserRevisionHi, &dwUserRevisionLo))) {
  330. dwUserRevisionHi = 0;
  331. dwUserRevisionLo = 0;
  332. }
  333. if (szLocale[0] != '\0') {
  334. cbData = sizeof(szUserLocale);
  335. err = RegQueryValueEx(hkeyUser, c_szRegLocaleValue,
  336. NULL, &dwType, (LPBYTE)szUserLocale,
  337. &cbData);
  338. /* If there's a locale string under the user key
  339. * and it's the same as the machine one, then we
  340. * blank out the machine one so we won't consider
  341. * that when running the stub.
  342. */
  343. if (err == ERROR_SUCCESS && dwType == REG_SZ &&
  344. !lstrcmp(szLocale, szUserLocale)) {
  345. szLocale[0] = '\0';
  346. }
  347. }
  348. if (fIsCloneUser) {
  349. /* Clone-user install stub. We need to re-run it if the
  350. * username we used when we last installed to this profile,
  351. * or the one it was copied from, is different from the
  352. * current username.
  353. */
  354. cbData = sizeof(szInstallUsername);
  355. if (RegQueryValueEx(hkeyUser, TEXT("Username"),
  356. NULL, &dwType, (LPBYTE)szInstallUsername,
  357. &cbData) != ERROR_SUCCESS ||
  358. dwType != REG_SZ) {
  359. szInstallUsername[0] = '\0';
  360. }
  361. }
  362. }
  363. else {
  364. hkeyUser = NULL;
  365. }
  366. /* Install if:
  367. *
  368. * - User doesn't have component installed, OR
  369. * - Component installed on machine has a revision AND
  370. * - Machine component revision greater than user's
  371. * - OR
  372. * - Component installed on machine has a locale AND
  373. * - Machine component locale different than user's
  374. * (this is actually checked above)
  375. * - OR
  376. * - Component is a clone-user install stub and the username
  377. * recorded for the stub is different from the current username
  378. */
  379. if ((hkeyUser == NULL) ||
  380. (fSetRevision &&
  381. ((dwRevisionHi > dwUserRevisionHi) ||
  382. ((dwRevisionHi == dwUserRevisionHi) &&
  383. (dwRevisionLo > dwUserRevisionLo)
  384. )
  385. )
  386. ) ||
  387. (szLocale[0] != '\0') ||
  388. #ifdef UNICODE
  389. (fIsCloneUser && StrCmpI(szInstallUsername, pszCurrentUsername))
  390. #else
  391. (fIsCloneUser && lstrcmpi(szInstallUsername, pszCurrentUsername))
  392. #endif
  393. ) {
  394. if ( (iPass == -1 ) ||
  395. ((iPass == 0) && (*pszKeyName == '<')) ||
  396. ((iPass == 1) && (*pszKeyName != '<') && (*pszKeyName != '>')) ||
  397. ((iPass == 2) && (*pszKeyName == '>')) )
  398. {
  399. // the condition meets, run it now.
  400. #ifdef TraceMsg
  401. TraceMsg(TF_WARNING, "Running install stub ( %s )", szCmdLine);
  402. #endif
  403. IndicateProgress(pszDescription, TRUE);
  404. ShellExecuteRegApp(szCmdLine, RRA_WAIT | RRA_NOUI);
  405. if (hkeyUser == NULL) {
  406. RegCreateKey(hkcuList, pszKeyName, &hkeyUser);
  407. }
  408. if (hkeyUser != NULL) {
  409. if (fSetRevision) {
  410. RegSetValueEx(hkeyUser, c_szRegInstallSequenceValue,
  411. 0, REG_SZ,
  412. (LPBYTE)szRevision,
  413. (lstrlen(szRevision)+1)*sizeof(TCHAR));
  414. }
  415. if (szLocale[0]) {
  416. RegSetValueEx(hkeyUser, c_szRegLocaleValue,
  417. 0, REG_SZ,
  418. (LPBYTE)szLocale,
  419. (lstrlen(szLocale)+1)*sizeof(TCHAR));
  420. }
  421. if (fIsCloneUser) {
  422. RegSetValueEx(hkeyUser, TEXT("Username"),
  423. 0, REG_SZ,
  424. (LPBYTE)pszCurrentUsername,
  425. (lstrlen(pszCurrentUsername)+1)*sizeof(TCHAR));
  426. }
  427. }
  428. }
  429. else
  430. {
  431. // decide if this belong to the next pass
  432. // if it is in Pass 2, should never get here
  433. if ( iPass == 0 )
  434. bNextPassNeeded = TRUE;
  435. else if ( (iPass == 1 ) && (*pszKeyName == '>') )
  436. bNextPassNeeded = TRUE;
  437. }
  438. }
  439. }
  440. else {
  441. /* Component is an uninstall stub. */
  442. err = RegOpenKeyEx(hkcuList, pszKeyName, 0,
  443. KEY_QUERY_VALUE, &hkeyUser);
  444. if (err == ERROR_SUCCESS) {
  445. DWORD fDontAsk = 0;
  446. /* Check the "Don't Ask" value. If it's present, its value
  447. * is interpreted as follows:
  448. *
  449. * 0 --> ask the user
  450. * 1 --> do not run the stub
  451. * 2 --> always run the stub
  452. */
  453. cbData = sizeof(fDontAsk);
  454. if (RegQueryValueEx(hkeyComponent, c_szRegDontAskValue,
  455. NULL, &dwType, (LPBYTE)&fDontAsk,
  456. &cbData) != ERROR_SUCCESS ||
  457. (dwType != REG_DWORD && (dwType != REG_BINARY || cbData != sizeof(DWORD))) ||
  458. fDontAsk != 1)
  459. {
  460. if ( (iPass == -1 ) ||
  461. ((iPass == 0) && (*pszKeyName == '>')) ||
  462. ((iPass == 1) && (*pszKeyName != '<') && (*pszKeyName != '>')) ||
  463. ((iPass == 2) && (*pszKeyName == '<')) )
  464. {
  465. // uninstall stub has the reversed order comparing with install stub
  466. if (fDontAsk == 2 || ConfirmUninstall(pszDescription) == IDYES) {
  467. #ifdef TraceMsg
  468. TraceMsg(TF_WARNING, "Running uninstall stub ( %s )", szCmdLine);
  469. #endif
  470. IndicateProgress(pszDescription, FALSE);
  471. ShellExecuteRegApp(szCmdLine, RRA_WAIT | RRA_NOUI);
  472. /* Component has been uninstalled. Forget that the
  473. * user ever had it installed.
  474. */
  475. RegCloseKey(hkeyUser);
  476. hkeyUser = NULL;
  477. RegDeleteKey(hkcuList, pszKeyName);
  478. }
  479. }
  480. else
  481. {
  482. // decide if this belong to the next pass
  483. // if it is in Pass 2, should never get here
  484. if ( iPass == 0 )
  485. bNextPassNeeded = TRUE;
  486. else if ( (iPass == 1 ) && (*pszKeyName == '<') )
  487. bNextPassNeeded = TRUE;
  488. }
  489. }
  490. }
  491. }
  492. if (hkeyUser != NULL) {
  493. RegCloseKey(hkeyUser);
  494. }
  495. RegCloseKey(hkeyComponent);
  496. }
  497. return bNextPassNeeded;
  498. }
  499. const TCHAR c_szIE40GUID_STUB[] = TEXT("{89820200-ECBD-11cf-8B85-00AA005B4383}");
  500. const TCHAR c_szBlockIE4Stub[] = TEXT("NoIE4StubProcessing");
  501. extern "C" void RunInstallUninstallStubs2(LPCTSTR pszStubToRun)
  502. {
  503. HKEY hklmList = NULL, hkcuList = NULL;
  504. LONG err;
  505. TCHAR szUsername[128+1]; /* 128 is the win95 limit, good default */
  506. LPTSTR pszCurrentUser = szUsername;
  507. /* As far as clone-user install stubs are concerned, we only want profile
  508. * usernames.
  509. */
  510. if (!ProfilesEnabled()) {
  511. *pszCurrentUser = '\0';
  512. }
  513. else {
  514. DWORD cbData = sizeof(szUsername);
  515. if (!GetUserName(szUsername, &cbData)) {
  516. if (cbData > sizeof(szUsername)) {
  517. cbData++; /* allow for null char just in case */
  518. pszCurrentUser = (LPTSTR)LocalAlloc(LPTR, cbData+1);
  519. if (pszCurrentUser == NULL || !GetUserName(pszCurrentUser, &cbData)) {
  520. if (pszCurrentUser != NULL)
  521. LocalFree(pszCurrentUser);
  522. pszCurrentUser = szUsername;
  523. *pszCurrentUser = '\0';
  524. }
  525. }
  526. else {
  527. szUsername[0] = '\0';
  528. }
  529. }
  530. }
  531. #ifdef TraceMsg
  532. TraceMsg(TF_WARNING, "Running install/uninstall stubs.");
  533. #endif
  534. err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegInstalledComponentsKey, 0,
  535. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &hklmList);
  536. if (err == ERROR_SUCCESS) {
  537. DWORD dwDisp;
  538. err = RegCreateKeyEx(HKEY_CURRENT_USER, c_szRegInstalledComponentsKey, 0,
  539. TEXT(""), REG_OPTION_NON_VOLATILE,
  540. KEY_READ | KEY_WRITE, NULL, &hkcuList, &dwDisp);
  541. }
  542. if (err == ERROR_SUCCESS) {
  543. if (pszStubToRun != NULL) {
  544. // here we call with pass number -1 means no pass order enforced
  545. RunOneInstallStub(hklmList, hkcuList, pszStubToRun, pszCurrentUser, -1);
  546. }
  547. else {
  548. DWORD cbKeyName, iKey, iPass;
  549. TCHAR szKeyName[80];
  550. BOOL bNextPassNeeded = TRUE;
  551. HANDLE hMutex;
  552. // This mutex check is to ensure if explore restarted due abnormal active desktop shutdown, and setup resume
  553. // per-user stubs should not be processed till setup is done.
  554. if (CheckWebViewShell())
  555. {
  556. hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, TEXT("Ie4Setup.Mutext"));
  557. if (hMutex)
  558. {
  559. CloseHandle(hMutex);
  560. goto done;
  561. }
  562. }
  563. // check if we want to block the stub processing
  564. cbKeyName = sizeof(szKeyName);
  565. if ((RegQueryValueEx(hklmList, c_szBlockIE4Stub, NULL, NULL,
  566. (LPBYTE)szKeyName, &cbKeyName) == ERROR_SUCCESS) &&
  567. (*CharUpper(szKeyName) == 'Y') )
  568. {
  569. goto done;
  570. }
  571. /* we will do TWO passes to meet the ordering requirement when run component stubs.
  572. Any KeyName with '*' as the first char, get run in the 1st Pass. the rest run 2nd pass */
  573. for ( iPass = 0; ((iPass<3) && bNextPassNeeded); iPass++ )
  574. {
  575. bNextPassNeeded = FALSE;
  576. // APPCOMPAT: in 2nd pass, we do want to special case of IE4.0 base browser stub
  577. // to run first. The reason we did not use '<' for this is to 1) reserve < stuff
  578. // for pre-ie4 stubs and this whole thing should redo in sorted fashion. For now,
  579. // we hard code this IE4.0 base browser GUID
  580. if ( iPass == 1 )
  581. {
  582. if ( RunOneInstallStub(hklmList, hkcuList, c_szIE40GUID_STUB, pszCurrentUser, iPass) )
  583. bNextPassNeeded = TRUE;
  584. }
  585. /* Enumerate components that are installed on the local machine. */
  586. for (iKey = 0; ; iKey++)
  587. {
  588. LONG lEnum;
  589. cbKeyName = ARRAYSIZE(szKeyName);
  590. // WARNING (Unicode, Davepl) I'm assuming that the data is UNICODE,
  591. // but I'm not sure who put it there yet... double check.
  592. if ((lEnum = RegEnumKey(hklmList, iKey, szKeyName, cbKeyName)) == ERROR_MORE_DATA)
  593. {
  594. // ERROR_MORE_DATA means the value name or data was too large
  595. // skip to the next item
  596. #ifdef TraceMsg
  597. TraceMsg( DM_ERROR, "Cannot run oversize entry in InstalledComponents");
  598. #endif
  599. continue;
  600. }
  601. else if( lEnum != ERROR_SUCCESS )
  602. {
  603. // could be ERROR_NO_MORE_ENTRIES, or some kind of failure
  604. // we can't recover from any other registry problem, anyway
  605. break;
  606. }
  607. // in case the user say NO when we try to run the IE4 stub first time,
  608. // we should not re-process this stub again.
  609. if ( (iPass == 1) && (!lstrcmpi(szKeyName, c_szIE40GUID_STUB)) )
  610. continue;
  611. if ( RunOneInstallStub(hklmList, hkcuList, szKeyName, pszCurrentUser, iPass) )
  612. bNextPassNeeded = TRUE;
  613. }
  614. }
  615. }
  616. }
  617. done:
  618. if (hklmList != NULL)
  619. RegCloseKey(hklmList);
  620. if (hkcuList != NULL)
  621. RegCloseKey(hkcuList);
  622. if (pszCurrentUser != szUsername)
  623. LocalFree(pszCurrentUser);
  624. CleanupProgressDialog();
  625. }
  626. // Check shell32.dll's version and see if it is the one which supports the integrated WebView
  627. BOOL CheckWebViewShell()
  628. {
  629. HINSTANCE hInstShell32;
  630. DLLGETVERSIONPROC fpGetDllVersion;
  631. BOOL pWebViewShell = FALSE;
  632. hInstShell32 = LoadLibrary(TEXT("Shell32.dll"));
  633. if (hInstShell32)
  634. {
  635. fpGetDllVersion = (DLLGETVERSIONPROC)GetProcAddress(hInstShell32, "DllGetVersion");
  636. pWebViewShell = (fpGetDllVersion != NULL);
  637. FreeLibrary(hInstShell32);
  638. }
  639. return pWebViewShell;
  640. }