mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
527 lines
11 KiB
527 lines
11 KiB
//*********************************************************************
|
|
//* Microsoft Windows **
|
|
//* Copyright(c) Microsoft Corp., 1995 **
|
|
//*********************************************************************
|
|
|
|
//
|
|
// CLSFACT.CPP - Implementation of IClassFactory
|
|
//
|
|
|
|
// HISTORY:
|
|
//
|
|
// 10/11/95 jeremys Created.
|
|
//
|
|
|
|
|
|
/* Headers
|
|
**********/
|
|
|
|
#include "project.hpp" // project header file
|
|
#pragma hdrstop
|
|
|
|
#include <initguid.h> // COM header file for GUID declaration
|
|
#include "clsfact.h" // prototypes for exported COM functions
|
|
|
|
#include "htmlview.hpp" // header file for HTML viewer class
|
|
#include "htmlguid.h" // contains GUID for HTML viewer
|
|
|
|
|
|
/* Types
|
|
********/
|
|
|
|
// callback function used by ClassFactory::ClassFactory()
|
|
|
|
typedef PIUnknown (*NEWOBJECTPROC)();
|
|
DECLARE_STANDARD_TYPES(NEWOBJECTPROC);
|
|
|
|
class ClassFactory;
|
|
// description of class supported by DllGetClassObject()
|
|
|
|
typedef struct classconstructor
|
|
{
|
|
PCCLSID pcclsid;
|
|
|
|
NEWOBJECTPROC NewObject;
|
|
|
|
ClassFactory *pcf; // cached class factory
|
|
}
|
|
CLASSCONSTRUCTOR;
|
|
DECLARE_STANDARD_TYPES(CLASSCONSTRUCTOR);
|
|
|
|
|
|
/* Classes
|
|
**********/
|
|
|
|
// object class factory
|
|
|
|
class ClassFactory : public IClassFactory
|
|
{
|
|
private:
|
|
PCLASSCONSTRUCTOR m_pcc;
|
|
int m_cRef;
|
|
|
|
public:
|
|
ClassFactory(PCLASSCONSTRUCTOR pcc);
|
|
~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 NewHTMLViewer();
|
|
|
|
/* Module Constants
|
|
*******************/
|
|
|
|
// array of CLSID's for objects this DLL can create, and the corresponding
|
|
// "constructor". Right now this is an array of only one element, but
|
|
// it's likely we'll want to have other objects live in this DLL in the future.
|
|
PRIVATE_DATA CLASSCONSTRUCTOR s_cclscnstr[] =
|
|
{
|
|
{ &CLSID_HTMLViewer, &NewHTMLViewer, NULL }
|
|
};
|
|
|
|
|
|
/* 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,
|
|
PCLASSCONSTRUCTOR *ppcc)
|
|
{
|
|
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
|
|
int u;
|
|
|
|
ASSERT(IsValidREFCLSID(rclsid));
|
|
|
|
*ppcc = NULL;
|
|
|
|
for (u = ARRAY_ELEMENTS(s_cclscnstr)- 1; u >= 0 ; u--)
|
|
{
|
|
if (rclsid == *(s_cclscnstr[u].pcclsid))
|
|
{
|
|
*ppcc = &s_cclscnstr[u];
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT((hr == S_OK &&
|
|
IS_VALID_CODE_PTR(*(*ppcc)->NewObject, NEWOBJECTPROC)) ||
|
|
(hr == CLASS_E_CLASSNOTAVAILABLE &&
|
|
*ppcc == NULL));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
PRIVATE_CODE PIUnknown NewHTMLViewer()
|
|
{
|
|
|
|
TRACE_OUT(("NewInternet(): Creating a new Internet."));
|
|
|
|
// construct a new HTML viewer object
|
|
HTMLView * pHTMLView = new (HTMLView);
|
|
|
|
if (pHTMLView) {
|
|
// initialize it
|
|
HRESULT hr = pHTMLView->Initialize();
|
|
|
|
if (hr != S_OK) {
|
|
// if it fails to initialize, then destroy it
|
|
delete pHTMLView;
|
|
pHTMLView = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
return((PIUnknown) pHTMLView);
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
PRIVATE_CODE BOOL IsValidPCClassFactory(PCClassFactory pccf)
|
|
{
|
|
return(IS_VALID_READ_PTR(pccf, CClassFactory) &&
|
|
IS_VALID_CODE_PTR(pccf->m_pcc->NewObject, NEWOBJECTPROC) &&
|
|
IS_VALID_INTERFACE_PTR((PCIClassFactory)pccf, IClassFactory));
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/****************************** Public Functions *****************************/
|
|
|
|
extern "C" {
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
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(PCLASSCONSTRUCTOR pcc) :
|
|
m_cRef(0)
|
|
{
|
|
//DebugEntry(ClassFactory::ClassFactory);
|
|
|
|
// this is a root object
|
|
DLLAddRef();
|
|
|
|
// Don't validate this until after construction.
|
|
|
|
ASSERT(IS_VALID_CODE_PTR(pcc->NewObject, NEWOBJECTPROC));
|
|
|
|
m_pcc = pcc;
|
|
|
|
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_pcc->pcf = NULL;
|
|
m_pcc = NULL;
|
|
DLLRelease();
|
|
|
|
//Don't validate this after destruction.
|
|
|
|
//DebugExitVOID(ClassFactory::~ClassFactory);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
ULONG STDMETHODCALLTYPE ClassFactory::AddRef(void)
|
|
{
|
|
|
|
// DebugEntry(ClassFactory::AddRef);
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
ENTERCRITICAL();
|
|
m_cRef++;
|
|
LEAVECRITICAL();
|
|
|
|
// DebugExitULONG(ClassFactory::AddRef, ulcRef);
|
|
|
|
return(m_cRef);
|
|
}
|
|
|
|
|
|
ULONG STDMETHODCALLTYPE ClassFactory::Release(void)
|
|
{
|
|
ULONG ulcRef;
|
|
|
|
//DebugEntry(ClassFactory::Release);
|
|
|
|
ENTERCRITICAL();
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(this, CClassFactory));
|
|
|
|
|
|
ulcRef = --m_cRef;
|
|
|
|
if (0 == ulcRef) {
|
|
delete this;
|
|
}
|
|
|
|
LEAVECRITICAL();
|
|
//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_pcc->NewObject)();
|
|
|
|
if (piunk)
|
|
{
|
|
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
|
|
{
|
|
// we don't support aggregation
|
|
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;
|
|
PCLASSCONSTRUCTOR pcc;
|
|
|
|
// DebugEntry(DllGetClassObject);
|
|
|
|
ASSERT(IsValidREFCLSID(rclsid));
|
|
ASSERT(IsValidREFIID(riid));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppvObject, PVOID));
|
|
|
|
*ppvObject = NULL;
|
|
|
|
hr = GetClassConstructor(rclsid, &pcc);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
if (riid == IID_IUnknown ||
|
|
riid == IID_IClassFactory)
|
|
{
|
|
PClassFactory pcf;
|
|
|
|
ENTERCRITICAL();
|
|
if (pcc->pcf) {
|
|
pcf = pcc->pcf;
|
|
} else {
|
|
pcf = new(ClassFactory(pcc));
|
|
pcc->pcf = pcf;
|
|
}
|
|
if (pcf)
|
|
pcf->AddRef();
|
|
LEAVECRITICAL();
|
|
|
|
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."));
|
|
}
|
|
|
|
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;
|
|
|
|
TRACE_OUT(("DllCanUnloadNow(): DLL reference count is %lu.",
|
|
s_ulcDLLRef));
|
|
|
|
// DebugExitHRESULT(DllCanUnloadNow, hr);
|
|
|
|
return(hr);
|
|
}
|
|
|