topical media & game development

talk show tell print

hush-src-multi-BaseClasses-dllentry.cpp / cpp



  //------------------------------------------------------------------------------
  // File: DllEntry.cpp
  //
  // Desc: DirectShow base classes - implements classes used to support dll
  //       entry points for COM objects.
  //
  // Copyright (c) Microsoft Corporation.  All rights reserved.
  //------------------------------------------------------------------------------
  
  include <streams.h>
  include <initguid.h>
  
  ifdef DEBUG
  ifdef UNICODE
  ifndef _UNICODE
  define _UNICODE
  endif // _UNICODE
  endif // UNICODE
  
  include <tchar.h>
  endif // DEBUG
  
  extern CFactoryTemplate g_Templates[];
  extern int g_cTemplates;
  
  HINSTANCE g_hInst;
  DWORD          g_amPlatform;                // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx)
  OSVERSIONINFO g_osInfo;
  
  //
  // an instance of this is created by the DLLGetClassObject entrypoint
  // it uses the CFactoryTemplate object it is given to support the
  // IClassFactory interface
  
  class CClassFactory : public IClassFactory, public CBaseObject
  {
  
  private:
      const CFactoryTemplate *const m_pTemplate;
  
      ULONG m_cRef;
  
      static int m_cLocked;
  public:
      CClassFactory(const CFactoryTemplate *);
  
      // IUnknown
      STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
      STDMETHODIMP_(ULONG)AddRef();
      STDMETHODIMP_(ULONG)Release();
  
      // IClassFactory
      STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **pv);
      STDMETHODIMP LockServer(BOOL fLock);
  
      // allow DLLGetClassObject to know about global server lock status
      static BOOL IsLocked() {
          return (m_cLocked > 0);
      };
  };
  
  // process-wide dll locked state
  int CClassFactory::m_cLocked = 0;
  
  CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate)
  : CBaseObject(NAME("Class Factory"))
  , m_cRef(0)
  , m_pTemplate(pTemplate)
  {
  }
  
  STDMETHODIMP
  CClassFactory::QueryInterface(REFIID riid,void **ppv)
  {
      CheckPointer(ppv,E_POINTER)
      ValidateReadWritePtr(ppv,sizeof(PVOID));
      *ppv = NULL;
  
      // any interface on this object is the object pointer.
      if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) {
          *ppv = (LPVOID) this;
          // AddRef returned interface pointer
          ((LPUNKNOWN) *ppv)->AddRef();
          return NOERROR;
      }
  
      return ResultFromScode(E_NOINTERFACE);
  }
  
  STDMETHODIMP_(ULONG)
  CClassFactory::AddRef()
  {
      return ++m_cRef;
  }
  
  STDMETHODIMP_(ULONG)
  CClassFactory::Release()
  {
      if (--m_cRef == 0) {
          delete this;
          return 0;
      } else {
          return m_cRef;
      }
  }
  
  STDMETHODIMP
  CClassFactory::CreateInstance(
      LPUNKNOWN pUnkOuter,
      REFIID riid,
      void **pv)
  {
      CheckPointer(pv,E_POINTER)
      ValidateReadWritePtr(pv,sizeof(void *));
  
      /* Enforce the normal OLE rules regarding interfaces and delegation */
  
      if (pUnkOuter != NULL) {
          if (IsEqualIID(riid,IID_IUnknown) == FALSE) {
              return ResultFromScode(E_NOINTERFACE);
          }
      }
  
      /* Create the new object through the derived class's create function */
  
      HRESULT hr = NOERROR;
      CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr);
  
      if (pObj == NULL) {
          if (SUCCEEDED(hr)) {
              hr = E_OUTOFMEMORY;
          }
          return hr;
      }
  
      /* Delete the object if we got a construction error */
  
      if (FAILED(hr)) {
          delete pObj;
          return hr;
      }
  
      /* Get a reference counted interface on the object */
  
      /* We wrap the non-delegating QI with NDAddRef & NDRelease. */
      /* This protects any outer object from being prematurely    */
      /* released by an inner object that may have to be created  */
      /* in order to supply the requested interface.              */
      pObj->NonDelegatingAddRef();
      hr = pObj->NonDelegatingQueryInterface(riid, pv);
      pObj->NonDelegatingRelease();
      /* Note that if NonDelegatingQueryInterface fails, it will  */
      /* not increment the ref count, so the NonDelegatingRelease */
      /* will drop the ref back to zero and the object will "self-*/
      /* destruct".  Hence we don't need additional tidy-up code  */
      /* to cope with NonDelegatingQueryInterface failing.        */
  
      if (SUCCEEDED(hr)) {
          ASSERT(*pv);
      }
  
      return hr;
  }
  
  STDMETHODIMP
  CClassFactory::LockServer(BOOL fLock)
  {
      if (fLock) {
          m_cLocked++;
      } else {
          m_cLocked--;
      }
      return NOERROR;
  }
  
  // --- COM entrypoints -----------------------------------------
  
  //called by COM to get the class factory object for a given class
  STDAPI
  DllGetClassObject(
      REFCLSID rClsID,
      REFIID riid,
      void **pv)
  {
      if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) {
              return E_NOINTERFACE;
      }
  
      // traverse the array of templates looking for one with this
      // class id
      for (int i = 0; i < g_cTemplates; i++) {
          const CFactoryTemplate * pT = &g_Templates[i];
          if (pT->IsClassID(rClsID)) {
  
              // found a template - make a class factory based on this
              // template
  
              *pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT);
              if (*pv == NULL) {
                  return E_OUTOFMEMORY;
              }
              ((LPUNKNOWN)*pv)->AddRef();
              return NOERROR;
          }
      }
      return CLASS_E_CLASSNOTAVAILABLE;
  }
  
  //
  //  Call any initialization routines
  //
  void
  DllInitClasses(BOOL bLoading)
  {
      int i;
  
      // traverse the array of templates calling the init routine
      // if they have one
      for (i = 0; i < g_cTemplates; i++) {
          const CFactoryTemplate * pT = &g_Templates[i];
          if (pT->m_lpfnInit != NULL) {
              (*pT->m_lpfnInit)(bLoading, pT->m_ClsID);
          }
      }
  
  }
  
  // called by COM to determine if this dll can be unloaded
  // return ok unless there are outstanding objects or a lock requested
  // by IClassFactory::LockServer
  //
  // CClassFactory has a static function that can tell us about the locks,
  // and CCOMObject has a static function that can tell us about the active
  // object count
  STDAPI
  DllCanUnloadNow()
  {
      DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = \%d, Active objects = \%d"),
          CClassFactory::IsLocked(),
          CBaseObject::ObjectsActive()));
  
      if (CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) {
          return S_FALSE;
      } else {
          return S_OK;
      }
  }
  
  // --- standard WIN32 entrypoints --------------------------------------
  
  extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
  
  BOOL WINAPI
  DllEntryPoint(HINSTANCE hInstance, ULONG ulReason, LPVOID pv)
  {
  ifdef DEBUG
      extern bool g_fDbgInDllEntryPoint;
      g_fDbgInDllEntryPoint = true;
  endif
  
      switch (ulReason)
      {
  
      case DLL_PROCESS_ATTACH:
          DisableThreadLibraryCalls(hInstance);
          DbgInitialise(hInstance);
  
              {
                  // The platform identifier is used to work out whether
                  // full unicode support is available or not.  Hence the
                  // default will be the lowest common denominator - i.e. N/A
                  g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails
      
                  g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo);
                  if (GetVersionEx(&g_osInfo)) {
                      g_amPlatform = g_osInfo.dwPlatformId;
                  } else {
                      DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95")));
                  }
              }
  
          g_hInst = hInstance;
          DllInitClasses(TRUE);
          break;
  
      case DLL_PROCESS_DETACH:
          DllInitClasses(FALSE);
  
  ifdef DEBUG
          if (CBaseObject::ObjectsActive()) {
              DbgSetModuleLevel(LOG_MEMORY, 2);
              TCHAR szInfo[512];
              extern TCHAR m_ModuleName[];     // Cut down module name
  
              TCHAR FullName[_MAX_PATH];      // Load the full path and module name
              TCHAR *pName;                   // Searches from the end for a backslash
  
              GetModuleFileName(NULL,FullName,_MAX_PATH);
              pName = _tcsrchr(FullName,'\\');
              if (pName == NULL) {
                  pName = FullName;
              } else {
                  pName++;
              }
  
              DWORD cch = wsprintf(szInfo, TEXT("Executable: \%s  Pid \%x  Tid \%x. "),
                              pName, GetCurrentProcessId(), GetCurrentThreadId());
  
              wsprintf(szInfo+cch, TEXT("Module \%s, \%d objects left active!"),
                       m_ModuleName, CBaseObject::ObjectsActive());
              DbgAssert(szInfo, TEXT(__FILE__),__LINE__);
  
              // If running remotely wait for the Assert to be acknowledged
              // before dumping out the object register
              DbgDumpObjectRegister();
          }
          DbgTerminate();
  endif
          break;
      }
  
  ifdef DEBUG
      g_fDbgInDllEntryPoint = false;
  endif
      return TRUE;
  }
  
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.