forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			370 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			370 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | //------------------------------------------------------------------------------
 | ||
|  | // 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 <streams.h>
 | ||
|  | #include <initguid.h>
 | ||
|  | 
 | ||
|  | #ifdef DEBUG
 | ||
|  | #ifdef UNICODE
 | ||
|  | #ifndef _UNICODE
 | ||
|  | #define _UNICODE
 | ||
|  | #endif // _UNICODE
 | ||
|  | #endif // UNICODE
 | ||
|  | 
 | ||
|  | #include <tchar.h>
 | ||
|  | #endif // DEBUG
 | ||
|  | #include <strsafe.h>
 | ||
|  | 
 | ||
|  | #pragma warning(disable: 4996)
 | ||
|  | 
 | ||
|  | 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; | ||
|  | } | ||
|  | 
 | ||
|  | 
 |