home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / apiapi.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  15.6 KB  |  611 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "stdafx.h"
  20. #include "apiapi.h"        // get all global interfaces
  21.  
  22. class CAPIList {
  23. protected:
  24.     CAPIList * m_pNext;
  25.     CAPIList * m_pPrevious;
  26.     void  * m_pData;
  27. public:
  28.     CAPIList(void * pData = NULL);
  29.     ~CAPIList();
  30.     long elements(void);
  31.     CAPIList * Add(void * element);
  32.     CAPIList * Remove(void * element);
  33.     void * GetAt (int element);
  34.     inline CAPIList * GetNext(void) {
  35.       return m_pNext; 
  36.       }
  37.     inline CAPIList * GetPrevious(void) { 
  38.       return m_pPrevious; 
  39.       }
  40.     inline CAPIList * SetNext(CAPIList * pElement) {
  41.         CAPIList * pNext = m_pNext;
  42.         m_pNext = pElement;
  43.         return pNext;
  44.         }
  45.     inline CAPIList * SetPrevious(CAPIList * pElement) {
  46.         CAPIList * pPrevious = m_pPrevious;
  47.         m_pPrevious = pElement;
  48.         return pPrevious;
  49.         }
  50.     inline void * GetData(void) { return m_pData; }
  51. };
  52.  
  53. CAPIList::CAPIList(void * pData)
  54. {
  55.     m_pNext = NULL;
  56.     m_pPrevious = NULL;
  57.     SetNext(this);
  58.     SetPrevious(this);
  59.     m_pData = pData;
  60. }
  61.  
  62. CAPIList::~CAPIList()
  63. {
  64.     assert(m_pNext);
  65.     assert(m_pPrevious);
  66.     GetPrevious()->SetNext(GetNext());
  67.     GetNext()->SetPrevious(GetPrevious());
  68. }
  69.  
  70. CAPIList * CAPIList::Add(void * element)
  71. {
  72.     CAPIList * pNode = new CAPIList(element);
  73.     CAPIList * pOld = SetNext(pNode);
  74.     pNode->SetNext(pOld);
  75.     pOld->SetPrevious(pNode);
  76.     pNode->SetPrevious(this);
  77.     return pNode;
  78. }
  79.  
  80. long CAPIList::elements(void)
  81. {
  82.     CAPIList * pNode = this;
  83.     long lcount = 0;
  84.     do {
  85.         lcount++;
  86.         pNode = pNode->GetNext();
  87.     } while (pNode != this);
  88.     return lcount;
  89. }
  90.  
  91. CAPIList * CAPIList::Remove(void * element)
  92. {
  93.     BOOL found = FALSE;
  94.     CAPIList * pNode = this;
  95.     do {
  96.         if (pNode->GetData() == element) {
  97.             found = TRUE;
  98.             break;
  99.         }
  100.         pNode = pNode->GetNext();    
  101.     } while (pNode != this);
  102.  
  103.     if (found) {
  104.         if (GetNext() == this) {
  105.             delete this;
  106.             return NULL;
  107.         }
  108.         else {
  109.             CAPIList * ptr = pNode->GetPrevious();
  110.             delete pNode;
  111.             return ptr;
  112.         }
  113.     }                    
  114.     return this;
  115. }
  116.  
  117. void * CAPIList::GetAt ( int element )
  118. {
  119.     CAPIList * pNode = this;
  120.     do {
  121.         if (!element)
  122.             return pNode->GetData();
  123.         element--;
  124.         pNode = pNode->GetNext();
  125.     } while (pNode != this);
  126.     return NULL;
  127. }
  128.  
  129. // the API repository implements the APIAPI interface and maintains
  130. // the list of APIs, their IDs, and reference counts.
  131.  
  132. class ApiEntry {
  133. protected:
  134.     LPUNKNOWN m_pUnk;
  135.     APISIGNATURE m_apiSig;
  136. public:
  137.     ApiEntry(LPUNKNOWN pUnk = NULL, APISIGNATURE apiSig = NULL ) {
  138.         m_pUnk =pUnk;
  139.         m_apiSig = apiSig;
  140.     }
  141.     inline LPUNKNOWN GetUnk() { return m_pUnk; }
  142.     inline APISIGNATURE GetSig() { return m_apiSig; }
  143.     inline void SetSig(APISIGNATURE apiSig) { m_apiSig = apiSig; }
  144.     inline void SetUnk(LPUNKNOWN pUnk) { m_pUnk = pUnk; }
  145. };
  146.  
  147. class ClassFactory {                        // class factory entries
  148. public:
  149.    LPCLASSFACTORY    m_pClassFactory;    // class instance creation factory
  150.    char * m_pszClassName;                // name of class
  151.    BOOL m_bIsLoaded;                      // is class factory loaded?
  152.    char * m_pszModuleName;                // module containing class factory
  153.    HMODULE m_hModule;                    // factory dll instance
  154.    CAPIList  * m_ApiList;                     // list of api instances
  155.  
  156.     ClassFactory (char * pszClassName, LPCLASSFACTORY pFactory, char * pszModule = 0 );
  157.    ~ClassFactory();
  158.  
  159.     LPUNKNOWN CreateClassInstance(LPUNKNOWN pUnkOuter, APISIGNATURE apiSig = NULL);      
  160.     LPUNKNOWN GetFirst(void);
  161.     LPUNKNOWN GetNext(LPUNKNOWN);
  162.     void Insert(LPUNKNOWN pUnk,APISIGNATURE apiSig = NULL);
  163.     void Remove(LPUNKNOWN);
  164.     LPUNKNOWN LocateBySignature(APISIGNATURE);
  165.     BOOL AttemptToLoad(void);
  166. };
  167.  
  168. void ClassFactory::Insert(
  169.     LPUNKNOWN pUnk,
  170.     APISIGNATURE apiSig
  171.     )
  172. {
  173.     if (!m_ApiList) {
  174.         m_ApiList = new CAPIList((void*)(new ApiEntry(pUnk,apiSig)));
  175.     }
  176.     else {
  177.         m_ApiList = m_ApiList->Add((void*)(new ApiEntry(pUnk,apiSig)));
  178.     }
  179. }
  180.  
  181. void ClassFactory::Remove(LPUNKNOWN pUnk)
  182. {
  183.     if (m_ApiList) {
  184.         ApiEntry * pEntry;
  185.         for (int i = 0; i < m_ApiList->elements(); i++) {
  186.             pEntry = (ApiEntry *)m_ApiList->GetAt(i);
  187.             assert(pEntry);
  188.             if (pEntry->GetUnk() == pUnk) {
  189.                 m_ApiList = m_ApiList->Remove((void*)pEntry);
  190.                 delete pEntry;
  191.                 return;
  192.             }
  193.         }
  194.     }
  195. }
  196.  
  197. LPUNKNOWN ClassFactory::GetFirst(void)
  198. {
  199.     if (!m_ApiList)
  200.         return 0;
  201.  
  202.     if (!m_ApiList->elements())
  203.         return 0;
  204.  
  205.     return ((ApiEntry *)(m_ApiList->GetAt(0)))->GetUnk();
  206. }
  207.  
  208. LPUNKNOWN ClassFactory::GetNext(LPUNKNOWN pUnk)
  209. {
  210.     if (m_ApiList) {
  211.         for (int i = 0; i < m_ApiList->elements() - 1; i++)
  212.                if (((ApiEntry*)m_ApiList->GetAt(i))->GetUnk() == (void*)pUnk)
  213.                   return ((ApiEntry*)m_ApiList->GetAt(i+1))->GetUnk();
  214.     }
  215.    return 0;
  216. }
  217.  
  218. LPUNKNOWN ClassFactory::LocateBySignature(APISIGNATURE apiSig)
  219. {
  220.     if (!apiSig || !m_ApiList)
  221.         return NULL;
  222.     ApiEntry * pEntry;
  223.     for (int i = 0; i < m_ApiList->elements(); i++) {
  224.         pEntry = (ApiEntry*)m_ApiList->GetAt(i);
  225.         if (APISIGCMP(pEntry->GetSig(),apiSig))
  226.             return pEntry->GetUnk();
  227.     }
  228.     return NULL;
  229. }
  230.  
  231. ClassFactory::ClassFactory(char * pszClassName, LPCLASSFACTORY pFactory, char * pszModule)
  232. {
  233.     assert(pszClassName);
  234.     m_pClassFactory = pFactory;
  235.     m_pszClassName = strdup(pszClassName);
  236.     m_hModule = NULL;
  237.     m_ApiList = NULL;
  238.     if (pszModule != 0) {
  239.            m_pszModuleName = strdup(pszModule);
  240.         m_bIsLoaded = FALSE;
  241.     }
  242.     else {
  243.            m_bIsLoaded = TRUE;
  244.         m_pszModuleName = NULL;
  245.     }
  246. }
  247.  
  248. ClassFactory::~ClassFactory()
  249. {
  250.    if (m_pszClassName != NULL)
  251.         free (m_pszClassName);
  252.    if (m_pszModuleName != NULL)
  253.       free (m_pszModuleName);
  254.    if (m_hModule != NULL)
  255.       FreeLibrary(m_hModule);
  256.  
  257.    int elements;
  258.    elements = m_ApiList ? (int)m_ApiList->elements( ): 0;
  259.    while ( elements ) {
  260.        ApiEntry * pEntry = (ApiEntry *)m_ApiList->GetAt(elements - 1);
  261.        assert(pEntry);
  262.        LPUNKNOWN entry = (LPUNKNOWN)pEntry->GetUnk();
  263.        // FIXME release objects here!
  264.        if (entry)
  265.         while (entry->Release())
  266.              ;
  267.        delete pEntry;
  268.        elements--;
  269.    }
  270. }
  271.  
  272. LPUNKNOWN ClassFactory::CreateClassInstance(
  273.     LPUNKNOWN pUnkOuter, 
  274.     APISIGNATURE apiSig)
  275. {
  276.    assert(m_pClassFactory);
  277.    LPUNKNOWN pUnknown;
  278.    if (m_pClassFactory->CreateInstance( 
  279.        pUnkOuter, IID_IUnknown, (LPVOID*)&pUnknown) == NOERROR)
  280.           Insert(pUnknown,apiSig);
  281.    return pUnknown;
  282. }
  283.  
  284. class ClassRepository    :   public CGenericFactory,
  285.                             public IApiapi {
  286. protected:
  287.     ULONG m_ulRefCount;
  288.     CAPIList * m_ClassList; 
  289.     // lookup attempts to find an API entry based on id
  290.     ClassFactory * Lookup (char * pszClassName);   
  291.     ClassFactory * GetFirst(void);
  292.     ClassFactory * GetNext(ClassFactory *);
  293.     void Remove(ClassFactory*);
  294.    
  295. public:
  296.  
  297.     ClassRepository ( );
  298.     ~ClassRepository ( );
  299.  
  300.     // IClassFactory Interface
  301.     STDMETHODIMP            CreateInstance(LPUNKNOWN,REFIID,LPVOID*);
  302.  
  303.     // IApiapi interface
  304.     LPUNKNOWN GetFirstInstance(APICLASS lpszClassName);
  305.     LPUNKNOWN GetNextInstance(APICLASS lpszClassName, LPUNKNOWN pUnk );
  306.     void * GetFirstApiInstance( REFIID refiid, LPUNKNOWN * ppUnk);
  307.     int RemoveInstance( LPUNKNOWN pUnk );
  308.     LPUNKNOWN CreateClassInstance (
  309.         APICLASS lpszClassName,LPUNKNOWN pUnkOuter,APISIGNATURE apiSig);
  310.     int RegisterClassFactory (
  311.            APICLASS lpszClassName, LPCLASSFACTORY pClassFactory, char * szModuleName = 0);
  312. };
  313.  
  314. ClassRepository::ClassRepository ( )
  315. {
  316.     m_ClassList = NULL;
  317.     RegisterClassFactory(APICLASS_APIAPI,(LPCLASSFACTORY)this);
  318. }
  319.  
  320. ClassRepository::~ClassRepository ( )
  321. {
  322.     if (m_ClassList) {
  323.         int elements = (int)m_ClassList->elements( );
  324.         while ( elements ) {
  325.             elements--;
  326.         }
  327.     }
  328. }
  329.  
  330. STDMETHODIMP ClassRepository::CreateInstance(
  331.     LPUNKNOWN pUnkOuter,REFIID refiid, LPVOID * ppvObj)
  332. {
  333.     *ppvObj = NULL;
  334.     ClassRepository * pRepository = new ClassRepository;
  335.     return pRepository->QueryInterface(refiid,ppvObj);   
  336. }
  337.  
  338. int ClassRepository::RemoveInstance( LPUNKNOWN pUnk )
  339. {
  340.     if (m_ClassList) {
  341.         int elements = (int) m_ClassList->elements();
  342.         int i;
  343.         for ( i = 0; i < elements; i++ ) {    
  344.             ClassFactory * entry = (ClassFactory *)m_ClassList->GetAt(i);
  345.             entry->Remove(pUnk);
  346.         }
  347.     }
  348.     return 0;
  349. }    
  350.  
  351. ClassFactory * ClassRepository::GetFirst(void)
  352. {
  353.     if (!m_ClassList)
  354.         return 0;
  355.  
  356.     if (!m_ClassList->elements())
  357.            return 0;
  358.     return (ClassFactory *)m_ClassList->GetAt(0);
  359. }
  360.  
  361. ClassFactory * ClassRepository::GetNext(ClassFactory * pFactory)
  362. {
  363.     if (m_ClassList) {
  364.         for (int i = 0; i < m_ClassList->elements() - 1; i++)
  365.             if (m_ClassList->GetAt(i) == (void*)pFactory)
  366.                   return (ClassFactory *)m_ClassList->GetAt(i+1);
  367.     }
  368.    return 0;
  369. }
  370.  
  371. void ClassRepository::Remove(ClassFactory * pFactory)
  372. {
  373.     if (m_ClassList)
  374.         m_ClassList = m_ClassList->Remove((void*)pFactory);
  375. }
  376.  
  377. LPUNKNOWN ClassRepository::CreateClassInstance(
  378.     APICLASS lpszClassName,
  379.     LPUNKNOWN pUnkOuter,
  380.     APISIGNATURE apiSig )
  381. {
  382.     ClassFactory * pFactory = Lookup(lpszClassName);
  383.     if (pFactory) {
  384.         if (apiSig) {
  385.             LPUNKNOWN pUnk;
  386.             if ((pUnk = pFactory->LocateBySignature(apiSig)) != NULL) 
  387.                 return pUnk;
  388.         }
  389.            return pFactory->CreateClassInstance(pUnkOuter,apiSig);
  390.     }
  391.       
  392.     return NULL;
  393. }
  394.    
  395. BOOL ClassFactory::AttemptToLoad(void)
  396. {
  397.     if ((!m_pszModuleName) || m_bIsLoaded)
  398.         return FALSE;
  399.     // attempt to load the interface module (DLL)
  400.     m_hModule = LoadLibrary (m_pszModuleName);
  401.     if (m_hModule > (HMODULE)32) {
  402.        // The class factory initializer is the first routine in the DLL.
  403.         APIBOOTER fpApiInitialize = 
  404.             (APIBOOTER)GetProcAddress(m_hModule,MAKEINTRESOURCE(1));
  405.       // if we got a valid initializer, then call it with the 
  406.       // class name.  This was the module can initialize one at 
  407.       // a time if it likes.
  408.         if (fpApiInitialize != NULL ) {
  409.             m_bIsLoaded = TRUE;
  410.             if ((*fpApiInitialize)(m_pszClassName))
  411.                 return TRUE;
  412.             }
  413.             else
  414.                 m_bIsLoaded = FALSE;
  415.     }
  416.     else {
  417.         // couldn't load the module
  418.         char szMessage[1024];
  419.         sprintf ( szMessage, "Cannot load module: %.800s\nClass factory %800s", 
  420.                 m_pszModuleName, m_pszClassName);
  421.         MessageBox ( 0, szMessage, "Interface Error", MB_OK | MB_ICONEXCLAMATION );
  422.     }
  423.     return FALSE;
  424. }
  425.  
  426. ClassFactory * ClassRepository::Lookup ( char * pszClassName )
  427. {
  428.     // get the number of stored elements
  429.     if (m_ClassList) {
  430.         int elements = (int) m_ClassList->elements();
  431.         int i;
  432.  
  433.         // look up the api            
  434.         for ( i = 0; i < elements; i++ )    {
  435.             ClassFactory * entry = (ClassFactory *)m_ClassList->GetAt(i);
  436.             if (!stricmp(entry->m_pszClassName, pszClassName)) {
  437.                 if (!entry->m_bIsLoaded)
  438.                     if (entry->AttemptToLoad())
  439.                         return entry;
  440.                     else
  441.                         return 0;
  442.                 return entry;        
  443.             }
  444.         }
  445.     }
  446.     return 0;
  447. }
  448.  
  449. int ClassRepository::RegisterClassFactory ( 
  450.     char * pszClassName,
  451.    LPCLASSFACTORY pClassFactory,
  452.    char * szModuleName )
  453. {
  454.     ClassFactory * pClassEntry;
  455.     if ((pClassEntry = Lookup (pszClassName)) != 0) {
  456.         pClassEntry->m_pClassFactory = pClassFactory;
  457.         return 1;
  458.     }
  459.     else {
  460.         pClassEntry = new ClassFactory ( pszClassName, pClassFactory, szModuleName);
  461.         if (!m_ClassList)
  462.             m_ClassList = new CAPIList((void*)pClassEntry);
  463.         else
  464.             m_ClassList = m_ClassList->Add ((void*)pClassEntry );
  465.     }
  466.  
  467.     return 0;
  468. }
  469.  
  470. void * ClassRepository::GetFirstApiInstance( REFIID refiid, LPUNKNOWN * ppUnk)
  471. {
  472.     void * pSomeInterface;
  473.     *ppUnk = 0;
  474.     ClassFactory * pClass = GetFirst();
  475.     while (pClass) {
  476.         LPUNKNOWN pUnk = pClass->GetFirst();
  477.         while (pUnk) {
  478.             if (pUnk->QueryInterface(refiid,(LPVOID*)&pSomeInterface) == NOERROR) {
  479.                 *ppUnk = pUnk;
  480.                 return pSomeInterface;
  481.                 }
  482.             pUnk = pClass->GetNext(pUnk);
  483.         }
  484.         pClass = GetNext(pClass);
  485.     }
  486.     return NULL;
  487. }
  488.  
  489. // function looks up an API by id and returns a void pointer which in
  490. // turn can be cast to the requested interface type.  This is done 
  491. // for you by the Api<id,interf> template.
  492.  
  493. LPUNKNOWN ClassRepository::GetFirstInstance ( char * pszClassName )
  494. {
  495.     if (m_ClassList) {
  496.         for (int i = 0; i < m_ClassList->elements(); i++) {
  497.             ClassFactory * pClassFactory = (ClassFactory *)m_ClassList->GetAt(i);
  498.             if (!stricmp(pClassFactory->m_pszClassName, pszClassName)) {
  499.                 if (pClassFactory->m_ApiList)
  500.                     return ((ApiEntry*)pClassFactory->m_ApiList->GetAt(0))->GetUnk();
  501.                 return NULL;
  502.             }
  503.         }
  504.     }
  505.     return NULL;
  506. }
  507.  
  508. LPUNKNOWN ClassRepository::GetNextInstance ( char * pszClassName, LPUNKNOWN pUnk )
  509. {
  510.     if (m_ClassList) {
  511.         for (int i = 0; i < m_ClassList->elements(); i++) {
  512.             ClassFactory * pClassFactory = (ClassFactory *)m_ClassList->GetAt(i);
  513.             if (!stricmp(pClassFactory->m_pszClassName, pszClassName)) {
  514.                 CAPIList * pList = pClassFactory->m_ApiList;
  515.                 if (pList)
  516.                 for (int j = 0; j<pList->elements()-1; j++)
  517.                     if (((ApiEntry*)pList->GetAt(j))->GetUnk() == pUnk)
  518.                         return ((ApiEntry*) pClassFactory->m_ApiList->GetAt(j+1))->GetUnk();
  519.                 return NULL;
  520.             }
  521.         }
  522.     }
  523.     return NULL;
  524. }
  525.  
  526.  
  527. // The apiapi object MUST be constructed first, this pragma ensures that
  528. // the static constructor will occur before any other static construction
  529. // happens.              
  530. #pragma warning( disable : 4074 )
  531. #pragma init_seg(compiler)
  532. static ClassRepository classRepository;
  533.  
  534. // global function gets the ApiApi from the static repository
  535. // From here, all registered APIs can be retrieved and set
  536.  
  537. API_PUBLIC(LPAPIAPI) GetAPIAPI()
  538. {
  539.     return (LPAPIAPI) &classRepository;
  540. }
  541.  
  542. // Generic Objects
  543. // Generic Factory
  544.  
  545.  
  546. STDMETHODIMP CGenericFactory::QueryInterface(REFIID refiid, LPVOID * ppv)
  547. {
  548.     *ppv = NULL;
  549.     if (IsEqualIID(refiid,IID_IUnknown))
  550.         *ppv = (LPUNKNOWN) this;
  551.     else if (IsEqualIID(refiid,IID_IClassFactory))
  552.         *ppv = (LPCLASSFACTORY) this;
  553.  
  554.     if (*ppv != NULL) {
  555.            AddRef();
  556.         return NOERROR;
  557.     }
  558.             
  559.     return ResultFromScode(E_NOINTERFACE);
  560. }
  561.  
  562. STDMETHODIMP_(ULONG) CGenericFactory::AddRef(void)
  563. {
  564.     return ++m_ulRefCount;
  565. }
  566.  
  567. STDMETHODIMP_(ULONG) CGenericFactory::Release(void)
  568. {
  569.     ULONG ulRef;
  570.     ulRef = --m_ulRefCount;
  571.     if (m_ulRefCount == 0) ;
  572. //        delete this;       
  573.     return ulRef;       
  574. }
  575.  
  576. STDMETHODIMP CGenericFactory::CreateInstance(
  577.     LPUNKNOWN pUnkOuter,REFIID refiid, LPVOID * ppvObj)
  578. {
  579.     return NULL;
  580.     // User Implemented       
  581. }
  582.  
  583. STDMETHODIMP CGenericFactory::LockServer(BOOL fLock)
  584. {
  585.     return NOERROR;
  586. }
  587.  
  588. // Generic Object
  589.  
  590. STDMETHODIMP CGenericObject::QueryInterface(REFIID refiid, LPVOID * ppv)
  591. {
  592.     return ResultFromScode(E_NOINTERFACE);
  593. }
  594.  
  595. STDMETHODIMP_(ULONG) CGenericObject::AddRef(void)
  596. {
  597.     return ++m_ulRefCount;
  598. }
  599.  
  600. STDMETHODIMP_(ULONG) CGenericObject::Release(void)
  601. {
  602.     ULONG ulRef;
  603.     ulRef = --m_ulRefCount;
  604.     if (m_ulRefCount == 0) {
  605.         classRepository.RemoveInstance(this);
  606.         delete this;       
  607.     }
  608.     return ulRef;       
  609. }
  610.  
  611.