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.

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