610 lines
18 KiB
C++
610 lines
18 KiB
C++
//#define DONT_USE_ATL
|
|
#include "priv.h"
|
|
#define ATL_ENABLED
|
|
#include "atl.h"
|
|
|
|
#include "sccls.h"
|
|
#include <ntverp.h>
|
|
|
|
#include <shlobj.h> // for CLSID_ACLMRU
|
|
#include <schedule.h>
|
|
|
|
#include "shbrows2.h" // CWinInetNotify_szWindowClass
|
|
#include "desktop.h" // DESKTOPPROXYCLASS
|
|
|
|
#include "mluisupp.h"
|
|
#define DECL_CRTFREE
|
|
#include <crtfree.h>
|
|
#include "shfusion.h"
|
|
|
|
STDAPI_(void) InitURLIDs(UINT uPlatform); // from shdocfl.cpp
|
|
STDAPI SHIsThereASystemScheduler(void); // from schedule.cpp
|
|
STDAPI SHFreeSystemScheduler(void);
|
|
|
|
//
|
|
// Downlevel delay load support (we forward to shlwapi)
|
|
//
|
|
#include <delayimp.h>
|
|
|
|
PfnDliHook __pfnDliFailureHook;
|
|
HANDLE BaseDllHandle;
|
|
|
|
|
|
LONG g_cRefThisDll = 0; // per-instance
|
|
CRITICAL_SECTION g_csDll = {0}; // per-instance
|
|
HINSTANCE g_hinst = NULL;
|
|
HANDLE g_hMutexHistory = NULL;
|
|
|
|
|
|
BOOL g_fNashInNewProcess = FALSE; // Are we running in a separate process
|
|
BOOL g_fRunningOnNT = FALSE;
|
|
BOOL g_bRunOnNT5 = FALSE;
|
|
BOOL g_fRunOnWhistler = FALSE;
|
|
BOOL g_bRunOnMemphis = FALSE;
|
|
BOOL g_fRunOnFE = FALSE;
|
|
DWORD g_dwStopWatchMode = 0; // Shell perf automation
|
|
HANDLE g_hCabStateChange = NULL;
|
|
BOOL g_fIE = FALSE;
|
|
|
|
// Is Mirroring enabled
|
|
BOOL g_bMirroredOS = FALSE;
|
|
|
|
HPALETTE g_hpalHalftone = NULL;
|
|
|
|
void DestroyZoneIconNameCache(void);
|
|
|
|
//
|
|
// This array holds information needed for ClassFacory.
|
|
// OLEMISC_ flags are used by shembed and shocx.
|
|
//
|
|
// PERF: this table should be ordered in most-to-least used order
|
|
//
|
|
CF_TABLE_BEGIN(g_ObjectInfo)
|
|
|
|
CF_TABLE_ENTRY(&CLSID_InternetToolbar, CInternetToolbar_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_BrandBand, CBrandBand_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_MenuBandSite, CMenuBandSite_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_MenuDeskBar, CMenuDeskBar_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_AugmentedShellFolder, CAugmentedISF_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_AugmentedShellFolder2, CAugmentedISF2_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_AddressBand, CAddressBand_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_AddressEditBox, CAddressEditBox_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_BandProxy, CBandProxy_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY_NOFLAGS( &CLSID_RebarBandSite, CBandSite_CreateInstance,
|
|
COCREATEONLY_NOFLAGS, OIF_ALLOWAGGREGATION),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_DeskBarApp, CDeskBarApp_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_DeskBar, CDeskBar_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_AutoComplete, CAutoComplete_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_ACLHistory, CACLHistory_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_ACListISF, CACLIShellFolder_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_ACLMRU, CACLMRU_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_ACLMulti, CACLMulti_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY_NOFLAGS( &CLSID_CCommonBrowser, CCommonBrowser_CreateInstance,
|
|
COCREATEONLY_NOFLAGS, OIF_ALLOWAGGREGATION),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_CDockingBarPropertyBag, CDockingBarPropertyBag_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_CRegTreeOptions, CRegTreeOptions_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_BrowserBand, CBrowserBand_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_SearchBand, CSearchBand_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_MediaBand, CMediaBand_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_CommBand, CCommBand_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_BandSiteMenu, CBandSiteMenu_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_ComCatCacheTask, CComCatCacheTask_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_ComCatConditionalCacheTask,CComCatConditionalCacheTask_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_ImgCtxThumbnailExtractor, CImgCtxThumb_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_ImageListCache, CImageListCache_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_ShellTaskScheduler, CShellTaskScheduler_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_SharedTaskScheduler, CSharedTaskScheduler_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_BrowseuiPreloader, CBitmapPreload_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_ShellSearchExt, CShellSearchExt_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_WebSearchExt, CWebSearchExt_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_OrderListExport, COrderList_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_UserAssist, CUserAssist_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_GlobalFolderSettings, CGlobalFolderSettings_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_ProgressDialog, CProgressDialog_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_ACLCustomMRU, CACLCustomMRU_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY(&CLSID_AddressBarParser, CShellUrl_CreateInstance,
|
|
COCREATEONLY),
|
|
|
|
CF_TABLE_ENTRY_NOFLAGS( &CLSID_MenuBand, CMenuBand_CreateInstance,
|
|
COCREATEONLY_NOFLAGS, OIF_DONTIECREATE), // legacy component, dont default to browseui's impl
|
|
|
|
CF_TABLE_ENTRY_NOFLAGS( &CLSID_QuickLinks, CQuickLinks_CreateInstance,
|
|
COCREATEONLY_NOFLAGS, OIF_DONTIECREATE), // legacy component, dont default to browseui's impl
|
|
|
|
CF_TABLE_ENTRY_NOFLAGS( &CLSID_ISFBand, CISFBand_CreateInstance,
|
|
COCREATEONLY_NOFLAGS, OIF_DONTIECREATE), // legacy component, dont default to browseui's impl
|
|
|
|
CF_TABLE_ENTRY_NOFLAGS( &CLSID_Thumbnail, CThumbnail_CreateInstance,
|
|
COCREATEONLY_NOFLAGS, OIF_DONTIECREATE), // legacy component, dont default to browseui's impl
|
|
|
|
CF_TABLE_ENTRY_NOFLAGS(&CLSID_TrackShellMenu, CTrackShellMenu_CreateInstance,
|
|
COCREATEONLY_NOFLAGS, OIF_DONTIECREATE), // legacy component, dont default to browseui's impl
|
|
|
|
CF_TABLE_END(g_ObjectInfo)
|
|
|
|
// constructor for CObjectInfo.
|
|
|
|
CObjectInfo::CObjectInfo(CLSID const* pclsidin, LPFNCREATEOBJINSTANCE pfnCreatein, IID const* piidIn,
|
|
IID const* piidEventsIn, long lVersionIn, DWORD dwOleMiscFlagsIn,
|
|
DWORD dwClassFactFlagsIn)
|
|
{
|
|
pclsid = pclsidin;
|
|
pfnCreateInstance = pfnCreatein;
|
|
piid = piidIn;
|
|
piidEvents = piidEventsIn;
|
|
lVersion = lVersionIn;
|
|
dwOleMiscFlags = dwOleMiscFlagsIn;
|
|
dwClassFactFlags = dwClassFactFlagsIn;
|
|
}
|
|
|
|
|
|
// static class factory (no allocs!)
|
|
|
|
STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
*ppvObj = (void *)GET_ICLASSFACTORY(this);
|
|
DllAddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CClassFactory::AddRef()
|
|
{
|
|
DllAddRef();
|
|
return 2;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CClassFactory::Release()
|
|
{
|
|
DllRelease();
|
|
return 1;
|
|
}
|
|
|
|
STDMETHODIMP CClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
|
|
{
|
|
*ppv = NULL;
|
|
|
|
if (punkOuter && !IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
// It is technically illegal to aggregate an object and request
|
|
// any interface other than IUnknown. Enforce this.
|
|
//
|
|
return CLASS_E_NOAGGREGATION;
|
|
}
|
|
else
|
|
{
|
|
LPOBJECTINFO pthisobj = (LPOBJECTINFO)this;
|
|
|
|
if (punkOuter && !(pthisobj->dwClassFactFlags & OIF_ALLOWAGGREGATION))
|
|
return CLASS_E_NOAGGREGATION;
|
|
|
|
IUnknown *punk;
|
|
HRESULT hres = pthisobj->pfnCreateInstance(punkOuter, &punk, pthisobj);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = punk->QueryInterface(riid, ppv);
|
|
punk->Release();
|
|
}
|
|
|
|
ASSERT(FAILED(hres) ? *ppv == NULL : TRUE);
|
|
return hres;
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
|
|
{
|
|
if (fLock)
|
|
DllAddRef();
|
|
else
|
|
DllRelease();
|
|
TraceMsg(DM_TRACE, "sccls: LockServer(%s) to %d", fLock ? TEXT("LOCK") : TEXT("UNLOCK"), g_cRefThisDll);
|
|
return S_OK;
|
|
}
|
|
|
|
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
|
|
{
|
|
TraceMsg(TF_SHDLIFE, "DllGetClassObject called with riid=%x (%x)", riid, &riid);
|
|
|
|
if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
for (LPCOBJECTINFO pcls = g_ObjectInfo; pcls->pclsid; pcls++)
|
|
{
|
|
if (IsEqualGUID(rclsid, *(pcls->pclsid)))
|
|
{
|
|
*ppv = (void*)pcls;
|
|
DllAddRef(); // class factory holds DLL ref count
|
|
return NOERROR;
|
|
}
|
|
}
|
|
|
|
#ifdef ATL_ENABLED
|
|
// Try the ATL class factory
|
|
if (SUCCEEDED(AtlGetClassObject(rclsid, riid, ppv)))
|
|
return NOERROR;
|
|
#endif
|
|
}
|
|
|
|
*ppv = NULL;
|
|
return CLASS_E_CLASSNOTAVAILABLE;
|
|
}
|
|
|
|
STDAPI DllCanUnloadNow(void)
|
|
{
|
|
#ifndef UNIX
|
|
// special case for the system scheduler we hang onto
|
|
if ( g_cRefThisDll == 1 && SHIsThereASystemScheduler() == S_OK )
|
|
{
|
|
// this will drop the ref count by one to zero....
|
|
SHFreeSystemScheduler();
|
|
}
|
|
|
|
#ifdef ATL_ENABLED
|
|
if (0 != g_cRefThisDll || 0 != AtlGetLockCount())
|
|
return S_FALSE;
|
|
#else
|
|
if (0 != g_cRefThisDll)
|
|
return S_FALSE;
|
|
#endif
|
|
|
|
#else
|
|
if (g_cRefThisDll)
|
|
return S_FALSE;
|
|
#endif
|
|
|
|
TraceMsg(DM_TRACE, "DllCanUnloadNow returning S_OK (bye, bye...)");
|
|
return S_OK;
|
|
}
|
|
|
|
// DllGetVersion
|
|
//
|
|
// All we have to do is declare this puppy and CCDllGetVersion does the rest
|
|
//
|
|
DLLVER_SINGLEBINARY(VER_PRODUCTVERSION_DW, VER_PRODUCTBUILD_QFE);
|
|
|
|
UINT g_msgMSWheel;
|
|
#ifdef DEBUG
|
|
EXTERN_C DWORD g_TlsMem = 0xffffffff;
|
|
#endif
|
|
|
|
// imports from isfband.cpp
|
|
STDAPI_(void) CLogoBase_Initialize( void );
|
|
STDAPI_(void) CLogoBase_Cleanup( void );
|
|
|
|
//
|
|
// Table of all window classes we register so we can unregister them
|
|
// at DLL unload.
|
|
//
|
|
|
|
const LPCTSTR c_rgszClasses[] = {
|
|
TEXT("BaseBar"), // basebar.cpp
|
|
TEXT("MenuSite"), // menusite.cpp
|
|
DESKTOPPROXYCLASS, // proxy.cpp
|
|
c_szExploreClass, // shbrows2.cpp
|
|
c_szIExploreClass, // shbrows2.cpp
|
|
c_szCabinetClass, // shbrows2.cpp
|
|
c_szAutoSuggestClass, // autocomp.cpp
|
|
TEXT("MediaPane"), //Mediaband.cpp
|
|
TEXT("MediaPopupPane"), //Mediaband.cpp
|
|
TEXT("MediaLayoutPane") //Mediaband.cpp
|
|
};
|
|
|
|
//
|
|
// Since we are single-binary, we have to play it safe and do
|
|
// this cleanup (needed only on NT, but harmless on Win95).
|
|
//
|
|
#define UnregisterWindowClasses() \
|
|
SHUnregisterClasses(HINST_THISDLL, c_rgszClasses, ARRAYSIZE(c_rgszClasses))
|
|
|
|
void InitNFCtl()
|
|
{
|
|
|
|
INITCOMMONCONTROLSEX icc;
|
|
|
|
icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
|
icc.dwICC = ICC_NATIVEFNTCTL_CLASS;
|
|
InitCommonControlsEx(&icc);
|
|
}
|
|
const LPCTSTR s_aryExplorerFileName[] =
|
|
{
|
|
TEXT("iexplore.exe"),
|
|
};
|
|
|
|
BOOL IsRootExeExplorer(void)
|
|
{
|
|
TCHAR szApp[MAX_PATH];
|
|
LPCTSTR pszApp;
|
|
GetModuleFileName(NULL, szApp, ARRAYSIZE(szApp));
|
|
pszApp = PathFindFileName(szApp);
|
|
if (pszApp)
|
|
{
|
|
for (int i = 0; i < ARRAYSIZE(s_aryExplorerFileName); i++)
|
|
{
|
|
if (!lstrcmpi(pszApp, s_aryExplorerFileName[i]))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// we use shlwapi as our delayload error handler.
|
|
// NOTE: this only works if we are statically linked to shlwapi!
|
|
//
|
|
void SetupDelayloadErrorHandler()
|
|
{
|
|
BaseDllHandle = GetModuleHandleA("shlwapi.dll");
|
|
ASSERTMSG(BaseDllHandle != NULL, "BROWSEUI must be statically linked to shlwapi.dll for delayload failure handling to work!");
|
|
__pfnDliFailureHook = (PfnDliHook)GetProcAddress((HMODULE)BaseDllHandle, "DelayLoadFailureHook");
|
|
}
|
|
|
|
STDAPI_(BOOL) DllMain(HINSTANCE hDll, DWORD dwReason, void *fProcessUnload)
|
|
{
|
|
if (dwReason == DLL_PROCESS_ATTACH)
|
|
{
|
|
SHFusionInitializeFromModule(hDll);
|
|
|
|
SetupDelayloadErrorHandler();
|
|
|
|
#ifdef ATL_ENABLED
|
|
AtlInit(hDll);
|
|
#endif
|
|
DisableThreadLibraryCalls(hDll); // perf
|
|
|
|
g_hinst = hDll;
|
|
InitializeCriticalSection(&g_csDll);
|
|
g_msgMSWheel = RegisterWindowMessage(TEXT("MSWHEEL_ROLLMSG"));
|
|
|
|
MLLoadResources(g_hinst, TEXT("browselc.dll"));
|
|
g_fIE = IsRootExeExplorer();
|
|
if (g_fIE)
|
|
InitMUILanguage(MLGetUILanguage());
|
|
|
|
// Don't put it under #ifdef DEBUG
|
|
CcshellGetDebugFlags();
|
|
|
|
#ifdef DEBUG
|
|
g_TlsMem = TlsAlloc();
|
|
if (IsFlagSet(g_dwBreakFlags, BF_ONLOADED))
|
|
{
|
|
TraceMsg(TF_ALWAYS, "DllMain() - SHDOCVW.DLL has just loaded");
|
|
DEBUG_BREAK;
|
|
}
|
|
#endif
|
|
g_fRunningOnNT = IsOS(OS_NT);
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
g_bRunOnNT5 = IsOS(OS_WIN2000ORGREATER);
|
|
g_fRunOnWhistler = IsOS(OS_WHISTLERORGREATER);
|
|
}
|
|
else
|
|
g_bRunOnMemphis = IsOS(OS_WIN98ORGREATER);
|
|
|
|
g_fRunOnFE = GetSystemMetrics(SM_DBCSENABLED);
|
|
|
|
g_bMirroredOS = IS_MIRRORING_ENABLED();
|
|
|
|
InitNFCtl();
|
|
|
|
// See if perfmode is enabled
|
|
g_dwStopWatchMode = StopWatchMode();
|
|
|
|
// Cache a palette handle for use throughout shdocvw
|
|
g_hpalHalftone = SHCreateShellPalette( NULL );
|
|
CLogoBase_Initialize( );
|
|
}
|
|
else if (dwReason == DLL_PROCESS_DETACH)
|
|
{
|
|
#ifdef ATL_ENABLED
|
|
AtlTerm();
|
|
#endif
|
|
CBrandBand_CleanUp();
|
|
CInternetToolbar_CleanUp();
|
|
CUserAssist_CleanUp(dwReason, fProcessUnload);
|
|
|
|
CLogoBase_Cleanup();
|
|
|
|
// let go of the resource DLL...
|
|
MLFreeResources(g_hinst);
|
|
|
|
ENTERCRITICAL;
|
|
|
|
DESTROY_OBJ_WITH_HANDLE(g_hpalHalftone, DeletePalette);
|
|
DESTROY_OBJ_WITH_HANDLE(g_hCabStateChange, SHGlobalCounterDestroy);
|
|
DESTROY_OBJ_WITH_HANDLE(g_hMutexHistory, CloseHandle);
|
|
|
|
DestroyZoneIconNameCache();
|
|
|
|
UnregisterWindowClasses();
|
|
|
|
LEAVECRITICAL;
|
|
|
|
DeleteCriticalSection(&g_csDll);
|
|
|
|
SHFusionUninitialize();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
STDAPI_(void) DllAddRef(void)
|
|
{
|
|
InterlockedIncrement(&g_cRefThisDll);
|
|
}
|
|
|
|
STDAPI_(void) DllRelease(void)
|
|
{
|
|
InterlockedDecrement(&g_cRefThisDll);
|
|
|
|
ASSERT(g_cRefThisDll >= 0); // don't underflow
|
|
}
|
|
|
|
// IEUNIX
|
|
// CoCreateInstance is #defined as IECreateInstance #ifdef __cplusplus,
|
|
// so I #undef it here to prevent the recursive call.
|
|
// On Windows it works, because this file is C file.
|
|
|
|
#ifdef CoCreateInstance
|
|
#undef CoCreateInstance
|
|
#endif
|
|
|
|
HRESULT IECreateInstance(REFCLSID rclsid, IUnknown *pUnkOuter,
|
|
DWORD dwClsContext, REFIID riid, void **ppv)
|
|
{
|
|
#ifndef NO_MARSHALLING
|
|
if (dwClsContext == CLSCTX_INPROC_SERVER)
|
|
#else
|
|
if (dwClsContext & CLSCTX_INPROC_SERVER)
|
|
#endif
|
|
{
|
|
LPCOBJECTINFO pcls;
|
|
for (pcls = g_ObjectInfo; pcls->pclsid; pcls++)
|
|
{
|
|
// Note that we do pointer comparison (instead of IsEuqalGUID)
|
|
if ((&rclsid == pcls->pclsid) && !(pcls->dwClassFactFlags & OIF_DONTIECREATE))
|
|
{
|
|
// const -> non-const expclit casting (this is OK)
|
|
IClassFactory* pcf = GET_ICLASSFACTORY(pcls);
|
|
return pcf->CreateInstance(pUnkOuter, riid, ppv);
|
|
}
|
|
}
|
|
}
|
|
// Use SHCoCreateInstanceAC to go through the app compat layer
|
|
return SHCoCreateInstanceAC(rclsid, pUnkOuter, dwClsContext, riid, ppv);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
//
|
|
// In DEBUG, make sure every class we register lives in the c_rgszClasses
|
|
// table so we can clean up properly at DLL unload. NT does not automatically
|
|
// unregister classes when a DLL unloads, so we have to do it manually.
|
|
//
|
|
STDAPI_(BOOL) SHRegisterClassD(CONST WNDCLASS *pwc)
|
|
{
|
|
for (int i = 0; i < ARRAYSIZE(c_rgszClasses); i++)
|
|
{
|
|
if (lstrcmpi(c_rgszClasses[i], pwc->lpszClassName) == 0)
|
|
{
|
|
return RealSHRegisterClass(pwc);
|
|
}
|
|
}
|
|
AssertMsg(0, TEXT("Class %s needs to be added to the c_rgszClasses list"), pwc->lpszClassName);
|
|
return 0;
|
|
}
|
|
|
|
STDAPI_(ATOM) RegisterClassD(CONST WNDCLASS *pwc)
|
|
{
|
|
for (int i = 0; i < ARRAYSIZE(c_rgszClasses); i++)
|
|
{
|
|
if (lstrcmpi(c_rgszClasses[i], pwc->lpszClassName) == 0)
|
|
{
|
|
return RealRegisterClass(pwc);
|
|
}
|
|
}
|
|
AssertMsg(0, TEXT("Class %s needs to be added to the c_rgszClasses list"), pwc->lpszClassName);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// In DEBUG, send FindWindow through a wrapper that ensures that the
|
|
// critical section is not taken. FindWindow'ing for a window title
|
|
// sends inter-thread WM_GETTEXT messages, which is not obvious.
|
|
//
|
|
STDAPI_(HWND) FindWindowD(LPCTSTR lpClassName, LPCTSTR lpWindowName)
|
|
{
|
|
return FindWindowExD(NULL, NULL, lpClassName, lpWindowName);
|
|
}
|
|
|
|
STDAPI_(HWND) FindWindowExD(HWND hwndParent, HWND hwndChildAfter, LPCTSTR lpClassName, LPCTSTR lpWindowName)
|
|
{
|
|
if (lpWindowName)
|
|
{
|
|
ASSERTNONCRITICAL;
|
|
}
|
|
return RealFindWindowEx(hwndParent, hwndChildAfter, lpClassName, lpWindowName);
|
|
}
|
|
|
|
#endif // DEBUG
|