374 lines
9.4 KiB
C++
374 lines
9.4 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>
|
|
#include "combase.h"
|
|
|
|
#ifdef DEBUG
|
|
#ifdef UNICODE
|
|
#ifndef _UNICODE
|
|
#define _UNICODE
|
|
#endif // _UNICODE
|
|
#endif // UNICODE
|
|
|
|
#include <tchar.h>
|
|
#endif // DEBUG
|
|
#include <strsafe.h>
|
|
|
|
|
|
//extern int g_cTemplates;
|
|
//extern CFactoryTemplate g_Templates[];
|
|
|
|
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;
|
|
}
|
|
|
|
*/
|