text: /*==========================================================================
   *
   *  Copyright (C) 1998 Microsoft Corporation.  All Rights Reserved.
   *
   *  File:       classfac.c
   *  Content:	a generic class factory
   *
   *
   *	This is a generic C class factory.  All you need to do is implement
   *	a function called DoCreateInstance that will create an instace of
   *	your object.  
   *
   *	GP_ stands for "General Purpose"
   *
   *  History:
   *   Date		By		Reason
   *   ====		==		======
   *	10/13/98	jwo		Created it.
   * 04/11/00     rodtoll     Added code for redirection for custom builds if registry bit is set 
   * 08/23/2000	rodtoll	DllCanUnloadNow always returning TRUE!
   * 06/27/2001	rodtoll	RC2: DPVOICE: DPVACM's DllMain calls into acm -- potential hang
   *						Move global initialization to first object creation
   ***************************************************************************/
  
  #include "dpvacmpch.h"
  
  DNCRITICAL_SECTION g_csObjectCountLock;
  LONG g_lNumObjects = 0;
  HINSTANCE g_hDllInst = NULL;
  
  LONG g_lNumLocks = 0;
  
  typedef struct GPCLASSFACTORY
  {
     IClassFactoryVtbl 		*lpVtbl;
     LONG					lRefCnt;
     CLSID					clsid;
  } GPCLASSFACTORY, *LPGPCLASSFACTORY;
  
  
  /*
   * GP_QueryInterface
   */
  STDMETHODIMP GP_QueryInterface(
                  LPCLASSFACTORY This,
                  REFIID riid,
                  LPVOID *ppvObj )
  {
      LPGPCLASSFACTORY	pcf;
  	HRESULT hr;
  	
      pcf = (LPGPCLASSFACTORY)This;
      *ppvObj = NULL;
  
  
      if( IsEqualIID(riid, IID_IClassFactory) ||
                      IsEqualIID(riid, IID_IUnknown))
      {
  		InterlockedIncrement( &pcf->lRefCnt );
          *ppvObj = This;
  		hr = S_OK;
      }
      else
      { 
  		hr = E_NOINTERFACE;
      }
  
  	
  	return hr;
  	
  } /* GP_QueryInterface */
  
  
  /*
   * GP_AddRef
   */
  STDMETHODIMP_(ULONG) GP_AddRef( LPCLASSFACTORY This )
  {
      LPGPCLASSFACTORY pcf;
  
      pcf = (LPGPCLASSFACTORY)This;
  
      return InterlockedIncrement( &pcf->lRefCnt );
  } /* GP_AddRef */
  
  
  
  /*
   * GP_Release
   */
  STDMETHODIMP_(ULONG) GP_Release( LPCLASSFACTORY This )
  {
      LPGPCLASSFACTORY	pcf;
      ULONG ulResult; 
  
      pcf = (LPGPCLASSFACTORY)This;
  
      if( (ulResult = (ULONG) InterlockedDecrement( &pcf->lRefCnt ) ) == 0 )
      {
  	    DNFree( pcf );
  		DecrementObjectCount();
      }
      
      return ulResult;
  
  } /* GP_Release */
  
  
  
  
  /*
   * GP_CreateInstance
   *
   * Creates an instance of a DNServiceProvider object
   */
  STDMETHODIMP GP_CreateInstance(
                  LPCLASSFACTORY This,
                  LPUNKNOWN pUnkOuter,
                  REFIID riid,
      			LPVOID *ppvObj
  				)
  {
      HRESULT					hr = S_OK;
      LPGPCLASSFACTORY		pcf;
  
      if( pUnkOuter != NULL )
      {
          return CLASS_E_NOAGGREGATION;
      }
  
  	pcf = (LPGPCLASSFACTORY) This;
  	*ppvObj = NULL;
  
  
      /*
       * create the object by calling DoCreateInstance.  This function
       *	must be implemented specifically for your COM object
       */
  	hr = DoCreateInstance(This, pUnkOuter, pcf->clsid, riid, ppvObj);
  	if (FAILED(hr))
  	{
  		*ppvObj = NULL;
  		return hr;
  	}
  
      return S_OK;
  
  } /* GP_CreateInstance */
  
  
  
  /*
   * GP_LockServer
   *
   * Called to force our DLL to stayed loaded
   */
  STDMETHODIMP GP_LockServer(
                  LPCLASSFACTORY This,
                  BOOL fLock
  				)
  {
      if( fLock )
      {
  	    InterlockedIncrement( &g_lNumLocks );    	
      }
      else
      {
  	    InterlockedDecrement( &g_lNumLocks );
      }
  
  	return S_OK;
  
  } /* GP_LockServer */
  
  static IClassFactoryVtbl GPClassFactoryVtbl =
  {
          GP_QueryInterface,
          GP_AddRef,
          GP_Release,
          GP_CreateInstance,
          GP_LockServer
  };
  
  /*
   * DllGetClassObject
   *
   * Entry point called by COM to get a ClassFactory pointer
   */
  STDAPI  DllGetClassObject(
                  REFCLSID rclsid,
                  REFIID riid,
                  LPVOID *ppvObj )
  {
      LPGPCLASSFACTORY	pcf;
      HRESULT		hr;
  
      *ppvObj = NULL;
  
      /*
       * is this our class id?
       */
  //	you must implement GetClassID() for your specific COM object
  	if (!IsClassImplemented(rclsid))
      {
  		return CLASS_E_CLASSNOTAVAILABLE;
  	}
  
      /*
       * only allow IUnknown and IClassFactory
       */
      if( !IsEqualIID( riid, IID_IUnknown ) &&
  	    !IsEqualIID( riid, IID_IClassFactory ) )
      {
          return E_NOINTERFACE;
      }
  
      /*
       * create a class factory object
       */
      pcf = (LPGPCLASSFACTORY)DNMalloc( sizeof( GPCLASSFACTORY ) );
      if( NULL == pcf)
      {
          return E_OUTOFMEMORY;
      }
  
  	pcf->lpVtbl = &GPClassFactoryVtbl;
      pcf->lRefCnt = 0;
  	pcf->clsid = rclsid;
  
      hr = GP_QueryInterface( (LPCLASSFACTORY) pcf, riid, ppvObj );
      if( FAILED( hr ) )
      {
          DNFree ( pcf );
          *ppvObj = NULL;
      }
      else
      {
      	IncrementObjectCount();    
      }
  	
      return hr;
  
  } /* DllGetClassObject */
  
  /*
   * DllCanUnloadNow
   *
   * Entry point called by COM to see if it is OK to free our DLL
   */
  STDAPI DllCanUnloadNow( void )
  {
      HRESULT	hr = S_FALSE;
  
  //	if (0 == gnObjects)
  	if ( (0 == g_lNumObjects) && (0 == g_lNumLocks) )
  	{
  		hr = S_OK;
  	}
  	
      return hr;
  
  } /* DllCanUnloadNow */
  
  
  #undef DPF_MODNAME
  #define DPF_MODNAME "IncrementObjectCount"
  LONG IncrementObjectCount()
  {
  	LONG lNewCount;
  	
  	DNEnterCriticalSection( &g_csObjectCountLock );
  
  	g_lNumObjects++;
  	lNewCount = g_lNumObjects;
  
  	if( g_lNumObjects == 1 )
  	{
  		DPFX(DPFPREP,1,"Initializing Dll Global State" );
  		CDPVACMI::InitCompressionList(g_hDllInst,DPVOICE_REGISTRY_BASE DPVOICE_REGISTRY_CP DPVOICE_REGISTRY_DPVACM );		
  	}
  
  	DNLeaveCriticalSection( &g_csObjectCountLock );
  
  	return lNewCount;
  }
  
  #undef DPF_MODNAME
  #define DPF_MODNAME "DecrementObjectCount"
  LONG DecrementObjectCount()
  {
  	LONG lNewCount;
  	
  	DNEnterCriticalSection( &g_csObjectCountLock );
  
  	g_lNumObjects--;
  	lNewCount = g_lNumObjects;
  
  	if( g_lNumObjects == 0 )
  	{
  		DPFX(DPFPREP,1,"Freeing Dll Global State" );
  		CDPVCPI::DeInitCompressionList();
  	}
  
  	DNLeaveCriticalSection( &g_csObjectCountLock );
  
  	return lNewCount;	
  }
  