520 lines
11 KiB
C++
520 lines
11 KiB
C++
/*
|
|
* clsfact.cpp - IClassFactory implementation.
|
|
*/
|
|
|
|
|
|
/* Headers
|
|
**********/
|
|
|
|
#include "project.hpp"
|
|
#pragma hdrstop
|
|
|
|
#include "clsfact.h"
|
|
#include "ftps.hpp"
|
|
#include "inetcpl.h"
|
|
#include "inetps.hpp"
|
|
|
|
|
|
/* Types
|
|
********/
|
|
|
|
// callback function used by ClassFactory::ClassFactory()
|
|
|
|
typedef PIUnknown (*NEWOBJECTPROC)(OBJECTDESTROYEDPROC);
|
|
DECLARE_STANDARD_TYPES(NEWOBJECTPROC);
|
|
|
|
// description of class supported by DllGetClassObject()
|
|
|
|
typedef struct classconstructor
|
|
{
|
|
PCCLSID pcclsid;
|
|
|
|
NEWOBJECTPROC NewObject;
|
|
}
|
|
CLASSCONSTRUCTOR;
|
|
DECLARE_STANDARD_TYPES(CLASSCONSTRUCTOR);
|
|
|
|
|
|
/* Classes
|
|
**********/
|
|
|
|
// object class factory
|
|
|
|
class ClassFactory : public RefCount,
|
|
public IClassFactory
|
|
{
|
|
private:
|
|
NEWOBJECTPROC m_NewObject;
|
|
|
|
public:
|
|
ClassFactory(NEWOBJECTPROC NewObject, OBJECTDESTROYEDPROC ObjectDestroyed);
|
|
~ClassFactory(void);
|
|
|
|
// IClassFactory methods
|
|
|
|
HRESULT STDMETHODCALLTYPE CreateInstance(PIUnknown piunkOuter, REFIID riid, PVOID *ppvObject);
|
|
HRESULT STDMETHODCALLTYPE LockServer(BOOL bLock);
|
|
|
|
// IUnknown methods
|
|
|
|
ULONG STDMETHODCALLTYPE AddRef(void);
|
|
ULONG STDMETHODCALLTYPE Release(void);
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppvObj);
|
|
|
|
// friends
|
|
|
|
#ifdef DEBUG
|
|
|
|
friend BOOL IsValidPCClassFactory(const ClassFactory *pcurlcf);
|
|
|
|
#endif
|
|
|
|
};
|
|
DECLARE_STANDARD_TYPES(ClassFactory);
|
|
|
|
|
|
/* Module Prototypes
|
|
********************/
|
|
|
|
PRIVATE_CODE PIUnknown NewInternetShortcut(OBJECTDESTROYEDPROC ObjectDestroyed);
|
|
PRIVATE_CODE PIUnknown NewMIMEHook(OBJECTDESTROYEDPROC ObjectDestroyed);
|
|
PRIVATE_CODE PIUnknown NewInternet(OBJECTDESTROYEDPROC ObjectDestroyed);
|
|
|
|
|
|
/* Module Constants
|
|
*******************/
|
|
|
|
#pragma data_seg(DATA_SEG_READ_ONLY)
|
|
|
|
PRIVATE_DATA CCLASSCONSTRUCTOR s_cclscnstr[] =
|
|
{
|
|
{ &CLSID_InternetShortcut, &NewInternetShortcut },
|
|
{ &CLSID_MIMEFileTypesPropSheetHook, &NewMIMEHook },
|
|
{ &CLSID_Internet, &NewInternet },
|
|
};
|
|
|
|
#pragma data_seg()
|
|
|
|
|
|
/* Module Variables
|
|
*******************/
|
|
|
|
#pragma data_seg(DATA_SEG_PER_INSTANCE)
|
|
|
|
// DLL reference count == number of class factories +
|
|
// number of URLs +
|
|
// LockServer() count
|
|
|
|
PRIVATE_DATA ULONG s_ulcDLLRef = 0;
|
|
|
|
#pragma data_seg()
|
|
|
|
|
|
/***************************** Private Functions *****************************/
|
|
|
|
|
|
PRIVATE_CODE HRESULT GetClassConstructor(REFCLSID rclsid,
|
|
PNEWOBJECTPROC pNewObject)
|
|
{
|
|
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
|
|
UINT u;
|
|
|
|
ASSERT(IsValidREFCLSID(rclsid));
|
|
ASSERT(IS_VALID_WRITE_PTR(pNewObject, NEWOBJECTPROC));
|
|
|
|
*pNewObject = NULL;
|
|
|
|
for (u = 0; u < ARRAY_ELEMENTS(s_cclscnstr); u++)
|
|
{
|
|
if (rclsid == *(s_cclscnstr[u].pcclsid))
|
|
{
|
|
*pNewObject = s_cclscnstr[u].NewObject;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
ASSERT((hr == S_OK &&
|
|
IS_VALID_CODE_PTR(*pNewObject, NEWOBJECTPROC)) ||
|
|
(hr == CLASS_E_CLASSNOTAVAILABLE &&
|
|
! *pNewObject));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
PRIVATE_CODE void STDMETHODCALLTYPE DLLObjectDestroyed(void)
|
|
{
|
|
TRACE_OUT(("DLLObjectDestroyed(): Object destroyed."));
|
|
|
|
DLLRelease();
|
|
}
|
|
|
|
|
|
PRIVATE_CODE PIUnknown NewInternetShortcut(OBJECTDESTROYEDPROC ObjectDestroyed)
|
|
{
|
|
ASSERT(! ObjectDestroyed ||
|
|
IS_VALID_CODE_PTR(ObjectDestroyed, OBJECTDESTROYEDPROC));
|
|
|
|
TRACE_OUT(("NewInternetShortcut(): Creating a new InternetShortcut."));
|
|
|
|
return((PIUnknown)(PIUniformResourceLocator)new(InternetShortcut(ObjectDestroyed)));
|
|
}
|
|
|
|
|
|
PRIVATE_CODE PIUnknown NewMIMEHook(OBJECTDESTROYEDPROC ObjectDestroyed)
|
|
{
|
|
ASSERT(! ObjectDestroyed ||
|
|
IS_VALID_CODE_PTR(ObjectDestroyed, OBJECTDESTROYEDPROC));
|
|
|
|
TRACE_OUT(("NewMIMEHook(): Creating a new MIMEHook."));
|
|
|
|
return((PIUnknown)(PIShellPropSheetExt)new(MIMEHook(ObjectDestroyed)));
|
|
}
|
|
|
|
|
|
PRIVATE_CODE PIUnknown NewInternet(OBJECTDESTROYEDPROC ObjectDestroyed)
|
|
{
|
|
ASSERT(! ObjectDestroyed ||
|
|
IS_VALID_CODE_PTR(ObjectDestroyed, OBJECTDESTROYEDPROC));
|
|
|
|
TRACE_OUT(("NewInternet(): Creating a new Internet."));
|
|
|
|
return((PIUnknown)(PIShellPropSheetExt)new(Internet(ObjectDestroyed)));
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
PRIVATE_CODE BOOL IsValidPCClassFactory(PCClassFactory pccf)
|
|
{
|
|
return(IS_VALID_READ_PTR(pccf, CClassFactory) &&
|
|
IS_VALID_CODE_PTR(pccf->m_NewObject, NEWOBJECTPROC) &&
|
|
IS_VALID_STRUCT_PTR((PCRefCount)pccf, CRefCount) &&
|
|
IS_VALID_INTERFACE_PTR((PCIClassFactory)pccf, IClassFactory));
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/****************************** Public Functions *****************************/
|
|
|
|
|
|
PUBLIC_CODE ULONG DLLAddRef(void)
|
|
{
|
|
ULONG ulcRef;
|
|
|
|
ASSERT(s_ulcDLLRef < ULONG_MAX);
|
|
|
|
ulcRef = ++s_ulcDLLRef;
|
|
|
|
TRACE_OUT(("DLLAddRef(): DLL reference count is now %lu.",
|
|
ulcRef));
|
|
|
|
return(ulcRef);
|
|
}
|
|
|
|
|
|
PUBLIC_CODE ULONG DLLRelease(void)
|
|
{
|
|
ULONG ulcRef;
|
|
|
|
if (EVAL(s_ulcDLLRef > 0))
|
|
s_ulcDLLRef--;
|
|
|
|
ulcRef = s_ulcDLLRef;
|
|
|
|
TRACE_OUT(("DLLRelease(): DLL reference count is now %lu.",
|
|
ulcRef));
|
|
|
|
return(ulcRef);
|
|
}
|
|
|
|
|
|
PUBLIC_CODE PULONG GetDLLRefCountPtr(void)
|
|
{
|
|
return(&s_ulcDLLRef);
|
|
}
|
|
|
|
|
|
/********************************** Methods **********************************/
|
|
|
|
|
|
ClassFactory::ClassFactory(NEWOBJECTPROC NewObject,
|
|
OBJECTDESTROYEDPROC ObjectDestroyed) :
|
|
RefCount(ObjectDestroyed)
|
|
{
|
|
DebugEntry(ClassFactory::ClassFactory);
|
|
|
|
// Don't validate this until after construction.
|
|
|
|
ASSERT(IS_VALID_CODE_PTR(NewObject, NEWOBJECTPROC));
|
|
|
|
m_NewObject = NewObject;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
|
|
DebugExitVOID(ClassFactory::ClassFactory);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
ClassFactory::~ClassFactory(void)
|
|
{
|
|
DebugEntry(ClassFactory::~ClassFactory);
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
|
|
m_NewObject = NULL;
|
|
|
|
// Don't validate this after destruction.
|
|
|
|
DebugExitVOID(ClassFactory::~ClassFactory);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
ULONG STDMETHODCALLTYPE ClassFactory::AddRef(void)
|
|
{
|
|
ULONG ulcRef;
|
|
|
|
DebugEntry(ClassFactory::AddRef);
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
|
|
ulcRef = RefCount::AddRef();
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
|
|
DebugExitULONG(ClassFactory::AddRef, ulcRef);
|
|
|
|
return(ulcRef);
|
|
}
|
|
|
|
|
|
ULONG STDMETHODCALLTYPE ClassFactory::Release(void)
|
|
{
|
|
ULONG ulcRef;
|
|
|
|
DebugEntry(ClassFactory::Release);
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
|
|
ulcRef = RefCount::Release();
|
|
|
|
DebugExitULONG(ClassFactory::Release, ulcRef);
|
|
|
|
return(ulcRef);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE ClassFactory::QueryInterface(REFIID riid,
|
|
PVOID *ppvObject)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugEntry(ClassFactory::QueryInterface);
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
ASSERT(IsValidREFIID(riid));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppvObject, PVOID));
|
|
|
|
if (riid == IID_IClassFactory)
|
|
{
|
|
*ppvObject = (PIClassFactory)this;
|
|
ASSERT(IS_VALID_INTERFACE_PTR((PIClassFactory)*ppvObject, IClassFactory));
|
|
TRACE_OUT(("ClassFactory::QueryInterface(): Returning IClassFactory."));
|
|
}
|
|
else if (riid == IID_IUnknown)
|
|
{
|
|
*ppvObject = (PIUnknown)this;
|
|
ASSERT(IS_VALID_INTERFACE_PTR((PIUnknown)*ppvObject, IUnknown));
|
|
TRACE_OUT(("ClassFactory::QueryInterface(): Returning IUnknown."));
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = NULL;
|
|
hr = E_NOINTERFACE;
|
|
TRACE_OUT(("ClassFactory::QueryInterface(): Called on unknown interface."));
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
AddRef();
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
ASSERT(FAILED(hr) ||
|
|
IS_VALID_INTERFACE_PTR(*ppvObject, INTERFACE));
|
|
|
|
DebugExitHRESULT(ClassFactory::QueryInterface, hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE ClassFactory::CreateInstance(PIUnknown piunkOuter,
|
|
REFIID riid,
|
|
PVOID *ppvObject)
|
|
{
|
|
HRESULT hr;
|
|
|
|
DebugEntry(ClassFactory::CreateInstance);
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
ASSERT(! piunkOuter ||
|
|
IS_VALID_INTERFACE_PTR(piunkOuter, IUnknown));
|
|
ASSERT(IsValidREFIID(riid));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppvObject, PVOID));
|
|
|
|
*ppvObject = NULL;
|
|
|
|
if (! piunkOuter)
|
|
{
|
|
PIUnknown piunk;
|
|
|
|
piunk = (*m_NewObject)(&DLLObjectDestroyed);
|
|
|
|
if (piunk)
|
|
{
|
|
DLLAddRef();
|
|
|
|
hr = piunk->QueryInterface(riid, ppvObject);
|
|
|
|
// N.b., the Release() method will destroy the object if the
|
|
// QueryInterface() method failed.
|
|
|
|
piunk->Release();
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
hr = CLASS_E_NOAGGREGATION;
|
|
WARNING_OUT(("ClassFactory::CreateInstance(): Aggregation not supported."));
|
|
}
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
ASSERT(FAILED(hr) ||
|
|
IS_VALID_INTERFACE_PTR(*ppvObject, INTERFACE));
|
|
|
|
DebugExitHRESULT(ClassFactory::CreateInstance, hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE ClassFactory::LockServer(BOOL bLock)
|
|
{
|
|
HRESULT hr;
|
|
|
|
DebugEntry(ClassFactory::LockServer);
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
|
|
// bLock may be any value.
|
|
|
|
if (bLock)
|
|
DLLAddRef();
|
|
else
|
|
DLLRelease();
|
|
|
|
hr = S_OK;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
|
|
DebugExitHRESULT(ClassFactory::LockServer, hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
/***************************** Exported Functions ****************************/
|
|
|
|
|
|
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, PVOID *ppvObject)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
NEWOBJECTPROC NewObject;
|
|
|
|
DebugEntry(DllGetClassObject);
|
|
|
|
ASSERT(IsValidREFCLSID(rclsid));
|
|
ASSERT(IsValidREFIID(riid));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppvObject, PVOID));
|
|
|
|
*ppvObject = NULL;
|
|
|
|
hr = GetClassConstructor(rclsid, &NewObject);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
if (riid == IID_IUnknown ||
|
|
riid == IID_IClassFactory)
|
|
{
|
|
PClassFactory pcf;
|
|
|
|
pcf = new(ClassFactory(NewObject, &DLLObjectDestroyed));
|
|
|
|
if (pcf)
|
|
{
|
|
if (riid == IID_IClassFactory)
|
|
{
|
|
*ppvObject = (PIClassFactory)pcf;
|
|
ASSERT(IS_VALID_INTERFACE_PTR((PIClassFactory)*ppvObject, IClassFactory));
|
|
TRACE_OUT(("DllGetClassObject(): Returning IClassFactory."));
|
|
}
|
|
else
|
|
{
|
|
ASSERT(riid == IID_IUnknown);
|
|
*ppvObject = (PIUnknown)pcf;
|
|
ASSERT(IS_VALID_INTERFACE_PTR((PIUnknown)*ppvObject, IUnknown));
|
|
TRACE_OUT(("DllGetClassObject(): Returning IUnknown."));
|
|
}
|
|
|
|
DLLAddRef();
|
|
hr = S_OK;
|
|
|
|
TRACE_OUT(("DllGetClassObject(): Created a new class factory."));
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("DllGetClassObject(): Called on unknown interface."));
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
}
|
|
else
|
|
WARNING_OUT(("DllGetClassObject(): Called on unknown class."));
|
|
|
|
ASSERT(FAILED(hr) ||
|
|
IS_VALID_INTERFACE_PTR(*ppvObject, INTERFACE));
|
|
|
|
DebugExitHRESULT(DllGetClassObject, hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
STDAPI DllCanUnloadNow(void)
|
|
{
|
|
HRESULT hr;
|
|
|
|
DebugEntry(DllCanUnloadNow);
|
|
|
|
hr = (s_ulcDLLRef > 0) ? S_FALSE : S_OK;
|
|
|
|
if (hr == S_OK)
|
|
hr = InternetCPLCanUnloadNow();
|
|
|
|
TRACE_OUT(("DllCanUnloadNow(): DLL reference count is %lu.",
|
|
s_ulcDLLRef));
|
|
|
|
DebugExitHRESULT(DllCanUnloadNow, hr);
|
|
|
|
return(hr);
|
|
}
|
|
|