gecko-dev/cmd/winfe/apiapi.cpp
1998-03-28 02:44:41 +00:00

611 lines
15 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "stdafx.h"
#include "apiapi.h" // get all global interfaces
class CAPIList {
protected:
CAPIList * m_pNext;
CAPIList * m_pPrevious;
void * m_pData;
public:
CAPIList(void * pData = NULL);
~CAPIList();
long elements(void);
CAPIList * Add(void * element);
CAPIList * Remove(void * element);
void * GetAt (int element);
inline CAPIList * GetNext(void) {
return m_pNext;
}
inline CAPIList * GetPrevious(void) {
return m_pPrevious;
}
inline CAPIList * SetNext(CAPIList * pElement) {
CAPIList * pNext = m_pNext;
m_pNext = pElement;
return pNext;
}
inline CAPIList * SetPrevious(CAPIList * pElement) {
CAPIList * pPrevious = m_pPrevious;
m_pPrevious = pElement;
return pPrevious;
}
inline void * GetData(void) { return m_pData; }
};
CAPIList::CAPIList(void * pData)
{
m_pNext = NULL;
m_pPrevious = NULL;
SetNext(this);
SetPrevious(this);
m_pData = pData;
}
CAPIList::~CAPIList()
{
assert(m_pNext);
assert(m_pPrevious);
GetPrevious()->SetNext(GetNext());
GetNext()->SetPrevious(GetPrevious());
}
CAPIList * CAPIList::Add(void * element)
{
CAPIList * pNode = new CAPIList(element);
CAPIList * pOld = SetNext(pNode);
pNode->SetNext(pOld);
pOld->SetPrevious(pNode);
pNode->SetPrevious(this);
return pNode;
}
long CAPIList::elements(void)
{
CAPIList * pNode = this;
long lcount = 0;
do {
lcount++;
pNode = pNode->GetNext();
} while (pNode != this);
return lcount;
}
CAPIList * CAPIList::Remove(void * element)
{
BOOL found = FALSE;
CAPIList * pNode = this;
do {
if (pNode->GetData() == element) {
found = TRUE;
break;
}
pNode = pNode->GetNext();
} while (pNode != this);
if (found) {
if (GetNext() == this) {
delete this;
return NULL;
}
else {
CAPIList * ptr = pNode->GetPrevious();
delete pNode;
return ptr;
}
}
return this;
}
void * CAPIList::GetAt ( int element )
{
CAPIList * pNode = this;
do {
if (!element)
return pNode->GetData();
element--;
pNode = pNode->GetNext();
} while (pNode != this);
return NULL;
}
// the API repository implements the APIAPI interface and maintains
// the list of APIs, their IDs, and reference counts.
class ApiEntry {
protected:
LPUNKNOWN m_pUnk;
APISIGNATURE m_apiSig;
public:
ApiEntry(LPUNKNOWN pUnk = NULL, APISIGNATURE apiSig = NULL ) {
m_pUnk =pUnk;
m_apiSig = apiSig;
}
inline LPUNKNOWN GetUnk() { return m_pUnk; }
inline APISIGNATURE GetSig() { return m_apiSig; }
inline void SetSig(APISIGNATURE apiSig) { m_apiSig = apiSig; }
inline void SetUnk(LPUNKNOWN pUnk) { m_pUnk = pUnk; }
};
class ClassFactory { // class factory entries
public:
LPCLASSFACTORY m_pClassFactory; // class instance creation factory
char * m_pszClassName; // name of class
BOOL m_bIsLoaded; // is class factory loaded?
char * m_pszModuleName; // module containing class factory
HMODULE m_hModule; // factory dll instance
CAPIList * m_ApiList; // list of api instances
ClassFactory (char * pszClassName, LPCLASSFACTORY pFactory, char * pszModule = 0 );
~ClassFactory();
LPUNKNOWN CreateClassInstance(LPUNKNOWN pUnkOuter, APISIGNATURE apiSig = NULL);
LPUNKNOWN GetFirst(void);
LPUNKNOWN GetNext(LPUNKNOWN);
void Insert(LPUNKNOWN pUnk,APISIGNATURE apiSig = NULL);
void Remove(LPUNKNOWN);
LPUNKNOWN LocateBySignature(APISIGNATURE);
BOOL AttemptToLoad(void);
};
void ClassFactory::Insert(
LPUNKNOWN pUnk,
APISIGNATURE apiSig
)
{
if (!m_ApiList) {
m_ApiList = new CAPIList((void*)(new ApiEntry(pUnk,apiSig)));
}
else {
m_ApiList = m_ApiList->Add((void*)(new ApiEntry(pUnk,apiSig)));
}
}
void ClassFactory::Remove(LPUNKNOWN pUnk)
{
if (m_ApiList) {
ApiEntry * pEntry;
for (int i = 0; i < m_ApiList->elements(); i++) {
pEntry = (ApiEntry *)m_ApiList->GetAt(i);
assert(pEntry);
if (pEntry->GetUnk() == pUnk) {
m_ApiList = m_ApiList->Remove((void*)pEntry);
delete pEntry;
return;
}
}
}
}
LPUNKNOWN ClassFactory::GetFirst(void)
{
if (!m_ApiList)
return 0;
if (!m_ApiList->elements())
return 0;
return ((ApiEntry *)(m_ApiList->GetAt(0)))->GetUnk();
}
LPUNKNOWN ClassFactory::GetNext(LPUNKNOWN pUnk)
{
if (m_ApiList) {
for (int i = 0; i < m_ApiList->elements() - 1; i++)
if (((ApiEntry*)m_ApiList->GetAt(i))->GetUnk() == (void*)pUnk)
return ((ApiEntry*)m_ApiList->GetAt(i+1))->GetUnk();
}
return 0;
}
LPUNKNOWN ClassFactory::LocateBySignature(APISIGNATURE apiSig)
{
if (!apiSig || !m_ApiList)
return NULL;
ApiEntry * pEntry;
for (int i = 0; i < m_ApiList->elements(); i++) {
pEntry = (ApiEntry*)m_ApiList->GetAt(i);
if (APISIGCMP(pEntry->GetSig(),apiSig))
return pEntry->GetUnk();
}
return NULL;
}
ClassFactory::ClassFactory(char * pszClassName, LPCLASSFACTORY pFactory, char * pszModule)
{
assert(pszClassName);
m_pClassFactory = pFactory;
m_pszClassName = strdup(pszClassName);
m_hModule = NULL;
m_ApiList = NULL;
if (pszModule != 0) {
m_pszModuleName = strdup(pszModule);
m_bIsLoaded = FALSE;
}
else {
m_bIsLoaded = TRUE;
m_pszModuleName = NULL;
}
}
ClassFactory::~ClassFactory()
{
if (m_pszClassName != NULL)
free (m_pszClassName);
if (m_pszModuleName != NULL)
free (m_pszModuleName);
if (m_hModule != NULL)
FreeLibrary(m_hModule);
int elements;
elements = m_ApiList ? (int)m_ApiList->elements( ): 0;
while ( elements ) {
ApiEntry * pEntry = (ApiEntry *)m_ApiList->GetAt(elements - 1);
assert(pEntry);
LPUNKNOWN entry = (LPUNKNOWN)pEntry->GetUnk();
// FIXME release objects here!
if (entry)
while (entry->Release())
;
delete pEntry;
elements--;
}
}
LPUNKNOWN ClassFactory::CreateClassInstance(
LPUNKNOWN pUnkOuter,
APISIGNATURE apiSig)
{
assert(m_pClassFactory);
LPUNKNOWN pUnknown;
if (m_pClassFactory->CreateInstance(
pUnkOuter, IID_IUnknown, (LPVOID*)&pUnknown) == NOERROR)
Insert(pUnknown,apiSig);
return pUnknown;
}
class ClassRepository : public CGenericFactory,
public IApiapi {
protected:
ULONG m_ulRefCount;
CAPIList * m_ClassList;
// lookup attempts to find an API entry based on id
ClassFactory * Lookup (char * pszClassName);
ClassFactory * GetFirst(void);
ClassFactory * GetNext(ClassFactory *);
void Remove(ClassFactory*);
public:
ClassRepository ( );
~ClassRepository ( );
// IClassFactory Interface
STDMETHODIMP CreateInstance(LPUNKNOWN,REFIID,LPVOID*);
// IApiapi interface
LPUNKNOWN GetFirstInstance(APICLASS lpszClassName);
LPUNKNOWN GetNextInstance(APICLASS lpszClassName, LPUNKNOWN pUnk );
void * GetFirstApiInstance( REFIID refiid, LPUNKNOWN * ppUnk);
int RemoveInstance( LPUNKNOWN pUnk );
LPUNKNOWN CreateClassInstance (
APICLASS lpszClassName,LPUNKNOWN pUnkOuter,APISIGNATURE apiSig);
int RegisterClassFactory (
APICLASS lpszClassName, LPCLASSFACTORY pClassFactory, char * szModuleName = 0);
};
ClassRepository::ClassRepository ( )
{
m_ClassList = NULL;
RegisterClassFactory(APICLASS_APIAPI,(LPCLASSFACTORY)this);
}
ClassRepository::~ClassRepository ( )
{
if (m_ClassList) {
int elements = (int)m_ClassList->elements( );
while ( elements ) {
elements--;
}
}
}
STDMETHODIMP ClassRepository::CreateInstance(
LPUNKNOWN pUnkOuter,REFIID refiid, LPVOID * ppvObj)
{
*ppvObj = NULL;
ClassRepository * pRepository = new ClassRepository;
return pRepository->QueryInterface(refiid,ppvObj);
}
int ClassRepository::RemoveInstance( LPUNKNOWN pUnk )
{
if (m_ClassList) {
int elements = (int) m_ClassList->elements();
int i;
for ( i = 0; i < elements; i++ ) {
ClassFactory * entry = (ClassFactory *)m_ClassList->GetAt(i);
entry->Remove(pUnk);
}
}
return 0;
}
ClassFactory * ClassRepository::GetFirst(void)
{
if (!m_ClassList)
return 0;
if (!m_ClassList->elements())
return 0;
return (ClassFactory *)m_ClassList->GetAt(0);
}
ClassFactory * ClassRepository::GetNext(ClassFactory * pFactory)
{
if (m_ClassList) {
for (int i = 0; i < m_ClassList->elements() - 1; i++)
if (m_ClassList->GetAt(i) == (void*)pFactory)
return (ClassFactory *)m_ClassList->GetAt(i+1);
}
return 0;
}
void ClassRepository::Remove(ClassFactory * pFactory)
{
if (m_ClassList)
m_ClassList = m_ClassList->Remove((void*)pFactory);
}
LPUNKNOWN ClassRepository::CreateClassInstance(
APICLASS lpszClassName,
LPUNKNOWN pUnkOuter,
APISIGNATURE apiSig )
{
ClassFactory * pFactory = Lookup(lpszClassName);
if (pFactory) {
if (apiSig) {
LPUNKNOWN pUnk;
if ((pUnk = pFactory->LocateBySignature(apiSig)) != NULL)
return pUnk;
}
return pFactory->CreateClassInstance(pUnkOuter,apiSig);
}
return NULL;
}
BOOL ClassFactory::AttemptToLoad(void)
{
if ((!m_pszModuleName) || m_bIsLoaded)
return FALSE;
// attempt to load the interface module (DLL)
m_hModule = LoadLibrary (m_pszModuleName);
if (m_hModule > (HMODULE)32) {
// The class factory initializer is the first routine in the DLL.
APIBOOTER fpApiInitialize =
(APIBOOTER)GetProcAddress(m_hModule,MAKEINTRESOURCE(1));
// if we got a valid initializer, then call it with the
// class name. This was the module can initialize one at
// a time if it likes.
if (fpApiInitialize != NULL ) {
m_bIsLoaded = TRUE;
if ((*fpApiInitialize)(m_pszClassName))
return TRUE;
}
else
m_bIsLoaded = FALSE;
}
else {
// couldn't load the module
char szMessage[1024];
sprintf ( szMessage, "Cannot load module: %.800s\nClass factory %800s",
m_pszModuleName, m_pszClassName);
MessageBox ( 0, szMessage, "Interface Error", MB_OK | MB_ICONEXCLAMATION );
}
return FALSE;
}
ClassFactory * ClassRepository::Lookup ( char * pszClassName )
{
// get the number of stored elements
if (m_ClassList) {
int elements = (int) m_ClassList->elements();
int i;
// look up the api
for ( i = 0; i < elements; i++ ) {
ClassFactory * entry = (ClassFactory *)m_ClassList->GetAt(i);
if (!stricmp(entry->m_pszClassName, pszClassName)) {
if (!entry->m_bIsLoaded)
if (entry->AttemptToLoad())
return entry;
else
return 0;
return entry;
}
}
}
return 0;
}
int ClassRepository::RegisterClassFactory (
char * pszClassName,
LPCLASSFACTORY pClassFactory,
char * szModuleName )
{
ClassFactory * pClassEntry;
if ((pClassEntry = Lookup (pszClassName)) != 0) {
pClassEntry->m_pClassFactory = pClassFactory;
return 1;
}
else {
pClassEntry = new ClassFactory ( pszClassName, pClassFactory, szModuleName);
if (!m_ClassList)
m_ClassList = new CAPIList((void*)pClassEntry);
else
m_ClassList = m_ClassList->Add ((void*)pClassEntry );
}
return 0;
}
void * ClassRepository::GetFirstApiInstance( REFIID refiid, LPUNKNOWN * ppUnk)
{
void * pSomeInterface;
*ppUnk = 0;
ClassFactory * pClass = GetFirst();
while (pClass) {
LPUNKNOWN pUnk = pClass->GetFirst();
while (pUnk) {
if (pUnk->QueryInterface(refiid,(LPVOID*)&pSomeInterface) == NOERROR) {
*ppUnk = pUnk;
return pSomeInterface;
}
pUnk = pClass->GetNext(pUnk);
}
pClass = GetNext(pClass);
}
return NULL;
}
// function looks up an API by id and returns a void pointer which in
// turn can be cast to the requested interface type. This is done
// for you by the Api<id,interf> template.
LPUNKNOWN ClassRepository::GetFirstInstance ( char * pszClassName )
{
if (m_ClassList) {
for (int i = 0; i < m_ClassList->elements(); i++) {
ClassFactory * pClassFactory = (ClassFactory *)m_ClassList->GetAt(i);
if (!stricmp(pClassFactory->m_pszClassName, pszClassName)) {
if (pClassFactory->m_ApiList)
return ((ApiEntry*)pClassFactory->m_ApiList->GetAt(0))->GetUnk();
return NULL;
}
}
}
return NULL;
}
LPUNKNOWN ClassRepository::GetNextInstance ( char * pszClassName, LPUNKNOWN pUnk )
{
if (m_ClassList) {
for (int i = 0; i < m_ClassList->elements(); i++) {
ClassFactory * pClassFactory = (ClassFactory *)m_ClassList->GetAt(i);
if (!stricmp(pClassFactory->m_pszClassName, pszClassName)) {
CAPIList * pList = pClassFactory->m_ApiList;
if (pList)
for (int j = 0; j<pList->elements()-1; j++)
if (((ApiEntry*)pList->GetAt(j))->GetUnk() == pUnk)
return ((ApiEntry*) pClassFactory->m_ApiList->GetAt(j+1))->GetUnk();
return NULL;
}
}
}
return NULL;
}
// The apiapi object MUST be constructed first, this pragma ensures that
// the static constructor will occur before any other static construction
// happens.
#pragma warning( disable : 4074 )
#pragma init_seg(compiler)
static ClassRepository classRepository;
// global function gets the ApiApi from the static repository
// From here, all registered APIs can be retrieved and set
API_PUBLIC(LPAPIAPI) GetAPIAPI()
{
return (LPAPIAPI) &classRepository;
}
// Generic Objects
// Generic Factory
STDMETHODIMP CGenericFactory::QueryInterface(REFIID refiid, LPVOID * ppv)
{
*ppv = NULL;
if (IsEqualIID(refiid,IID_IUnknown))
*ppv = (LPUNKNOWN) this;
else if (IsEqualIID(refiid,IID_IClassFactory))
*ppv = (LPCLASSFACTORY) this;
if (*ppv != NULL) {
AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CGenericFactory::AddRef(void)
{
return ++m_ulRefCount;
}
STDMETHODIMP_(ULONG) CGenericFactory::Release(void)
{
ULONG ulRef;
ulRef = --m_ulRefCount;
if (m_ulRefCount == 0) ;
// delete this;
return ulRef;
}
STDMETHODIMP CGenericFactory::CreateInstance(
LPUNKNOWN pUnkOuter,REFIID refiid, LPVOID * ppvObj)
{
return NULL;
// User Implemented
}
STDMETHODIMP CGenericFactory::LockServer(BOOL fLock)
{
return NOERROR;
}
// Generic Object
STDMETHODIMP CGenericObject::QueryInterface(REFIID refiid, LPVOID * ppv)
{
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CGenericObject::AddRef(void)
{
return ++m_ulRefCount;
}
STDMETHODIMP_(ULONG) CGenericObject::Release(void)
{
ULONG ulRef;
ulRef = --m_ulRefCount;
if (m_ulRefCount == 0) {
classRepository.RemoveInstance(this);
delete this;
}
return ulRef;
}