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.

695 lines
22 KiB

  1. #define DONT_USE_ATL
  2. #include "priv.h"
  3. #include "sccls.h"
  4. #include "atl.h"
  5. #include <ntverp.h>
  6. #include <ieguidp.h> // for CLSID_CDocObjectFolder
  7. #include "ishcut.h"
  8. #include "reload.h" // for URLDL_WNDCLASS
  9. #include "inetnot.h" // CWinInetNotify_szWindowClass
  10. #include <activscp.h> // IID_IActiveScriptStats
  11. #define MLUI_INIT
  12. #include <mluisupp.h>
  13. #define DECL_CRTFREE
  14. #include <crtfree.h>
  15. #include "shfusion.h"
  16. //
  17. // Downlevel delay load support (we forward to shlwapi)
  18. //
  19. #include <delayimp.h>
  20. STDAPI_(FARPROC) DelayloadNotifyHook(UINT iReason, PDelayLoadInfo pdli);
  21. PfnDliHook __pfnDliFailureHook;
  22. PfnDliHook __pfnDliNotifyHook = DelayloadNotifyHook; // notify hook is needed so that we can unload wininet.dll
  23. HANDLE BaseDllHandle;
  24. LONG g_cRefThisDll = 0; // per-instance
  25. CRITICAL_SECTION g_csDll = {0}; // per-instance
  26. HINSTANCE g_hinst = NULL;
  27. EXTERN_C HANDLE g_hMutexHistory = NULL;
  28. BOOL g_fRunningOnNT = FALSE;
  29. BOOL g_bNT5Upgrade = FALSE;
  30. BOOL g_bRunOnNT5 = FALSE;
  31. BOOL g_bRunOnMemphis = FALSE;
  32. BOOL g_fRunOnFE = FALSE;
  33. UINT g_uiACP = CP_ACP;
  34. DWORD g_dwStopWatchMode = 0; // Shell perf automation
  35. BOOL g_bMirroredOS = FALSE; // Is Mirroring enabled
  36. BOOL g_bBiDiW95Loc = FALSE; // needed for BiDi localized win95 RTL stuff
  37. HMODULE g_hmodWininet = NULL; // have we loaded wininet because of a delayload thunk??
  38. EXTERN_C HANDLE g_hSemBrowserCount;
  39. HPALETTE g_hpalHalftone = NULL;
  40. EXTERN_C const GUID CLSID_MsgBand;
  41. STDAPI CMsgBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi);
  42. //
  43. // This array holds information needed for ClassFacory.
  44. // OLEMISC_ flags are used by shembed and shocx.
  45. //
  46. // PERF: this table should be ordered in most-to-least used order
  47. //
  48. CF_TABLE_BEGIN(g_ObjectInfo)
  49. CF_TABLE_ENTRY(&CLSID_CDocObjectFolder, CDocObjectFolder_CreateInstance,
  50. COCREATEONLY),
  51. CF_TABLE_ENTRY_NOFLAGS(&CLSID_CBaseBrowser, CBaseBrowser2_CreateInstance,
  52. COCREATEONLY_NOFLAGS, OIF_ALLOWAGGREGATION),
  53. CF_TABLE_ENTRY(&CLSID_CURLFolder, CInternetFolder_CreateInstance,
  54. COCREATEONLY),
  55. CF_TABLE_ENTRY(&CLSID_Internet, CInternetFolder_CreateInstance,
  56. COCREATEONLY),
  57. CF_TABLE_ENTRY(&CLSID_CacheFolder, CacheFolder_CreateInstance,
  58. COCREATEONLY),
  59. CF_TABLE_ENTRY(&CLSID_CacheFolder2, CacheFolder_CreateInstance,
  60. COCREATEONLY),
  61. CF_TABLE_ENTRY(&CLSID_HistFolder, HistFolder_CreateInstance,
  62. COCREATEONLY),
  63. CF_TABLE_ENTRY_ALL(&CLSID_WebBrowser, CWebBrowserOC_CreateInstance,
  64. &IID_IWebBrowser2, &DIID_DWebBrowserEvents2, VERSION_2,
  65. OLEMISC_SETCLIENTSITEFIRST|OLEMISC_ACTIVATEWHENVISIBLE|OLEMISC_RECOMPOSEONRESIZE|OLEMISC_CANTLINKINSIDE|OLEMISC_INSIDEOUT,OIF_ALLOWAGGREGATION),
  66. CF_TABLE_ENTRY(&CLSID_CUrlHistory, CUrlHistory_CreateInstance,
  67. COCREATEONLY),
  68. CF_TABLE_ENTRY(&CLSID_CURLSearchHook, CURLSearchHook_CreateInstance,
  69. COCREATEONLY),
  70. CF_TABLE_ENTRY_ALL(&CLSID_WebBrowser_V1, CWebBrowserOC_CreateInstance,
  71. &IID_IWebBrowser, &DIID_DWebBrowserEvents, VERSION_1,
  72. OLEMISC_SETCLIENTSITEFIRST|OLEMISC_ACTIVATEWHENVISIBLE|OLEMISC_RECOMPOSEONRESIZE|OLEMISC_CANTLINKINSIDE|OLEMISC_INSIDEOUT,OIF_ALLOWAGGREGATION),
  73. CF_TABLE_ENTRY(&CLSID_CStubBindStatusCallback, CStubBSC_CreateInstance,
  74. COCREATEONLY),
  75. CF_TABLE_ENTRY(&CLSID_ShellUIHelper, CShellUIHelper_CreateInstance,
  76. COCREATEONLY),
  77. CF_TABLE_ENTRY(&CLSID_InternetShortcut, CIntShcut_CreateInstance,
  78. COCREATEONLY),
  79. #ifdef ENABLE_CHANNELS
  80. CF_TABLE_ENTRY_ALL(&CLSID_ChannelOC, ChannelOC_CreateInstance,
  81. NULL,NULL,0,
  82. OLEMISC_ACTIVATEWHENVISIBLE|OLEMISC_CANTLINKINSIDE|OLEMISC_INSIDEOUT,
  83. OIF_ALLOWAGGREGATION),
  84. #endif // ENABLE_CHANNELS
  85. #ifndef NO_SPLASHSCREEN
  86. CF_TABLE_ENTRY(&CLSID_IESplashScreen, CIESplashScreen_CreateInstance,
  87. COCREATEONLY),
  88. #endif
  89. CF_TABLE_ENTRY(&CLSID_WinListShellProc, CWinListShellProc_CreateInstance,
  90. COCREATEONLY),
  91. CF_TABLE_ENTRY(&CLSID_CDFCopyHook, CCDFCopyHook_CreateInstance,
  92. COCREATEONLY),
  93. CF_TABLE_ENTRY(&CLSID_InternetCacheCleaner, CInternetCacheCleaner_CreateInstance,
  94. COCREATEONLY),
  95. CF_TABLE_ENTRY(&CLSID_OfflinePagesCacheCleaner, COfflinePagesCacheCleaner_CreateInstance,
  96. COCREATEONLY),
  97. CF_TABLE_ENTRY(&CLSID_TaskbarList, TaskbarList_CreateInstance,
  98. COCREATEONLY),
  99. CF_TABLE_ENTRY(&CLSID_DocFileInfoTip, CDocFileInfoTip_CreateInstance,
  100. COCREATEONLY),
  101. CF_TABLE_ENTRY(&CLSID_DocHostUIHandler, CDocHostUIHandler_CreateInstance,
  102. COCREATEONLY),
  103. CF_TABLE_ENTRY(&CLSID_ToolbarExtBand, CToolbarExtBand_CreateInstance,
  104. COCREATEONLY),
  105. CF_TABLE_ENTRY(&CLSID_ToolbarExtExec, CToolbarExtExec_CreateInstance,
  106. COCREATEONLY),
  107. CF_TABLE_ENTRY(&CLSID_NSCTree, CNscTree_CreateInstance,
  108. COCREATEONLY),
  109. CF_TABLE_ENTRY(&CLSID_FavBand, CFavBand_CreateInstance,
  110. COCREATEONLY),
  111. CF_TABLE_ENTRY(&CLSID_ExplorerBand, CExplorerBand_CreateInstance,
  112. COCREATEONLY),
  113. CF_TABLE_ENTRY(&CLSID_HistBand, CHistBand_CreateInstance,
  114. COCREATEONLY),
  115. CF_TABLE_ENTRY(&CLSID_MruLongList, CMruLongList_CreateInstance,
  116. COCREATEONLY),
  117. CF_TABLE_ENTRY(&CLSID_MruPidlList, CMruPidlList_CreateInstance,
  118. COCREATEONLY),
  119. CF_TABLE_END(g_ObjectInfo)
  120. // constructor for CObjectInfo.
  121. CObjectInfo::CObjectInfo(CLSID const* pclsidin, LPFNCREATEOBJINSTANCE pfnCreatein, IID const* piidIn,
  122. IID const* piidEventsIn, long lVersionIn, DWORD dwOleMiscFlagsIn,
  123. DWORD dwClassFactFlagsIn)
  124. {
  125. pclsid = pclsidin;
  126. pfnCreateInstance = pfnCreatein;
  127. piid = piidIn;
  128. piidEvents = piidEventsIn;
  129. lVersion = lVersionIn;
  130. dwOleMiscFlags = dwOleMiscFlagsIn;
  131. dwClassFactFlags = dwClassFactFlagsIn;
  132. }
  133. // static class factory (no allocs!)
  134. STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void **ppvObj)
  135. {
  136. if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
  137. {
  138. *ppvObj = (void *)GET_ICLASSFACTORY(this);
  139. DllAddRef();
  140. return S_OK;
  141. }
  142. *ppvObj = NULL;
  143. return E_NOINTERFACE;
  144. }
  145. STDMETHODIMP_(ULONG) CClassFactory::AddRef()
  146. {
  147. DllAddRef();
  148. return 2;
  149. }
  150. STDMETHODIMP_(ULONG) CClassFactory::Release()
  151. {
  152. DllRelease();
  153. return 1;
  154. }
  155. STDMETHODIMP CClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  156. {
  157. *ppv = NULL;
  158. if (punkOuter && !IsEqualIID(riid, IID_IUnknown))
  159. {
  160. // It is technically illegal to aggregate an object and request
  161. // any interface other than IUnknown. Enforce this.
  162. //
  163. return CLASS_E_NOAGGREGATION;
  164. }
  165. else
  166. {
  167. LPOBJECTINFO pthisobj = (LPOBJECTINFO)this;
  168. if (punkOuter && !(pthisobj->dwClassFactFlags & OIF_ALLOWAGGREGATION))
  169. return CLASS_E_NOAGGREGATION;
  170. IUnknown *punk;
  171. HRESULT hr = pthisobj->pfnCreateInstance(punkOuter, &punk, pthisobj);
  172. if (SUCCEEDED(hr))
  173. {
  174. hr = punk->QueryInterface(riid, ppv);
  175. punk->Release();
  176. }
  177. ASSERT(FAILED(hr) ? *ppv == NULL : TRUE);
  178. return hr;
  179. }
  180. }
  181. STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
  182. {
  183. if (fLock)
  184. DllAddRef();
  185. else
  186. DllRelease();
  187. TraceMsg(DM_TRACE, "sccls: LockServer(%s) to %d", fLock ? TEXT("LOCK") : TEXT("UNLOCK"), g_cRefThisDll);
  188. return S_OK;
  189. }
  190. BOOL IsProxyRegisteredProperly(LPCTSTR pszInterface, LPCTSTR pszClsid)
  191. {
  192. TCHAR szInterface[128];
  193. wnsprintf(szInterface, ARRAYSIZE(szInterface), TEXT("Interface\\%s\\ProxyStubClsid32"), pszInterface);
  194. TCHAR szValue[40];
  195. DWORD cbValue = sizeof(szValue);
  196. return (ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT, szInterface, NULL, NULL, szValue, &cbValue)) &&
  197. (0 == StrCmpI(szValue, pszClsid));
  198. }
  199. // published, so invariant
  200. #define ACTXPROXYSTUB TEXT("{B8DA6310-E19B-11D0-933C-00A0C90DCAA9}")
  201. #define FOLDERMARSHALPROXYSTUB TEXT("{bf50b68e-29b8-4386-ae9c-9734d5117cd5}") // CLSID_FolderMarshalStub
  202. #define ISHELLFOLDER TEXT("{000214E6-0000-0000-C000-000000000046}") // IID_IShellFolder
  203. #define ISHELLFOLDER2 TEXT("{93F2F68C-1D1B-11D3-A30E-00C04F79ABD1}") // IID_IShellFolder2
  204. #define IOLECOMMANDTARGET TEXT("{b722bccb-4e68-101b-a2bc-00aa00404770}") // IID_IOleCommandTarget
  205. #define IHLINKTARGET TEXT("{79eac9c4-baf9-11ce-8c82-00aa004ba90b}") // IID_IHlinkTarget
  206. void SHShouldRegisterActxprxy(void)
  207. {
  208. // IOleCommandTarget / IHlinkTarget Proxy/Stub CLSID key missing?
  209. if (!IsProxyRegisteredProperly(IOLECOMMANDTARGET, ACTXPROXYSTUB) ||
  210. !IsProxyRegisteredProperly(IHLINKTARGET, ACTXPROXYSTUB))
  211. {
  212. HINSTANCE hinst = LoadLibrary(TEXT("ACTXPRXY.DLL"));
  213. if (hinst)
  214. {
  215. typedef HRESULT (WINAPI * REGSERVERPROC)(void);
  216. REGSERVERPROC pfn = (REGSERVERPROC) GetProcAddress(hinst, "DllRegisterServer");
  217. if (pfn)
  218. pfn();
  219. FreeLibrary(hinst);
  220. }
  221. }
  222. // test for IShellFolder marshaler not being set to our app compat stub
  223. if (!IsProxyRegisteredProperly(ISHELLFOLDER, FOLDERMARSHALPROXYSTUB) ||
  224. !IsProxyRegisteredProperly(ISHELLFOLDER2, FOLDERMARSHALPROXYSTUB))
  225. {
  226. SHSetValue(HKEY_CLASSES_ROOT, TEXT("Interface\\") ISHELLFOLDER TEXT("\\ProxyStubClsid32"),
  227. TEXT(""), REG_SZ, FOLDERMARSHALPROXYSTUB, sizeof(FOLDERMARSHALPROXYSTUB));
  228. SHSetValue(HKEY_CLASSES_ROOT, TEXT("Interface\\") ISHELLFOLDER2 TEXT("\\ProxyStubClsid32"),
  229. TEXT(""), REG_SZ, FOLDERMARSHALPROXYSTUB, sizeof(FOLDERMARSHALPROXYSTUB));
  230. }
  231. }
  232. void SHCheckRegistry(void)
  233. {
  234. // VBE has a bug where they destroy the interface registration information of any control
  235. // hosted in a VBE user form. Check the registry here. Only do this once.
  236. // 17-Nov-97 [alanau/terrylu] Added a check for the IOleCommandTarget Proxy/Stub handler
  237. //
  238. static BOOL fNeedToCheckRegistry = TRUE;
  239. if (fNeedToCheckRegistry)
  240. {
  241. fNeedToCheckRegistry = FALSE;
  242. // This is published, so is invariant
  243. TCHAR szValue[39];
  244. DWORD cbValue = sizeof(szValue);
  245. LONG rc = SHGetValue(HKEY_CLASSES_ROOT, TEXT("Interface\\{EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B}\\Typelib"),
  246. NULL, NULL, szValue, &cbValue);
  247. if (rc == ERROR_SUCCESS)
  248. {
  249. // Compare the retrieved value with our typelib id.
  250. //
  251. if (StrCmpI(szValue, TEXT("{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}")) != 0)
  252. {
  253. // If different, we need to explicitly register our typelib
  254. //
  255. SHRegisterTypeLib();
  256. }
  257. }
  258. SHShouldRegisterActxprxy();
  259. }
  260. }
  261. STDAPI CInstClassFactory_Create(REFCLSID rclsid, REFIID riid, void *ppv);
  262. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
  263. {
  264. SHCheckRegistry(); // patch up broken registry
  265. *ppv = NULL;
  266. HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
  267. if ((riid == IID_IClassFactory) || (riid == IID_IUnknown))
  268. {
  269. for (LPCOBJECTINFO pcls = g_ObjectInfo; pcls->pclsid; pcls++)
  270. {
  271. if (IsEqualGUID(rclsid, *(pcls->pclsid)))
  272. {
  273. *ppv = (void*)pcls;
  274. DllAddRef(); // class factory holds DLL ref count
  275. hr = S_OK;
  276. break;
  277. }
  278. }
  279. if (FAILED(hr))
  280. {
  281. // Try the ATL class factory
  282. hr = AtlGetClassObject(rclsid, riid, ppv);
  283. if (FAILED(hr))
  284. {
  285. // not found, see if it's an 'instance' (code + initialization)
  286. hr = CInstClassFactory_Create(rclsid, riid, ppv);
  287. }
  288. }
  289. }
  290. else if ((riid == IID_IPSFactoryBuffer) &&
  291. (rclsid == CLSID_FolderMarshalStub) &&
  292. !(SHGetAppCompatFlags(ACF_APPISOFFICE) & ACF_APPISOFFICE))
  293. {
  294. // IID_IActiveScriptStats == CLSID_ActiveXProxy
  295. // B8DA6310-E19B-11d0-933C-00A0C90DCAA9
  296. hr = CoGetClassObject(IID_IActiveScriptStats, CLSCTX_INPROC_SERVER, NULL, riid, ppv);
  297. }
  298. return hr;
  299. }
  300. STDAPI DllCanUnloadNow(void)
  301. {
  302. if (0 != g_cRefThisDll || 0 != AtlGetLockCount())
  303. return S_FALSE;
  304. TraceMsg(DM_TRACE, "DllCanUnloadNow returning S_OK (bye, bye...)");
  305. return S_OK;
  306. }
  307. // DllGetVersion - New for IE 4.0
  308. //
  309. // All we have to do is declare this puppy and CCDllGetVersion does the rest
  310. //
  311. DLLVER_SINGLEBINARY(VER_PRODUCTVERSION_DW, VER_PRODUCTBUILD_QFE);
  312. #ifdef DEBUG
  313. EXTERN_C
  314. DWORD g_TlsMem = 0xffffffff;
  315. #endif
  316. void InitNFCtl()
  317. {
  318. INITCOMMONCONTROLSEX icc;
  319. icc.dwSize = sizeof(icc);
  320. icc.dwICC = ICC_NATIVEFNTCTL_CLASS;
  321. InitCommonControlsEx(&icc);
  322. }
  323. //
  324. // we use shlwapi as our delayload error handler.
  325. // NOTE: this only works if we are statically linked to shlwapi!
  326. //
  327. void SetupDelayloadErrorHandler()
  328. {
  329. BaseDllHandle = GetModuleHandleA("shlwapi.dll");
  330. ASSERTMSG(BaseDllHandle != NULL, "SHDOCVW must be statically linked to shlwapi.dll for delayload failure handling to work!");
  331. __pfnDliFailureHook = (PfnDliHook)GetProcAddress((HMODULE)BaseDllHandle, "DelayLoadFailureHook");
  332. }
  333. //
  334. // we use this function to see if we have loaded wininet.dll due to a delayload thunk so that we
  335. // can free it at dll detach and therefore it will cleanup all of its crud
  336. //
  337. STDAPI_(FARPROC) DelayloadNotifyHook(UINT iReason, PDelayLoadInfo pdli)
  338. {
  339. if (iReason == dliNoteEndProcessing)
  340. {
  341. if (pdli &&
  342. pdli->szDll &&
  343. (StrCmpIA("wininet.dll", pdli->szDll) == 0))
  344. {
  345. // wininet was loaded!!
  346. g_hmodWininet = pdli->hmodCur;
  347. }
  348. }
  349. return NULL;
  350. }
  351. //
  352. // Table of all window classes we register so we can unregister them
  353. // at DLL unload.
  354. //
  355. const LPCTSTR c_rgszClasses[] = {
  356. c_szViewClass, // dochost.cpp
  357. URLDL_WNDCLASS, // reload.cpp
  358. c_szShellEmbedding, // embed.cpp
  359. TEXT("CIESplashScreen"), // splash.cpp
  360. CWinInetNotify_szWindowClass, // inetnot.cpp
  361. OCHOST_CLASS, // occtrl.cpp
  362. TEXT("AutoImageResizeHost"), // airesize.cpp
  363. TEXT("MyPicturesHost") // mypics.cpp
  364. };
  365. //
  366. // Since we are single-binary, we have to play it safe and do
  367. // this cleanup (needed only on NT, but harmless on Win95).
  368. //
  369. #define UnregisterWindowClasses() \
  370. SHUnregisterClasses(HINST_THISDLL, c_rgszClasses, ARRAYSIZE(c_rgszClasses))
  371. // IEUNIX - This function should be moved to some file used to create
  372. // shdocvw.dll. While compiling for DLLs mainsoft will #define DllMain
  373. // to the appropriate function being called in generated *_init.c
  374. #if defined(MAINWIN)
  375. STDAPI_(BOOL) DllMain_Internal(HINSTANCE hDll, DWORD dwReason, void *fProcessUnload)
  376. #else
  377. STDAPI_(BOOL) DllMain(HINSTANCE hDll, DWORD dwReason, void *fProcessUnload)
  378. #endif
  379. {
  380. if (dwReason == DLL_PROCESS_ATTACH)
  381. {
  382. SHFusionInitializeFromModule(hDll);
  383. SetupDelayloadErrorHandler();
  384. AtlInit(hDll);
  385. DisableThreadLibraryCalls(hDll); // perf
  386. g_hinst = hDll;
  387. InitializeCriticalSection(&g_csDll);
  388. MLLoadResources(g_hinst, TEXT("shdoclc.dll"));
  389. // Don't put it under #ifdef DEBUG
  390. CcshellGetDebugFlags();
  391. #ifdef DEBUG
  392. g_TlsMem = TlsAlloc();
  393. if (IsFlagSet(g_dwBreakFlags, BF_ONLOADED))
  394. {
  395. TraceMsg(TF_ALWAYS, "SHDOCVW.DLL has just loaded");
  396. DEBUG_BREAK;
  397. }
  398. #endif
  399. g_fRunningOnNT = IsOS(OS_NT);
  400. if (g_fRunningOnNT)
  401. g_bRunOnNT5 = IsOS(OS_WIN2000ORGREATER);
  402. else
  403. g_bRunOnMemphis = IsOS(OS_WIN98ORGREATER);
  404. g_fRunOnFE = GetSystemMetrics(SM_DBCSENABLED);
  405. g_uiACP = GetACP();
  406. //
  407. // Check if the mirroring APIs exist on the current
  408. // platform.
  409. //
  410. g_bMirroredOS = IS_MIRRORING_ENABLED();
  411. #ifdef WINDOWS_ME
  412. //
  413. // Check to see if running on BiDi localized Win95
  414. //
  415. g_bBiDiW95Loc = IsBiDiLocalizedWin95(FALSE);
  416. #endif // WINDOWS_ME
  417. InitNFCtl();
  418. // See if perfmode is enabled
  419. g_dwStopWatchMode = StopWatchMode();
  420. // Cache a palette handle for use throughout shdocvw
  421. g_hpalHalftone = SHCreateShellPalette(NULL);
  422. SHCheckRegistry();
  423. }
  424. else if (dwReason == DLL_PROCESS_DETACH)
  425. {
  426. MLFreeResources(g_hinst);
  427. if (g_hMutexHistory)
  428. {
  429. CloseHandle(g_hMutexHistory);
  430. g_hMutexHistory = NULL;
  431. }
  432. if (g_hSemBrowserCount)
  433. CloseHandle(g_hSemBrowserCount);
  434. if (g_hpalHalftone)
  435. DeletePalette(g_hpalHalftone);
  436. if (g_hiconSSL)
  437. DestroyIcon(g_hiconSSL);
  438. if (g_hiconOffline)
  439. DestroyIcon(g_hiconOffline);
  440. if (g_hiconPrinter)
  441. DestroyIcon(g_hiconPrinter);
  442. if (fProcessUnload == NULL)
  443. {
  444. // DLL being unloaded, FreeLibrary() (vs process shutdown)
  445. // at process shutdown time we can't make call outs since
  446. // we don't know if those DLLs will still be loaded!
  447. AtlTerm();
  448. CUrlHistory_CleanUp();
  449. if (g_psfInternet)
  450. {
  451. // Atomic Release for a C pgm.
  452. //
  453. IShellFolder *psfInternet = g_psfInternet;
  454. g_psfInternet = NULL;
  455. psfInternet->Release();
  456. }
  457. UnregisterWindowClasses();
  458. if (g_fRunningOnNT && g_hmodWininet)
  459. {
  460. // we need to free wininet if it was loaded because of a delayload thunk.
  461. //
  462. // (a) we can only safely do this on NT since on win9x calling FreeLibrary during
  463. // process detach can cause a crash (depending on what msvcrt you are using).
  464. //
  465. // (b) we only really need to free this module from winlogon.exe's process context
  466. // because when we apply group policy in winlogon, MUST finally free wininet
  467. // so that it will clean up all of its reg key and file handles.
  468. FreeLibrary(g_hmodWininet);
  469. }
  470. }
  471. SHFusionUninitialize();
  472. DeleteCriticalSection(&g_csDll);
  473. }
  474. return TRUE;
  475. }
  476. STDAPI_(void) DllAddRef(void)
  477. {
  478. InterlockedIncrement(&g_cRefThisDll);
  479. }
  480. STDAPI_(void) DllRelease(void)
  481. {
  482. InterlockedDecrement(&g_cRefThisDll);
  483. ASSERT(g_cRefThisDll >= 0); // don't underflow
  484. }
  485. STDAPI_(UINT) WhichPlatformFORWARD()
  486. {
  487. return WhichPlatform();
  488. }
  489. // IEUNIX
  490. // CoCreateInstance is #defined as IECreateInstance #ifdef __cplusplus,
  491. // so I #undef it here to prevent the recursive call.
  492. // On Windows it works, because this file is C file.
  493. #ifdef CoCreateInstance
  494. #undef CoCreateInstance
  495. #endif
  496. HRESULT IECreateInstance(REFCLSID rclsid, IUnknown *pUnkOuter, DWORD dwClsContext, REFIID riid, void **ppv)
  497. {
  498. #ifndef NO_MARSHALLING
  499. if (dwClsContext == CLSCTX_INPROC_SERVER)
  500. {
  501. #else
  502. if (dwClsContext & CLSCTX_INPROC_SERVER)
  503. {
  504. #endif
  505. for (LPCOBJECTINFO pcls = g_ObjectInfo; pcls->pclsid; pcls++)
  506. {
  507. // Note that we do pointer comparison (instead of IsEuqalGUID)
  508. if (&rclsid == pcls->pclsid)
  509. {
  510. // const -> non-const expclit casting (this is OK)
  511. IClassFactory* pcf = GET_ICLASSFACTORY(pcls);
  512. return pcf->CreateInstance(pUnkOuter, riid, ppv);
  513. }
  514. }
  515. }
  516. // Use SHCoCreateInstanceAC to go through the app compat layer
  517. return SHCoCreateInstanceAC(rclsid, pUnkOuter, dwClsContext, riid, ppv);
  518. }
  519. #ifdef DEBUG
  520. //
  521. // In DEBUG, make sure every class we register lives in the c_rgszClasses
  522. // table so we can clean up properly at DLL unload. NT does not automatically
  523. // unregister classes when a DLL unloads, so we have to do it manually.
  524. //
  525. STDAPI_(BOOL) SHRegisterClassD(CONST WNDCLASS *pwc)
  526. {
  527. for (int i = 0; i < ARRAYSIZE(c_rgszClasses); i++)
  528. {
  529. if (StrCmpI(c_rgszClasses[i], pwc->lpszClassName) == 0)
  530. {
  531. return RealSHRegisterClass(pwc);
  532. }
  533. }
  534. AssertMsg(0, TEXT("Class %s needs to be added to the c_rgszClasses list"), pwc->lpszClassName);
  535. return 0;
  536. }
  537. STDAPI_(ATOM) RegisterClassD(CONST WNDCLASS *pwc)
  538. {
  539. for (int i = 0; i < ARRAYSIZE(c_rgszClasses); i++)
  540. {
  541. if (StrCmpI(c_rgszClasses[i], pwc->lpszClassName) == 0)
  542. {
  543. return RealRegisterClass(pwc);
  544. }
  545. }
  546. AssertMsg(0, TEXT("Class %s needs to be added to the c_rgszClasses list"), pwc->lpszClassName);
  547. return 0;
  548. }
  549. //
  550. // In DEBUG, send FindWindow through a wrapper that ensures that the
  551. // critical section is not taken. FindWindow'ing for a window title
  552. // sends inter-thread WM_GETTEXT messages, which is not obvious.
  553. //
  554. STDAPI_(HWND) FindWindowD(LPCTSTR lpClassName, LPCTSTR lpWindowName)
  555. {
  556. return FindWindowExD(NULL, NULL, lpClassName, lpWindowName);
  557. }
  558. STDAPI_(HWND) FindWindowExD(HWND hwndParent, HWND hwndChildAfter, LPCTSTR lpClassName, LPCTSTR lpWindowName)
  559. {
  560. if (lpWindowName) {
  561. ASSERTNONCRITICAL;
  562. }
  563. return RealFindWindowEx(hwndParent, hwndChildAfter, lpClassName, lpWindowName);
  564. }
  565. #endif // DEBUG