//------------------------------------------------------------------------------ // File: DlleEntry.cpp // // Desc: DirectShow base classes - implements classes used to support dll // entry points for COM objects. // // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ #include #include #ifdef DEBUG #ifdef UNICODE #ifndef _UNICODE #define _UNICODE #endif // _UNICODE #endif // UNICODE #include #endif // DEBUG #include extern CFactoryTemplate g_Templates[]; extern int g_cTemplates; HINSTANCE g_hInst; DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx) OSVERSIONINFO g_osInfo; // // an instance of this is created by the DLLGetClassObject entrypoint // it uses the CFactoryTemplate object it is given to support the // IClassFactory interface class CClassFactory : public IClassFactory, public CBaseObject { private: const CFactoryTemplate *const m_pTemplate; ULONG m_cRef; static int m_cLocked; public: CClassFactory(const CFactoryTemplate *); // IUnknown STDMETHODIMP QueryInterface(REFIID riid, __deref_out void ** ppv); STDMETHODIMP_(ULONG)AddRef(); STDMETHODIMP_(ULONG)Release(); // IClassFactory STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, __deref_out void **pv); STDMETHODIMP LockServer(BOOL fLock); // allow DLLGetClassObject to know about global server lock status static BOOL IsLocked() { return (m_cLocked > 0); }; }; // process-wide dll locked state int CClassFactory::m_cLocked = 0; CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate) : CBaseObject(NAME("Class Factory")) , m_cRef(0) , m_pTemplate(pTemplate) { } STDMETHODIMP CClassFactory::QueryInterface(REFIID riid,__deref_out void **ppv) { CheckPointer(ppv,E_POINTER) ValidateReadWritePtr(ppv,sizeof(PVOID)); *ppv = NULL; // any interface on this object is the object pointer. if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) { *ppv = (LPVOID) this; // AddRef returned interface pointer ((LPUNKNOWN) *ppv)->AddRef(); return NOERROR; } return ResultFromScode(E_NOINTERFACE); } STDMETHODIMP_(ULONG) CClassFactory::AddRef() { return ++m_cRef; } STDMETHODIMP_(ULONG) CClassFactory::Release() { LONG lRef = InterlockedDecrement((volatile LONG *)&m_cRef); if (lRef == 0) { delete this; return 0; } else { return lRef; } } STDMETHODIMP CClassFactory::CreateInstance( LPUNKNOWN pUnkOuter, REFIID riid, __deref_out void **pv) { CheckPointer(pv,E_POINTER) ValidateReadWritePtr(pv,sizeof(void *)); *pv = NULL; /* Enforce the normal OLE rules regarding interfaces and delegation */ if (pUnkOuter != NULL) { if (IsEqualIID(riid,IID_IUnknown) == FALSE) { *pv = NULL; return ResultFromScode(E_NOINTERFACE); } } /* Create the new object through the derived class's create function */ HRESULT hr = NOERROR; CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr); if (pObj == NULL) { *pv = NULL; if (SUCCEEDED(hr)) { hr = E_OUTOFMEMORY; } return hr; } /* Delete the object if we got a construction error */ if (FAILED(hr)) { delete pObj; *pv = NULL; return hr; } /* Get a reference counted interface on the object */ /* We wrap the non-delegating QI with NDAddRef & NDRelease. */ /* This protects any outer object from being prematurely */ /* released by an inner object that may have to be created */ /* in order to supply the requested interface. */ pObj->NonDelegatingAddRef(); hr = pObj->NonDelegatingQueryInterface(riid, pv); pObj->NonDelegatingRelease(); /* Note that if NonDelegatingQueryInterface fails, it will */ /* not increment the ref count, so the NonDelegatingRelease */ /* will drop the ref back to zero and the object will "self-*/ /* destruct". Hence we don't need additional tidy-up code */ /* to cope with NonDelegatingQueryInterface failing. */ if (SUCCEEDED(hr)) { ASSERT(*pv); } return hr; } STDMETHODIMP CClassFactory::LockServer(BOOL fLock) { if (fLock) { m_cLocked++; } else { m_cLocked--; } return NOERROR; } // --- COM entrypoints ----------------------------------------- //called by COM to get the class factory object for a given class __control_entrypoint(DllExport) STDAPI DllGetClassObject( __in REFCLSID rClsID, __in REFIID riid, __deref_out void **pv) { *pv = NULL; if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) { return E_NOINTERFACE; } // traverse the array of templates looking for one with this // class id for (int i = 0; i < g_cTemplates; i++) { const CFactoryTemplate * pT = &g_Templates[i]; if (pT->IsClassID(rClsID)) { // found a template - make a class factory based on this // template *pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT); if (*pv == NULL) { return E_OUTOFMEMORY; } ((LPUNKNOWN)*pv)->AddRef(); return NOERROR; } } return CLASS_E_CLASSNOTAVAILABLE; } // // Call any initialization routines // void DllInitClasses(BOOL bLoading) { int i; // traverse the array of templates calling the init routine // if they have one for (i = 0; i < g_cTemplates; i++) { const CFactoryTemplate * pT = &g_Templates[i]; if (pT->m_lpfnInit != NULL) { (*pT->m_lpfnInit)(bLoading, pT->m_ClsID); } } } // called by COM to determine if this dll can be unloaded // return ok unless there are outstanding objects or a lock requested // by IClassFactory::LockServer // // CClassFactory has a static function that can tell us about the locks, // and CCOMObject has a static function that can tell us about the active // object count STDAPI DllCanUnloadNow() { DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"), CClassFactory::IsLocked(), CBaseObject::ObjectsActive())); if (CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) { return S_FALSE; } else { return S_OK; } } // --- standard WIN32 entrypoints -------------------------------------- extern "C" void __cdecl __security_init_cookie(void); extern "C" BOOL WINAPI _DllEntryPoint(HINSTANCE, ULONG, __inout_opt LPVOID); #pragma comment(linker, "/merge:.CRT=.rdata") extern "C" DECLSPEC_NOINLINE BOOL WINAPI DllEntryPoint( HINSTANCE hInstance, ULONG ulReason, __inout_opt LPVOID pv ) { if ( ulReason == DLL_PROCESS_ATTACH ) { // Must happen before any other code is executed. Thankfully - it's re-entrant __security_init_cookie(); } return _DllEntryPoint(hInstance, ulReason, pv); } DECLSPEC_NOINLINE BOOL WINAPI _DllEntryPoint( HINSTANCE hInstance, ULONG ulReason, __inout_opt LPVOID pv ) { #ifdef DEBUG extern bool g_fDbgInDllEntryPoint; g_fDbgInDllEntryPoint = true; #endif switch (ulReason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hInstance); DbgInitialise(hInstance); { // The platform identifier is used to work out whether // full unicode support is available or not. Hence the // default will be the lowest common denominator - i.e. N/A g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo); if (GetVersionEx(&g_osInfo)) { g_amPlatform = g_osInfo.dwPlatformId; } else { DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95"))); } } g_hInst = hInstance; DllInitClasses(TRUE); break; case DLL_PROCESS_DETACH: DllInitClasses(FALSE); #ifdef DEBUG if (CBaseObject::ObjectsActive()) { DbgSetModuleLevel(LOG_MEMORY, 2); TCHAR szInfo[512]; extern TCHAR m_ModuleName[]; // Cut down module name TCHAR FullName[_MAX_PATH]; // Load the full path and module name TCHAR *pName; // Searches from the end for a backslash GetModuleFileName(NULL,FullName,_MAX_PATH); pName = _tcsrchr(FullName,'\\'); if (pName == NULL) { pName = FullName; } else { pName++; } (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("Executable: %s Pid %x Tid %x. "), pName, GetCurrentProcessId(), GetCurrentThreadId()); (void)StringCchPrintf(szInfo+lstrlen(szInfo), NUMELMS(szInfo) - lstrlen(szInfo), TEXT("Module %s, %d objects left active!"), m_ModuleName, CBaseObject::ObjectsActive()); DbgAssert(szInfo, TEXT(__FILE__),__LINE__); // If running remotely wait for the Assert to be acknowledged // before dumping out the object register DbgDumpObjectRegister(); } DbgTerminate(); #endif break; } #ifdef DEBUG g_fDbgInDllEntryPoint = false; #endif return TRUE; }