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.

397 lines
9.8 KiB

  1. /*
  2. * init.c - DLL startup routines module.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. #include "shlwapi.h"
  9. #include "shlobj.h"
  10. #include "ieguidp.h"
  11. #include "init.h"
  12. #include "clsfact.h"
  13. #include "inetcpl.h"
  14. #include "refcount.hpp"
  15. #include "shlstock.h"
  16. #include "olestock.h"
  17. #include "ftps.hpp" /* for CLSID_MIMEFileTypesPropSheetHook */
  18. #include "inetps.hpp" /* for CLSID_Internet */
  19. #include "shguidp.h" // for CLSID_URLExecHook
  20. #include "cfmacros.h" // static class factory macros
  21. #define MLUI_INIT
  22. #include <mluisupp.h>
  23. /****************************** Public Functions *****************************/
  24. /* Declare _main() so we can link with the CRT lib, but not have to
  25. ** use the DllMainCRTStartup entry point.
  26. */
  27. void
  28. _cdecl
  29. main(void)
  30. {
  31. }
  32. #pragma warning(disable:4100) /* "unreferenced formal parameter" warning */
  33. #ifdef MAINWIN
  34. BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, PVOID pvReserved);
  35. extern "C" BOOL url_DllMain(
  36. IN HINSTANCE DllHandle,
  37. IN DWORD Reason,
  38. IN LPVOID Reserved
  39. )
  40. {
  41. return DllMain(DllHandle,Reason,Reserved);
  42. }
  43. #endif
  44. /*
  45. ** DllMain()
  46. **
  47. **
  48. **
  49. ** Arguments:
  50. **
  51. ** Returns:
  52. **
  53. ** Side Effects: none
  54. */
  55. PUBLIC_CODE BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason,
  56. PVOID pvReserved)
  57. {
  58. BOOL bResult;
  59. DebugEntry(DllMain);
  60. /* Validate dwReason below. */
  61. /* pvReserved may be any value. */
  62. ASSERT(IS_VALID_HANDLE(hModule, MODULE));
  63. switch (dwReason)
  64. {
  65. case DLL_PROCESS_ATTACH:
  66. MLLoadResources(hModule, TEXT("urllc.dll"));
  67. bResult = AttachProcess(hModule);
  68. break;
  69. case DLL_PROCESS_DETACH:
  70. MLFreeResources(hModule);
  71. bResult = DetachProcess(hModule);
  72. break;
  73. case DLL_THREAD_ATTACH:
  74. bResult = AttachThread(hModule);
  75. break;
  76. case DLL_THREAD_DETACH:
  77. bResult = DetachThread(hModule);
  78. break;
  79. default:
  80. ERROR_OUT(("LibMain() called with unrecognized dwReason %lu.",
  81. dwReason));
  82. bResult = FALSE;
  83. break;
  84. }
  85. DebugExitBOOL(DllMain, bResult);
  86. return(bResult);
  87. }
  88. UINT
  89. WhichPlatform(void)
  90. {
  91. HINSTANCE hinst;
  92. //
  93. // in retail we cache this info
  94. // in debug we always re-fetch it (so people can switch)
  95. //
  96. #ifdef DEBUG
  97. UINT uInstall = PLATFORM_UNKNOWN;
  98. #else
  99. static UINT uInstall = PLATFORM_UNKNOWN;
  100. if (uInstall != PLATFORM_UNKNOWN)
  101. return uInstall;
  102. #endif
  103. hinst = GetModuleHandle(TEXT("SHDOCVW.DLL"));
  104. if (hinst)
  105. {
  106. // NOTE: GetProcAddress always takes ANSI strings!
  107. DLLGETVERSIONPROC pfnGetVersion =
  108. (DLLGETVERSIONPROC)GetProcAddress(hinst, "DllGetVersion");
  109. if (pfnGetVersion)
  110. {
  111. DLLVERSIONINFO info;
  112. info.cbSize = sizeof(info);
  113. if (SUCCEEDED(pfnGetVersion(&info)))
  114. {
  115. if (4 <= info.dwMajorVersion &&
  116. 71 <= info.dwMinorVersion &&
  117. 429 <= info.dwBuildNumber)
  118. {
  119. uInstall = PLATFORM_INTEGRATED;
  120. }
  121. else
  122. uInstall = PLATFORM_IE3;
  123. }
  124. }
  125. #ifdef DEBUG
  126. // To allow easier debugging, we can override the platform by
  127. // setting InstallPlatform value in ccshell.ini.
  128. {
  129. UINT uInstallT = GetPrivateProfileInt(TEXT("urldebugoptions"),
  130. TEXT("InstallPlatform"),
  131. PLATFORM_UNKNOWN,
  132. TEXT("ohare.ini"));
  133. if (PLATFORM_UNKNOWN != uInstallT)
  134. {
  135. TRACE_OUT((" ***Overriding real platform installation***\r\n"));
  136. uInstall = uInstallT;
  137. }
  138. }
  139. switch (uInstall)
  140. {
  141. case PLATFORM_IE3:
  142. TRACE_OUT((" ***Assuming IE3***\r\n"));
  143. break;
  144. case PLATFORM_INTEGRATED:
  145. TRACE_OUT((" ***Assuming Nashville***\r\n"));
  146. break;
  147. }
  148. #endif
  149. }
  150. return uInstall;
  151. }
  152. #pragma data_seg(DATA_SEG_PER_INSTANCE)
  153. // DLL reference count == number of class factories +
  154. // number of URLs +
  155. // LockServer() count
  156. PRIVATE_DATA ULONG s_ulcDLLRef = 0;
  157. #pragma data_seg()
  158. PUBLIC_CODE ULONG DLLAddRef(void)
  159. {
  160. ULONG ulcRef;
  161. ASSERT(s_ulcDLLRef < ULONG_MAX);
  162. ulcRef = ++s_ulcDLLRef;
  163. TRACE_OUT(("DLLAddRef(): DLL reference count is now %lu.",
  164. ulcRef));
  165. return(ulcRef);
  166. }
  167. PUBLIC_CODE ULONG DLLRelease(void)
  168. {
  169. ULONG ulcRef;
  170. if (EVAL(s_ulcDLLRef > 0))
  171. s_ulcDLLRef--;
  172. ulcRef = s_ulcDLLRef;
  173. TRACE_OUT(("DLLRelease(): DLL reference count is now %lu.",
  174. ulcRef));
  175. return(ulcRef);
  176. }
  177. PUBLIC_CODE PULONG GetDLLRefCountPtr(void)
  178. {
  179. // REARCHITECT: this is dangerous. Shouldn't be used like this.
  180. return(&s_ulcDLLRef);
  181. }
  182. typedef HRESULT (CALLBACK* DLLGETCLASSOBJECTPROC)(REFCLSID, REFIID, void**);
  183. STDMETHODIMP_(BOOL)
  184. PatchForNashville(
  185. REFCLSID rclsid,
  186. REFIID riid,
  187. void **ppv,
  188. HRESULT * phres)
  189. {
  190. BOOL bRet = FALSE;
  191. *phres = CLASS_E_CLASSNOTAVAILABLE; // assume error
  192. if (IsEqualIID(rclsid, CLSID_InternetShortcut) &&
  193. PLATFORM_INTEGRATED == WhichPlatform())
  194. {
  195. HINSTANCE hinst;
  196. // Normally we can just patch the registry. But there is a valid
  197. // case where url.dll is the InprocServer, and that is when the
  198. // user has chosen to uninstall IE 4.0 and we haven't restarted
  199. // the machine yet. In this case, we don't want to patch the
  200. // registry. Use the "MayChangeDefaultMenu" as an indication
  201. // of whether we should really patch it or not.
  202. // Are we uninstalling IE 4.0?
  203. if (NO_ERROR == SHGetValue(HKEY_CLASSES_ROOT,
  204. TEXT("CLSID\\{FBF23B40-E3F0-101B-8488-00AA003E56F8}\\shellex\\MayChangeDefaultMenu"),
  205. TEXT(""),
  206. NULL, NULL, NULL))
  207. {
  208. // No; patch the registry so shdocvw is the handler again
  209. SetRegKeyValue(HKEY_CLASSES_ROOT,
  210. "CLSID\\{FBF23B40-E3F0-101B-8488-00AA003E56F8}\\InProcServer32",
  211. NULL,
  212. REG_SZ,
  213. (PCBYTE)"shdocvw.dll", sizeof("shdocvw.dll"));
  214. // Now call shdocvw's DllGetClassObject
  215. hinst = GetModuleHandle(TEXT("SHDOCVW.DLL"));
  216. if (hinst)
  217. {
  218. DLLGETCLASSOBJECTPROC pfn =
  219. (DLLGETCLASSOBJECTPROC)GetProcAddress(hinst, "DllGetClassObject");
  220. if (pfn)
  221. {
  222. *phres = pfn(rclsid, riid, ppv);
  223. bRet = TRUE;
  224. }
  225. }
  226. }
  227. }
  228. return bRet;
  229. }
  230. STDAPI CreateInstance_Intshcut(IUnknown *punkOuter, REFIID riid, void **ppvOut);
  231. STDAPI CreateInstance_MIMEHook(IUnknown *punkOuter, REFIID riid, void **ppvOut);
  232. STDAPI CreateInstance_Internet(IUnknown *punkOuter, REFIID riid, void **ppvOut);
  233. STDAPI CreateInstance_URLExec(IUnknown *punkOuter, REFIID riid, void **ppvOut);
  234. //
  235. // ClassFactory methods.
  236. //
  237. STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void **ppvObj)
  238. {
  239. if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
  240. {
  241. *ppvObj = (void *)GET_ICLASSFACTORY(this);
  242. DLLAddRef();
  243. return NOERROR;
  244. }
  245. *ppvObj = NULL;
  246. return E_NOINTERFACE;
  247. }
  248. STDMETHODIMP_(ULONG) CClassFactory::AddRef()
  249. {
  250. return DLLAddRef();
  251. }
  252. STDMETHODIMP_(ULONG) CClassFactory::Release()
  253. {
  254. return DLLRelease();
  255. }
  256. STDMETHODIMP CClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppvObject)
  257. {
  258. CObjectInfo *localthis = (CObjectInfo*)(this);
  259. return localthis->pfnCreate(punkOuter, riid, ppvObject);
  260. }
  261. STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
  262. {
  263. if (fLock)
  264. DLLAddRef();
  265. else
  266. DLLRelease();
  267. return S_OK;
  268. }
  269. //
  270. // we always do a linear search here so put your most often used things first
  271. //
  272. CF_TABLE_BEGIN(c_clsmap)
  273. CF_TABLE_ENTRY(&CLSID_URLExecHook, CreateInstance_URLExec)
  274. CF_TABLE_ENTRY(&CLSID_InternetShortcut, CreateInstance_Intshcut)
  275. CF_TABLE_ENTRY(&CLSID_MIMEFileTypesPropSheetHook, CreateInstance_MIMEHook)
  276. CF_TABLE_ENTRY(&CLSID_Internet, CreateInstance_Internet)
  277. CF_TABLE_END(c_clsmap)
  278. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
  279. {
  280. HRESULT hres = CLASS_E_CLASSNOTAVAILABLE;
  281. *ppv = NULL; // assume error
  282. if (IsEqualIID(riid, IID_IClassFactory))
  283. {
  284. // Under Nashville, the internet shortcuts are handled by shdocvw.
  285. // It is possible that the user installed Netscape after installing
  286. // Nashville, which would cause url.dll to be the handler again
  287. // for internet shortcuts. This patches the registry and calls
  288. // shdocvw's DllGetClassObject if we're in that scenario.
  289. // Did we patch for nashville?
  290. if ( !PatchForNashville(rclsid, riid, ppv, &hres) )
  291. {
  292. // No; carry on...
  293. const CObjectInfo *pcls;
  294. for (pcls = c_clsmap; pcls->pclsid; pcls++)
  295. {
  296. if (IsEqualIID(rclsid, *(pcls->pclsid)))
  297. {
  298. *ppv = (void *)GET_ICLASSFACTORY(pcls);
  299. DLLAddRef(); // creation of the CF, CF holds DLL Ref count
  300. return NOERROR;
  301. }
  302. }
  303. }
  304. }
  305. return hres;
  306. }
  307. STDAPI DllCanUnloadNow(void)
  308. {
  309. if (s_ulcDLLRef > 0)
  310. return S_FALSE;
  311. return InternetCPLCanUnloadNow();
  312. }
  313. #pragma warning(default:4100) /* "unreferenced formal parameter" warning */