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;
 | |
| }
 | |
| 
 | |
| 
 |