home *** CD-ROM | disk | FTP | other *** search
/ Mastering Visual Basic 6 / mastvb6.iso / numega / sc501.exe / data1.cab / Examples / IFT_DLL.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-25  |  21.5 KB  |  617 lines

  1. /*
  2.  * IFT_DLL.cpp
  3.  * $Header: /bcsample/IFACEDLL/IFT_DLL.CPP 1     5/28/96 1:12p Dave $
  4.  *
  5.  * Description:
  6.  *  This file provides the main entry-points for OLE and the implementation
  7.  *  of the class factory for the Interface Test Object.  The DLL is a 
  8.  *  self-registering DLL. 
  9.  *
  10.  * Notes:
  11.  *  To avoid a large memory and performance overhead for a simple OLE interface 
  12.  *  testing object, MFC was not used.  As a result, much of the design for the 
  13.  *  DLL entry-points and class factory are based on the implementations from 
  14.  *  Kraig Brockschmidt's book, "Inside OLE," the foremost resource on OLE 
  15.  *  technology.
  16.  *
  17.  ***********************************************************************
  18.  *
  19.  * NuMega Technologies, Inc.
  20.  * P.O. Box 7780
  21.  * Nashua, NH 03060
  22.  *
  23.  * (c) Copyright 1994, 1995, 1996 NuMega Technologies, Inc.
  24.  * ALL RIGHTS RESERVED.
  25.  *
  26.  ***********************************************************************
  27.  *
  28.  **********************************************************************/
  29.  
  30. #include "IFT_OLE.h"
  31. #define INITGUIDS
  32.  
  33. #include "IT_GUID.h"
  34. #include "IFT_DLL.h"
  35. #include "IUnknown.h"
  36. #include <tchar.h>
  37. #include <crtdbg.h>
  38.  
  39. /*----------------------------------------------------------------------
  40.                      Constants - Strings
  41. ----------------------------------------------------------------------*/
  42. const TCHAR* gk_szModuleID                 = _T ( "IFACEDLL" )                 ;
  43. const TCHAR* gk_szCLSID                    = _T ( "CLSID" )                    ;
  44. const TCHAR* gk_szSlash                    = _T ( "\\" )                       ;
  45. const TCHAR* gk_szProgID                   = _T ( "ProgID" )                   ;
  46. const TCHAR* gk_szCurVer                   = _T ( "CurVer" )                   ;
  47. const TCHAR* gk_szNotInsertable            = _T ( "NotInsertable" )            ;
  48. const TCHAR* gk_szVersionIndependentProgID = _T ( "VersionIndependentProgID" ) ;
  49. const TCHAR* gk_szInprocServer32           = _T ( "InprocServer32" )           ;
  50. const TCHAR* gk_szIfaceTestObjectName      = _T ( "InterfaceTest Object" )     ;
  51. const TCHAR* gk_szVerIfaceTestPRGID        = _T ( "InterfaceTest1.0" )         ;
  52. const TCHAR* gk_szIfaceTestPRGID           = _T ( "InterfaceTest" )            ;
  53.  
  54. /*----------------------------------------------------------------------
  55.                      Constants - UINTs
  56. ----------------------------------------------------------------------*/
  57. const UINT   gk_nMaxRegKeySize             = 512 ;
  58. const UINT   gk_nMakeRegExcept             = 13  ;
  59. const UINT   gk_nDelRegExcept              = 113 ;
  60.  
  61.  
  62. // Count number of objects and number of locks.
  63. ULONG        g_nObject  = 0 ;
  64. ULONG        g_nLock    = 0 ;
  65.  
  66. // The usual DLL entry point.
  67. BOOL WINAPI DllMain ( HINSTANCE          ,
  68.                       ULONG     ulReason ,
  69.                       LPVOID              )
  70. {
  71.     if ( DLL_PROCESS_ATTACH == ulReason )
  72.     {
  73.         // Turn of CRT library assertion dialogs.
  74.         _CrtSetReportMode ( _CRT_ASSERT , _CRTDBG_MODE_DEBUG ) ;
  75.         _CrtSetReportMode ( _CRT_ERROR , _CRTDBG_MODE_DEBUG ) ;
  76.         _CrtSetReportMode ( _CRT_WARN , _CRTDBG_MODE_DEBUG ) ;
  77.     }
  78.  
  79.     return ( TRUE ) ;
  80. }
  81.  
  82. /*----------------------------------------------------------------------
  83. FUNCTION    :   DLLGetClassObject
  84. DISCUSSION  :
  85.     When an OLE object is exposed from an in-process server,
  86. CoGetClassObject calls this exported function to retrieve the class
  87. factory of the requested REFCLSID.
  88. PARAMETERS  :
  89.     rclsid - The class ID of the requested class.  (More than one object
  90.              can come from this DLL).
  91.     riid   - The ID of the interface that the user wants.  This is
  92.              usually IClassFactory.
  93.     ppv    - The variable that gets the interface.
  94. RETURN      :
  95.     NOERROR       - Everything was OK and ppv holds a valid interface.
  96.     E_FAIL        - The CLSID requested is not part of this class.
  97.     E_OUTOFMEMORY - There was not enough memory for the request.
  98. ----------------------------------------------------------------------*/
  99. // Note that the STDAPI resolves to "EXTERN_C HRESULT STDAPICALLTYPE"
  100. //  Which sets up the extern "C" for us.
  101. STDAPI DllGetClassObject ( REFCLSID rclsid , REFIID riid , PPVOID ppv )
  102. {
  103.     // The IClassFactory implementation class pointer.
  104.     CIFaceTestClassFactory * pObj ;
  105.     // The value we return.
  106.     HRESULT hr = NOERROR ;
  107.  
  108.     // Set the interface return value to NULL just in case.
  109.     *ppv = NULL ;
  110.  
  111.     // If the requested class is not the one we expose, then kick out.
  112.     if ( CLSID_InterfaceTest != rclsid )
  113.     {
  114.         return ( E_FAIL ) ;
  115.     }
  116.  
  117.     // Allocate the class.
  118.     pObj = new CIFaceTestClassFactory ( ) ;
  119.  
  120.     // If we could not allocate it, return out of memory.
  121.     if ( NULL == pObj )
  122.     {
  123.         return ( E_OUTOFMEMORY ) ;
  124.     }
  125.  
  126.     // Do the query for the requested interface.
  127.     hr = pObj->QueryInterface ( riid , ppv ) ;
  128.  
  129.     // If the interface is not supported, delete the IClassFactory
  130.     //  implementation instance.
  131.     if ( FAILED ( hr ) )
  132.     {
  133.         delete pObj ;
  134.     }
  135.  
  136.     return ( hr ) ;
  137. }
  138.  
  139. /*----------------------------------------------------------------------
  140. FUNCTION    :   DllCanUnloadNow
  141. DISCUSSION  :
  142.     If there are no references ony objects that this DLL provides, than
  143. the DLL can be unloaded.
  144. PARAMETERS  :
  145.     None.
  146. RETURN      :
  147.     S_OK    - The DLL can be unloaded.
  148.     S_FALSE - The DLL still has referenced objects.
  149. ----------------------------------------------------------------------*/
  150. STDAPI DllCanUnloadNow ( void )
  151. {
  152.     HRESULT hr ;
  153.  
  154.     // Check the global variables to see if there are any objects or
  155.     //  locks outstanding.
  156.     if ( ( 0 == g_nObject ) && ( 0 == g_nLock ) )
  157.     {
  158.         hr = S_OK ;
  159.     }
  160.     else
  161.     {
  162.         hr == S_FALSE ;
  163.     }
  164.     return ( hr ) ;
  165. }
  166.  
  167.  
  168. /*----------------------------------------------------------------------
  169. FUNCTION    :   DllRegisterServer
  170. DISCUSSION  :
  171.     Implementation of sef-registration functionality.
  172. PARAMETERS  :   void
  173. RETURN      :
  174.     NOERROR if successful, SELFREG_E_CLASS otherwise.
  175. ----------------------------------------------------------------------*/
  176. STDAPI DllRegisterServer ( void )
  177. {
  178.     BOOL        fContinue        = TRUE                      ;
  179.     TCHAR       szIfaceTestID    [ gk_nMaxRegKeySize ]       ;
  180.     TCHAR       szRootKey        [ gk_nMaxRegKeySize ]       ; 
  181.     TCHAR       szModule         [ _MAX_PATH ]               ;
  182.     TCHAR       szTemp           [ gk_nMaxRegKeySize ]       ;
  183.     WCHAR       szwIfaceTestID   [ gk_nMaxRegKeySize ]       ;
  184.  
  185.     HRESULT     hrRet           = NOERROR                    ;
  186.  
  187.  
  188.     // Root registry key names
  189.     StringFromGUID2 ( CLSID_InterfaceTest , szwIfaceTestID , gk_nMaxRegKeySize );
  190. #ifdef _UNICODE
  191.     lstrcpy ( szIfaceTestID , szwIfaceTestID ) ;
  192. #else                               
  193.     wcstombs ( szIfaceTestID , szwIfaceTestID , gk_nMaxRegKeySize ) ;
  194. #endif
  195.  
  196.     lstrcpy         ( szRootKey , gk_szCLSID ) ;
  197.     lstrcat         ( szRootKey , gk_szSlash ) ;
  198.     lstrcat         ( szRootKey , szIfaceTestID )   ;
  199.  
  200.     try
  201.     {
  202.         // Create ProgID keys
  203.         MakeRegEntry( gk_szVerIfaceTestPRGID  , 
  204.                       NULL                    ,
  205.                       gk_szIfaceTestObjectName ) ;
  206.   
  207.         MakeRegEntry( gk_szVerIfaceTestPRGID ,
  208.                       gk_szCLSID             , 
  209.                       szIfaceTestID           ) ;
  210.  
  211.  
  212.         // Create VersionIndependentProgID keys
  213.         MakeRegEntry( gk_szIfaceTestPRGID         ,
  214.                       NULL                        ,
  215.                       gk_szIfaceTestObjectName     ) ;
  216.             
  217.         MakeRegEntry( gk_szIfaceTestPRGID   ,  
  218.                       gk_szCurVer           ,
  219.                       gk_szVerIfaceTestPRGID ) ;
  220.  
  221.         MakeRegEntry( gk_szIfaceTestPRGID , 
  222.                       gk_szCLSID          , 
  223.                       szIfaceTestID        ) ;
  224.  
  225.         // Create CLSID key entries
  226.         wsprintf ( szTemp , _T ( "%s\\%s" ) , gk_szCLSID , szIfaceTestID ) ;
  227.         MakeRegEntry( szTemp                  ,  
  228.                       NULL                    , 
  229.                       gk_szIfaceTestObjectName ) ;
  230.  
  231.         MakeRegEntry( szTemp      , 
  232.                       gk_szProgID     , 
  233.                       gk_szVerIfaceTestPRGID ) ;
  234.  
  235.         MakeRegEntry( szTemp                       , 
  236.                       gk_szVersionIndependentProgID    ,
  237.                       gk_szIfaceTestPRGID               ) ;
  238.  
  239.         MakeRegEntry( szTemp          , 
  240.                       gk_szNotInsertable  , 
  241.                       NULL                 ) ;
  242.  
  243.         HINSTANCE hMod = GetModuleHandle( gk_szModuleID ) ;
  244.         GetModuleFileName(hMod, szModule, sizeof(szModule)/sizeof(TCHAR));
  245.  
  246.         MakeRegEntry( szTemp          , 
  247.                       gk_szInprocServer32 , 
  248.                       szModule             ) ;
  249.     }
  250.     catch ( UINT nE )
  251.     {
  252.         if ( gk_nMakeRegExcept == nE )
  253.             hrRet = SELFREG_E_CLASS ;
  254.         else
  255.             throw nE ;
  256.     }
  257.  
  258.     return hrRet ;
  259.         
  260. }
  261.  
  262.  
  263. /*----------------------------------------------------------------------
  264. FUNCTION    :   DllUnregisterServer
  265. DISCUSSION  :
  266.     Implementation of sef-registration functionality.
  267. PARAMETERS  :   void
  268. RETURN      :
  269.     NOERROR if successful, SELFREG_E_CLASS otherwise.
  270. ----------------------------------------------------------------------*/
  271. STDAPI DllUnregisterServer ( void )
  272. {                                        
  273.     BOOL        fContinue        = TRUE    ;
  274.     TCHAR       szIfaceTestID    [ gk_nMaxRegKeySize ]   ;
  275.     TCHAR       szRootKey        [ gk_nMaxRegKeySize ]   ; 
  276.     TCHAR       szTemp           [ gk_nMaxRegKeySize ]   ;
  277.     WCHAR       szwIfaceTestID   [ gk_nMaxRegKeySize ]   ;
  278.  
  279.     HRESULT     hrRet            = NOERROR ;
  280.  
  281.     
  282.     // Root registry key names
  283.     StringFromGUID2 ( CLSID_InterfaceTest , szwIfaceTestID , gk_nMaxRegKeySize );
  284. #ifdef _UNICODE
  285.     lstrcpy ( szIfaceTestID , szwIfaceTestID ) ;
  286. #else
  287.     wcstombs ( szIfaceTestID , szwIfaceTestID , gk_nMaxRegKeySize ) ;
  288. #endif
  289.  
  290.     lstrcpy         ( szRootKey , gk_szCLSID ) ;
  291.     lstrcat         ( szRootKey , gk_szSlash ) ;
  292.     lstrcat         ( szRootKey , szIfaceTestID )   ;
  293.  
  294.     try 
  295.     {
  296.         // Delete ProgID keys
  297.         wsprintf ( szTemp , _T ( "%s\\%s" ) , gk_szIfaceTestPRGID , gk_szCurVer ) ;
  298.         if ( ERROR_SUCCESS != RegDeleteKey ( HKEY_CLASSES_ROOT , szTemp ) )
  299.             throw gk_nDelRegExcept ;
  300.         wsprintf ( szTemp , _T ( "%s\\%s" ) , gk_szIfaceTestPRGID , gk_szCLSID ) ;
  301.         if ( ERROR_SUCCESS != RegDeleteKey ( HKEY_CLASSES_ROOT , szTemp ) )
  302.             throw gk_nDelRegExcept ;    
  303.         if ( ERROR_SUCCESS != RegDeleteKey ( HKEY_CLASSES_ROOT , gk_szIfaceTestPRGID ) )
  304.             throw gk_nDelRegExcept ;    
  305.  
  306.         // Delete VersionIndependentProgID keys
  307.         wsprintf ( szTemp , _T ( "%s\\%s" ) , gk_szVerIfaceTestPRGID , gk_szCLSID ) ;
  308.         if ( ERROR_SUCCESS != RegDeleteKey ( HKEY_CLASSES_ROOT , szTemp ) )
  309.             throw gk_nDelRegExcept ;    
  310.         if ( ERROR_SUCCESS != RegDeleteKey ( HKEY_CLASSES_ROOT , gk_szVerIfaceTestPRGID ) )
  311.             throw gk_nDelRegExcept ;    
  312.  
  313.         // Delete CLSID key entries
  314.         wsprintf ( szTemp , _T ( "%s\\%s\\%s" ) , gk_szCLSID , szIfaceTestID , gk_szProgID ) ;
  315.         if ( ERROR_SUCCESS != RegDeleteKey ( HKEY_CLASSES_ROOT , szTemp ) )
  316.             throw gk_nDelRegExcept ;    
  317.         wsprintf ( szTemp , _T ( "%s\\%s\\%s" ) , gk_szCLSID , szIfaceTestID , gk_szVersionIndependentProgID ) ;
  318.         if ( ERROR_SUCCESS != RegDeleteKey ( HKEY_CLASSES_ROOT , szTemp ) )
  319.             throw gk_nDelRegExcept ;    
  320.         wsprintf ( szTemp , _T ( "%s\\%s\\%s" ) , gk_szCLSID , szIfaceTestID , gk_szNotInsertable ) ;
  321.         if ( ERROR_SUCCESS != RegDeleteKey ( HKEY_CLASSES_ROOT , szTemp ) )
  322.             throw gk_nDelRegExcept ;    
  323.         wsprintf ( szTemp , _T ( "%s\\%s\\%s" ) , gk_szCLSID , szIfaceTestID , gk_szInprocServer32 ) ;
  324.         if ( ERROR_SUCCESS != RegDeleteKey ( HKEY_CLASSES_ROOT , szTemp ) )
  325.             throw gk_nDelRegExcept ;    
  326.         wsprintf ( szTemp , _T ( "%s\\%s" ) , gk_szCLSID , szIfaceTestID ) ;
  327.         if ( ERROR_SUCCESS != RegDeleteKey ( HKEY_CLASSES_ROOT , szTemp ) )
  328.             throw gk_nDelRegExcept ;    
  329.     }
  330.     catch ( UINT nE )
  331.     {
  332.         if ( gk_nDelRegExcept == nE )
  333.             hrRet = SELFREG_E_CLASS ;
  334.         else
  335.             throw nE ;
  336.     }
  337.  
  338.     return hrRet ;
  339. }
  340.  
  341.  
  342.  
  343. /*----------------------------------------------------------------------
  344. FUNCTION    :   MakeRegEntry
  345. DISCUSSION  :
  346.     Support function for the sef-registration functionality.
  347. PARAMETERS  :   void
  348.     szKey          Name of key under which to add the entry
  349.     szEntryKey     The name of the key in the new entry
  350.     szEntryVal     The string value to store for the new entry
  351. RETURN      :
  352.     TRUE if successful, FALSE otherwise.
  353. ----------------------------------------------------------------------*/
  354. BOOL MakeRegEntry ( LPCTSTR szKey      , 
  355.                     LPCTSTR szEntryKey ,
  356.                     LPCTSTR szEntryVal  )
  357. {
  358.     HKEY        hKey               ;
  359.     TCHAR       szTempKey [ 256 ]  ;
  360.     BOOL        fReturn = FALSE    ;
  361.  
  362.     lstrcpy ( szTempKey , szKey ) ;
  363.  
  364.     if ( NULL != szEntryKey )
  365.     {
  366.         lstrcat ( szTempKey , gk_szSlash ) ;
  367.         lstrcat ( szTempKey , szEntryKey ) ;
  368.     }
  369.  
  370.     if ( ERROR_SUCCESS == RegCreateKeyEx ( HKEY_CLASSES_ROOT        ,
  371.                                            szTempKey                ,  
  372.                                            0                        , 
  373.                                            NULL                     , 
  374.                                            REG_OPTION_NON_VOLATILE  ,
  375.                                            KEY_ALL_ACCESS           , 
  376.                                            NULL                     , 
  377.                                            &hKey                    , 
  378.                                            NULL                      ) )
  379.     {
  380.         if ( NULL != szEntryVal )
  381.         {
  382.             RegSetValueEx( hKey                                             ,   
  383.                            NULL                                             , 
  384.                            0                                                , 
  385.                            REG_SZ                                           , 
  386.                            ( BYTE * ) szEntryVal                            ,
  387.                            ( lstrlen ( szEntryVal ) + 1 ) * sizeof ( TCHAR ) );
  388.         }
  389.  
  390.         RegCloseKey ( hKey ) ;
  391.  
  392.         fReturn = TRUE ;        
  393.     }    
  394.     else
  395.         throw gk_nMakeRegExcept ;
  396.  
  397.     return ( fReturn ) ;
  398.     
  399. }
  400.  
  401.  
  402. /*----------------------------------------------------------------------
  403. FUNCTION    :   ObjectDestroyed
  404. DISCUSSION  :
  405.     The notification function that the object will call to let the DLL
  406. implementation that it is going away.  If we didn't have this, then the
  407. DLL would never know the reference or lock count.
  408. PARAMETERS  :
  409.     None.
  410. RETURN      :
  411.     None.
  412. ----------------------------------------------------------------------*/
  413. void ObjectDestroyed ( void )
  414. {
  415.     // Bump the count down.
  416.     g_nObject-- ;
  417. }
  418.  
  419. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  420.  
  421. /*----------------------------------------------------------------------
  422. FUNCTION    :   CIFaceTestClassFactory :: CIFaceTestClassFactory
  423. DISCUSSION  :
  424.     Constructor for the IClassFactory implementation class.
  425. PARAMETERS  :
  426.     None.
  427. RETURN      :
  428.     None.
  429. ----------------------------------------------------------------------*/
  430. CIFaceTestClassFactory :: CIFaceTestClassFactory ( )
  431. {
  432.     m_nRef = 0L ;
  433. }
  434.  
  435. /*----------------------------------------------------------------------
  436. FUNCTION    :   CIFaceTestClassFactory :: ~CIFaceTestClassFactory
  437. DISCUSSION  :
  438.     Destructor for the IClassFactory implementation class.
  439. PARAMETERS  :
  440.     None.
  441. RETURN      :
  442.     None.
  443. ----------------------------------------------------------------------*/
  444. CIFaceTestClassFactory :: ~CIFaceTestClassFactory ( )
  445. {
  446. }
  447.  
  448.  
  449. /*----------------------------------------------------------------------
  450. FUNCTION    :   CIFaceTestClassFactory :: QueryInterface
  451. DISCUSSION  :
  452.     The implementation of the IUnknown::QueryInterface function.
  453. PARAMETERS  :
  454.     riid - The IID of the interface requested.
  455.     ppv  - Receives the returned interface.
  456. RETURN      :
  457.     NOERROR       - The requested interface is in ppv.
  458.     E_NOINTERFACE - The requested interface is not implemented.
  459. ----------------------------------------------------------------------*/
  460. STDMETHODIMP CIFaceTestClassFactory :: QueryInterface ( REFIID riid ,
  461.                                                         PPVOID ppv   )
  462. {
  463.     // Always set the return interface pointer to NULL.
  464.     *ppv = NULL ;
  465.  
  466.     // If the request of for the IUnknown or IClassFactory interface,
  467.     //  we can support it.
  468.     if ( ( IID_IUnknown == riid ) || ( IID_IClassFactory == riid ) )
  469.     {
  470.         *ppv = this ;
  471.     }
  472.  
  473.     // If the request was for an interface we know about, then AddRef
  474.     //  the interface.
  475.     if ( NULL != *ppv )
  476.     {
  477.         ((LPUNKNOWN)*ppv)->AddRef ( ) ;
  478.         return ( NOERROR ) ;
  479.     }
  480.  
  481.     // The requested interface is not supported.
  482.     return ( E_NOINTERFACE ) ;
  483. }
  484.  
  485.  
  486. /*----------------------------------------------------------------------
  487. FUNCTION    :   CIFaceTestClassFactory :: AddRef
  488. DISCUSSION  :
  489.     The implementation of the IUnknown::AddRef function.
  490. PARAMETERS  :
  491.     None.
  492. RETURN      :
  493.     The new reference count for diagnostic purposes only.
  494. ----------------------------------------------------------------------*/
  495. STDMETHODIMP_( ULONG ) CIFaceTestClassFactory :: AddRef ( void )
  496. {
  497.     m_nRef++ ;
  498.     return ( m_nRef ) ;
  499. }
  500.  
  501. /*----------------------------------------------------------------------
  502. FUNCTION    :   CIFaceTestClassFactory :: Release
  503. DISCUSSION  :
  504.     The implementation of the IUnknown::Release function.
  505. PARAMETERS  :
  506.     None.
  507. RETURN      :
  508.     The new reference count for diagnostic purposes only.
  509. ----------------------------------------------------------------------*/
  510. STDMETHODIMP_( ULONG ) CIFaceTestClassFactory :: Release ( void )
  511. {
  512.     m_nRef-- ;
  513.     if ( 0L != m_nRef )
  514.     {
  515.         return ( m_nRef ) ;
  516.     }
  517.  
  518.     delete this ;
  519.     return ( 0L ) ;
  520. }
  521.  
  522.  
  523. /*----------------------------------------------------------------------
  524. FUNCTION    :   CIFaceTestClassFactory :: CreateInstance
  525. DISCUSSION  :
  526.     The implementation of the IClassFactory::CreateInstance function.
  527. PARAMETERS  :
  528.     pUnkOuter - Indicates if the object is being created as part of a
  529.                 aggregate.  If not NULL, the controlling unknown.
  530.     riid      - Specified the IID of the interface the caller wants from
  531.                 the object.
  532.     ppvObj    - The interface storeage location.
  533. RETURN      :
  534.     CLASS_E_NOAGGREGATION - This object does not support aggregation.
  535.     E_OUTOFMEMORY         - Unable to allocate memory for the
  536.                             implementation class.
  537.     E_UNEXPECTED          - Unable to initialize the implementation
  538.                             class.
  539.     NOERROR               - All OK, Jumpmaster!
  540. ----------------------------------------------------------------------*/
  541. STDMETHODIMP CIFaceTestClassFactory ::
  542.                                   CreateInstance ( LPUNKNOWN pUnkOuter ,
  543.                                                    REFIID    riid      ,
  544.                                                    PPVOID    ppvObj    )
  545. {
  546.     // The pointer to the class object.
  547.     PCIUnknown      pObj ;
  548.     HRESULT         hr   ;
  549.  
  550.     // Always NULL out the interface return location.
  551.     *ppvObj = NULL ;
  552.  
  553.     // Verify that a controlling unknown asks for IUnknown.  This
  554.     //  implementation does not support aggregation.
  555.     if ( ( NULL != pUnkOuter ) && ( IID_IUnknown != riid ) )
  556.     {
  557.         return ( CLASS_E_NOAGGREGATION ) ;
  558.     }
  559.  
  560.     // Create the object passing function to notify on destruction.
  561.     pObj = new CIUnknown ( pUnkOuter , ObjectDestroyed ) ;
  562.  
  563.     // If we could not allocate the implementation class, kick out.
  564.     if ( NULL == pObj )
  565.     {
  566.         return ( E_OUTOFMEMORY ) ;
  567.     }
  568.  
  569.     // Call the implementation initialization function.  If if fails,
  570.     //  we will return E_UNEXPECTED to indicate we had a major problem.
  571.     if ( FALSE == pObj->Init ( ) )
  572.     {
  573.         return ( E_UNEXPECTED ) ;
  574.     }
  575.  
  576.     // Now do the query interface for the requested interface.
  577.     hr = pObj->QueryInterface ( riid , ppvObj ) ;
  578.  
  579.     //Kill the object if initial creation or Init failed.
  580.     if ( FAILED ( hr ) )
  581.     {
  582.         delete pObj ;
  583.     }
  584.     else
  585.     {
  586.         // Bump up the number of objects created.
  587.         g_nObject++ ;
  588.     }
  589.  
  590.     return ( hr ) ;
  591. }
  592.  
  593. /*----------------------------------------------------------------------
  594. FUNCTION    :   CIFaceTestClassFactory :: LockServer
  595. DISCUSSION  :
  596.     The implementation of the IClassFactory::LockServer function.
  597. PARAMETERS  :
  598.     fLock - If TRUE, the lock count is incremented.  If false, the lock
  599.             count is decremented.
  600. RETURN      :
  601.     NOERROR.
  602. ----------------------------------------------------------------------*/
  603. STDMETHODIMP CIFaceTestClassFactory :: LockServer ( BOOL fLock )
  604. {
  605.     if ( TRUE == fLock )
  606.     {
  607.         g_nLock++ ;
  608.     }
  609.     else
  610.     {
  611.         g_nLock-- ;
  612.     }
  613.  
  614.     return ( NOERROR ) ;
  615. }
  616.  
  617.