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.

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