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.

469 lines
14 KiB

  1. // dllreg.c -- autmatic registration and unregistration
  2. //
  3. #include "priv.h"
  4. #include "util.h"
  5. #include "htregmng.h"
  6. #include <advpub.h>
  7. #include <comcat.h>
  8. #include <winineti.h>
  9. #include "resource.h"
  10. #include "DllRegHelper.h"
  11. #include <mluisupp.h>
  12. #ifdef UNIX
  13. #include "unixstuff.h"
  14. #endif
  15. //=--------------------------------------------------------------------------=
  16. // miscellaneous [useful] numerical constants
  17. //=--------------------------------------------------------------------------=
  18. // the length of a guid once printed out with -'s, leading and trailing bracket,
  19. // plus 1 for NULL
  20. //
  21. #define GUID_STR_LEN 40
  22. //
  23. // helper macros
  24. //
  25. //#define RegCreate(hk, psz, phk) if (ERROR_SUCCESS != RegCreateKeyEx((hk), psz, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, (phk), &dwDummy)) goto CleanUp
  26. //#define RegSetStr(hk, psz) if (ERROR_SUCCESS != RegSetValueEx((hk), NULL, 0, REG_SZ, (BYTE*)(psz), lstrlen(psz)+1)) goto CleanUp
  27. //#define RegSetStrValue(hk, pszStr, psz) if(ERROR_SUCCESS != RegSetValueEx((hk), (const char *)(pszStr), 0, REG_SZ, (BYTE*)(psz), lstrlen(psz)+1)) goto CleanUp
  28. //#define RegCloseK(hk) RegCloseKey(hk); hk = NULL
  29. #define RegOpenK(hk, psz, phk) if (ERROR_SUCCESS != RegOpenKeyEx(hk, psz, 0, KEY_READ|KEY_WRITE, phk)) return FALSE
  30. //=--------------------------------------------------------------------------=
  31. // UnregisterTypeLibrary
  32. //=--------------------------------------------------------------------------=
  33. // blows away the type library keys for a given libid.
  34. //
  35. // Parameters:
  36. // REFCLSID - [in] libid to blow away.
  37. //
  38. // Output:
  39. // BOOL - TRUE OK, FALSE bad.
  40. //
  41. // Notes:
  42. // - WARNING: this function just blows away the entire type library section,
  43. // including all localized versions of the type library. mildly anti-
  44. // social, but not killer.
  45. //
  46. BOOL UnregisterTypeLibrary
  47. (
  48. const CLSID* piidLibrary
  49. )
  50. {
  51. TCHAR szScratch[GUID_STR_LEN];
  52. HKEY hk;
  53. BOOL f;
  54. // convert the libid into a string.
  55. //
  56. SHStringFromGUID(*piidLibrary, szScratch, ARRAYSIZE(szScratch));
  57. RegOpenK(HKEY_CLASSES_ROOT, TEXT("TypeLib"), &hk);
  58. f = SHDeleteKey(hk, szScratch);
  59. RegCloseKey(hk);
  60. return f;
  61. }
  62. HRESULT SHRegisterTypeLib(void)
  63. {
  64. HRESULT hr = S_OK;
  65. ITypeLib *pTypeLib;
  66. DWORD dwPathLen;
  67. TCHAR szTmp[MAX_PATH];
  68. // Load and register our type library.
  69. //
  70. dwPathLen = GetModuleFileName(HINST_THISDLL, szTmp, ARRAYSIZE(szTmp));
  71. #ifdef UNIX
  72. dwPathLen = ConvertModuleNameToUnix( szTmp );
  73. #endif
  74. hr = LoadTypeLib(szTmp, &pTypeLib);
  75. if (SUCCEEDED(hr))
  76. {
  77. // call the unregister type library as we had some old junk that
  78. // was registered by a previous version of OleAut32, which is now causing
  79. // the current version to not work on NT...
  80. UnregisterTypeLibrary(&LIBID_SHDocVw);
  81. hr = RegisterTypeLib(pTypeLib, szTmp, NULL);
  82. if (FAILED(hr))
  83. {
  84. TraceMsg(DM_WARNING, "sccls: RegisterTypeLib failed (%x)", hr);
  85. }
  86. pTypeLib->Release();
  87. }
  88. else
  89. {
  90. TraceMsg(DM_WARNING, "sccls: LoadTypeLib failed (%x)", hr);
  91. }
  92. return hr;
  93. }
  94. //
  95. // The actual functions called
  96. //
  97. /*----------------------------------------------------------
  98. Purpose: Calls the ADVPACK entry-point which executes an inf
  99. file section.
  100. */
  101. HRESULT
  102. CallRegInstall(
  103. LPSTR pszSection,
  104. BOOL bUninstall)
  105. {
  106. HRESULT hr = E_FAIL;
  107. HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL"));
  108. if (hinstAdvPack)
  109. {
  110. REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, "RegInstall");
  111. if (pfnri)
  112. {
  113. char szIEPath[MAX_PATH];
  114. STRENTRY seReg[] = {
  115. { "MSIEXPLORE", szIEPath },
  116. // These two NT-specific entries must be at the end
  117. { "25", "%SystemRoot%" },
  118. { "11", "%SystemRoot%\\system32" },
  119. };
  120. STRTABLE stReg = { ARRAYSIZE(seReg) - 2, seReg };
  121. // Get the location of iexplore from the registry
  122. if ( !EVAL(GetIEPath(szIEPath, SIZECHARS(szIEPath))) )
  123. {
  124. // Failed, just say "iexplore"
  125. #ifndef UNIX
  126. StrCpyNA(szIEPath, "iexplore.exe", ARRAYSIZE(szIEPath));
  127. #else
  128. StrCpyNA(szIEPath, "iexplorer", ARRAYSIZE(szIEPath));
  129. #endif
  130. }
  131. if (g_fRunningOnNT)
  132. {
  133. // If on NT, we want custom action for %25% %11%
  134. // so that it uses %SystemRoot% in writing the
  135. // path to the registry.
  136. stReg.cEntries += 2;
  137. }
  138. hr = pfnri(g_hinst, pszSection, &stReg);
  139. if (bUninstall)
  140. {
  141. // ADVPACK will return E_UNEXPECTED if you try to uninstall
  142. // (which does a registry restore) on an INF section that was
  143. // never installed. We uninstall sections that may never have
  144. // been installed, so ignore this error
  145. hr = ((E_UNEXPECTED == hr) ? S_OK : hr);
  146. }
  147. }
  148. else
  149. TraceMsg(TF_ERROR, "DLLREG CallRegInstall() calling GetProcAddress(hinstAdvPack, \"RegInstall\") failed");
  150. FreeLibrary(hinstAdvPack);
  151. }
  152. else
  153. TraceMsg(TF_ERROR, "DLLREG CallRegInstall() Failed to load ADVPACK.DLL");
  154. return hr;
  155. }
  156. const CATID * const c_DeskBandClasses[] =
  157. {
  158. &CLSID_QuickLinks,
  159. &CLSID_AddressBand,
  160. NULL
  161. };
  162. const CATID * const c_OldDeskBandClasses[] =
  163. {
  164. &CLSID_QuickLinksOld,
  165. NULL
  166. };
  167. const CATID * const c_InfoBandClasses[] =
  168. {
  169. &CLSID_FavBand,
  170. &CLSID_HistBand,
  171. &CLSID_ExplorerBand,
  172. NULL
  173. };
  174. void RegisterCategories(BOOL fRegister)
  175. {
  176. enum DRH_REG_MODE eRegister = fRegister ? CCR_REG : CCR_UNREG;
  177. DRH_RegisterOneCategory(&CATID_DeskBand, IDS_CATDESKBAND, c_DeskBandClasses, eRegister);
  178. DRH_RegisterOneCategory(&CATID_InfoBand, IDS_CATINFOBAND, c_InfoBandClasses, eRegister);
  179. if (fRegister)
  180. {
  181. // only nuke the implementor(s), not the category
  182. DRH_RegisterOneCategory(&CATID_DeskBand, IDS_CATDESKBAND, c_OldDeskBandClasses, CCR_UNREGIMP);
  183. }
  184. }
  185. HRESULT CreateShellFolderPath(LPCTSTR pszPath, LPCTSTR pszGUID, BOOL bUICLSID)
  186. {
  187. if (!PathFileExists(pszPath))
  188. CreateDirectory(pszPath, NULL);
  189. // Mark the folder as a system directory
  190. if (SetFileAttributes(pszPath, FILE_ATTRIBUTE_SYSTEM))
  191. {
  192. TCHAR szDesktopIni[MAX_PATH];
  193. // Write in the desktop.ini the cache folder class ID
  194. PathCombine(szDesktopIni, pszPath, TEXT("desktop.ini"));
  195. // If the desktop.ini already exists, make sure it is writable
  196. if (PathFileExists(szDesktopIni))
  197. SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_NORMAL);
  198. // (First, flush the cache to make sure the desktop.ini
  199. // file is really created.)
  200. WritePrivateProfileString(NULL, NULL, NULL, szDesktopIni);
  201. WritePrivateProfileString(TEXT(".ShellClassInfo"), bUICLSID ? TEXT("UICLSID") : TEXT("CLSID"), pszGUID, szDesktopIni);
  202. WritePrivateProfileString(NULL, NULL, NULL, szDesktopIni);
  203. // Hide the desktop.ini since the shell does not selectively
  204. // hide it.
  205. SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_HIDDEN);
  206. return NOERROR;
  207. }
  208. else
  209. {
  210. TraceMsg(TF_ERROR, "Cannot make %s a system folder", pszPath);
  211. return E_FAIL;
  212. }
  213. }
  214. STDAPI
  215. DllRegisterServer(void)
  216. {
  217. HRESULT hr = S_OK;
  218. HRESULT hrExternal = S_OK;
  219. TraceMsg(DM_TRACE, "DLLREG DllRegisterServer() Beginning");
  220. #ifdef DEBUG
  221. if (IsFlagSet(g_dwBreakFlags, BF_ONAPIENTER))
  222. {
  223. TraceMsg(TF_ALWAYS, "Stopping in DllRegisterServer");
  224. DEBUG_BREAK;
  225. }
  226. #endif
  227. // Delete any old registration entries, then add the new ones.
  228. // Keep ADVPACK.DLL loaded across multiple calls to RegInstall.
  229. // (The inf engine doesn't guarantee DelReg/AddReg order, that's
  230. // why we explicitly unreg and reg here.)
  231. //
  232. HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL"));
  233. hr = THR(CallRegInstall("InstallControls", FALSE));
  234. if (SUCCEEDED(hrExternal))
  235. hrExternal = hr;
  236. if (hinstAdvPack)
  237. FreeLibrary(hinstAdvPack);
  238. hr = THR(SHRegisterTypeLib());
  239. if (SUCCEEDED(hrExternal))
  240. hrExternal = hr;
  241. #ifdef UNIX
  242. hrExternal = UnixRegisterBrowserInActiveSetup();
  243. #endif /* UNIX */
  244. return hrExternal;
  245. }
  246. STDAPI DllUnregisterServer(void)
  247. {
  248. HRESULT hr;
  249. TraceMsg(DM_TRACE, "DLLREG DllUnregisterServer() Beginning");
  250. // UnInstall the registry values
  251. hr = THR(CallRegInstall("UnInstallControls", TRUE));
  252. return hr;
  253. }
  254. extern HRESULT UpgradeSettings(void);
  255. /*----------------------------------------------------------
  256. Purpose: Install/uninstall user settings
  257. Description: Note that this function has special error handling.
  258. The function will keep hrExternal with the worse error
  259. but will only stop executing util the internal error (hr)
  260. gets really bad. This is because we need the external
  261. error to catch incorrectly authored INFs but the internal
  262. error to be robust in attempting to install other INF sections
  263. even if one doesn't make it.
  264. */
  265. STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
  266. {
  267. HRESULT hr = S_OK;
  268. HRESULT hrExternal = S_OK;
  269. HINSTANCE hinstAdvPack;
  270. if (0 == StrCmpIW(pszCmdLine, TEXTW("ForceAssoc")))
  271. {
  272. InstallIEAssociations(IEA_FORCEIE);
  273. return hr;
  274. }
  275. hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL")); // Keep ADVPACK.DLL loaded across multiple calls to RegInstall.
  276. #ifdef DEBUG
  277. if (IsFlagSet(g_dwBreakFlags, BF_ONAPIENTER))
  278. {
  279. TraceMsg(TF_ALWAYS, "Stopping in DllInstall");
  280. DEBUG_BREAK;
  281. }
  282. #endif
  283. // Assume we're installing for integrated shell unless otherwise
  284. // noted.
  285. BOOL bIntegrated = ((WhichPlatform() == PLATFORM_INTEGRATED) ? TRUE : FALSE);
  286. TraceMsg(DM_TRACE, "DLLREG DllInstall(bInstall=%lx, pszCmdLine=\"%ls\") bIntegrated=%lx", (DWORD) bInstall, pszCmdLine, (DWORD) bIntegrated);
  287. CoInitialize(0);
  288. if (bInstall)
  289. {
  290. // Backup current associations because InstallPlatformRegItems() may overwrite.
  291. hr = THR(CallRegInstall("InstallAssociations", FALSE));
  292. if (SUCCEEDED(hrExternal))
  293. hrExternal = hr;
  294. hr = THR(CallRegInstall("InstallBrowser", FALSE));
  295. if (SUCCEEDED(hrExternal))
  296. hrExternal = hr;
  297. if (bIntegrated)
  298. {
  299. // UnInstall settings that cannot be installed with Shell Integration.
  300. // This will be a NO-OP if it wasn't installed.
  301. hr = THR(CallRegInstall("UnInstallOnlyBrowser", TRUE));
  302. if (SUCCEEDED(hrExternal))
  303. hrExternal = hr;
  304. // Install IE4 shell components too.
  305. hr = THR(CallRegInstall("InstallOnlyShell", FALSE));
  306. if (SUCCEEDED(hrExternal))
  307. hrExternal = hr;
  308. if (GetUIVersion() >= 5)
  309. {
  310. hr = THR(CallRegInstall("InstallWin2KShell", FALSE));
  311. if (SUCCEEDED(hrExternal))
  312. hrExternal = hr;
  313. }
  314. else
  315. {
  316. hr = THR(CallRegInstall("InstallPreWin2KShell", FALSE));
  317. if (SUCCEEDED(hrExternal))
  318. hrExternal = hr;
  319. }
  320. if (IsOS(OS_WHISTLERORGREATER))
  321. {
  322. hr = THR(CallRegInstall("InstallXP", FALSE));
  323. if (SUCCEEDED(hrExternal))
  324. hrExternal = hr;
  325. }
  326. }
  327. else
  328. {
  329. // UnInstall Shell Integration settings.
  330. // This will be a NO-OP if it wasn't installed.
  331. hr = THR(CallRegInstall("UnInstallOnlyShell", TRUE));
  332. if (SUCCEEDED(hrExternal))
  333. hrExternal = hr;
  334. // Install IE4 shell components too.
  335. hr = THR(CallRegInstall("InstallOnlyBrowser", FALSE));
  336. if (SUCCEEDED(hrExternal))
  337. hrExternal = hr;
  338. }
  339. UpgradeSettings();
  340. UninstallCurrentPlatformRegItems();
  341. InstallIEAssociations(IEA_NORMAL);
  342. RegisterCategories(TRUE);
  343. SHRegisterTypeLib();
  344. }
  345. else
  346. {
  347. // Uninstall browser-only or integrated-browser?
  348. UninstallPlatformRegItems(bIntegrated);
  349. // Restore previous association settings that UninstallPlatformRegItems() could
  350. // have Uninstalled.
  351. hr = THR(CallRegInstall("UnInstallAssociations", TRUE));
  352. if (SUCCEEDED(hrExternal))
  353. hrExternal = hr;
  354. // UnInstall settings that cannot be installed with Shell Integration.
  355. // This will be a NO-OP if it wasn't installed.
  356. hr = THR(CallRegInstall("UnInstallOnlyBrowser", TRUE));
  357. if (SUCCEEDED(hrExternal))
  358. hrExternal = hr;
  359. // UnInstall Shell Integration settings.
  360. // This will be a NO-OP if it wasn't installed.
  361. hr = THR(CallRegInstall("UnInstallShell", TRUE));
  362. if (SUCCEEDED(hrExternal))
  363. hrExternal = hr;
  364. hr = THR(CallRegInstall("UnInstallBrowser", TRUE));
  365. if (SUCCEEDED(hrExternal))
  366. hrExternal = hr;
  367. UnregisterTypeLibrary(&LIBID_SHDocVw);
  368. RegisterCategories(FALSE);
  369. }
  370. if (hinstAdvPack)
  371. FreeLibrary(hinstAdvPack);
  372. CoUninitialize();
  373. return hrExternal;
  374. }
  375. /*----------------------------------------------------------
  376. Purpose: Gets a registry value that is User Specifc.
  377. This will open HKEY_CURRENT_USER if it exists,
  378. otherwise it will open HKEY_LOCAL_MACHINE.
  379. Returns: DWORD containing success or error code.
  380. Cond: --
  381. */
  382. LONG OpenRegUSKey(LPCTSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
  383. {
  384. DWORD dwRet = RegOpenKeyEx(HKEY_CURRENT_USER, lpSubKey, ulOptions, samDesired, phkResult);
  385. if (ERROR_SUCCESS != dwRet)
  386. dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, ulOptions, samDesired, phkResult);
  387. return dwRet;
  388. }