//------------------------------------------------------------------------------
// File: DllSetup.cpp
//
// Desc: DirectShow base classes.
//
// Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------------------------
 
 
#include "streams.h"
#include <strsafe.h>
 
//---------------------------------------------------------------------------
// defines
 
#define MAX_KEY_LEN  260
 
 
//---------------------------------------------------------------------------
// externally defined functions/variable
 
extern int g_cTemplates;
extern CFactoryTemplate g_Templates[];
 
//---------------------------------------------------------------------------
//
// EliminateSubKey
//
// Try to enumerate all keys under this one.
// if we find anything, delete it completely.
// Otherwise just delete it.
//
// note - this was pinched/duplicated from
// Filgraph\Mapper.cpp - so should it be in
// a lib somewhere?
//
//---------------------------------------------------------------------------
 
STDAPI
EliminateSubKey( HKEY hkey, LPCTSTR strSubKey )
{
  HKEY hk;
  if (0 == lstrlen(strSubKey) ) {
      // defensive approach
      return E_FAIL;
  }
 
  LONG lreturn = RegOpenKeyEx( hkey
                             , strSubKey
                             , 0
                             , MAXIMUM_ALLOWED
                             , &hk );
 
  ASSERT(    lreturn == ERROR_SUCCESS
          || lreturn == ERROR_FILE_NOT_FOUND
          || lreturn == ERROR_INVALID_HANDLE );
 
  if( ERROR_SUCCESS == lreturn )
  {
    // Keep on enumerating the first (zero-th)
    // key and deleting that
 
    for( ; ; )
    {
      TCHAR Buffer[MAX_KEY_LEN];
      DWORD dw = MAX_KEY_LEN;
      FILETIME ft;
 
      lreturn = RegEnumKeyEx( hk
                            , 0
                            , Buffer
                            , &dw
                            , NULL
                            , NULL
                            , NULL
                            , &ft);
 
      ASSERT(    lreturn == ERROR_SUCCESS
              || lreturn == ERROR_NO_MORE_ITEMS );
 
      if( ERROR_SUCCESS == lreturn )
      {
        EliminateSubKey(hk, Buffer);
      }
      else
      {
        break;
      }
    }
 
    RegCloseKey(hk);
    RegDeleteKey(hkey, strSubKey);
  }
 
  return NOERROR;
}
 
 
//---------------------------------------------------------------------------
//
// AMovieSetupRegisterServer()
//
// registers specfied file "szFileName" as server for
// CLSID "clsServer".  A description is also required.
// The ThreadingModel and ServerType are optional, as
// they default to InprocServer32 (i.e. dll) and Both.
//
//---------------------------------------------------------------------------
 
STDAPI
AMovieSetupRegisterServer( CLSID   clsServer
                         , LPCWSTR szDescription
                         , LPCWSTR szFileName
                         , LPCWSTR szThreadingModel = L"Both"
                         , LPCWSTR szServerType     = L"InprocServer32" )
{
  // temp buffer
  //
  TCHAR achTemp[MAX_PATH];
 
  // convert CLSID uuid to string and write
  // out subkey as string - CLSID\{}
  //
  OLECHAR szCLSID[CHARS_IN_GUID];
  HRESULT hr = StringFromGUID2( clsServer
                              , szCLSID
                              , CHARS_IN_GUID );
  ASSERT( SUCCEEDED(hr) );
  UNREFERENCED_PARAMETER(hr);
 
  // create key
  //
  HKEY hkey;
  (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("CLSID\\%ls"), szCLSID );
  LONG lreturn = RegCreateKey( HKEY_CLASSES_ROOT
                             , (LPCTSTR)achTemp
                             , &hkey              );
  if( ERROR_SUCCESS != lreturn )
  {
    return AmHresultFromWin32(lreturn);
  }
 
  // set description string
  //
 
  (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szDescription );
  lreturn = RegSetValue( hkey
                       , (LPCTSTR)NULL
                       , REG_SZ
                       , achTemp
                       , sizeof(achTemp) );
  if( ERROR_SUCCESS != lreturn )
  {
    RegCloseKey( hkey );
    return AmHresultFromWin32(lreturn);
  }
 
  // create CLSID\\{"CLSID"}\\"ServerType" key,
  // using key to CLSID\\{"CLSID"} passed back by
  // last call to RegCreateKey().
  //
  HKEY hsubkey;
 
  (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szServerType );
  lreturn = RegCreateKey( hkey
                        , achTemp
                        , &hsubkey     );
  if( ERROR_SUCCESS != lreturn )
  {
    RegCloseKey( hkey );
    return AmHresultFromWin32(lreturn);
  }
 
  // set Server string
  //
  (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szFileName );
  lreturn = RegSetValue( hsubkey
                       , (LPCTSTR)NULL
                       , REG_SZ
                       , (LPCTSTR)achTemp
                       , sizeof(TCHAR) * (lstrlen(achTemp)+1) );
  if( ERROR_SUCCESS != lreturn )
  {
    RegCloseKey( hkey );
    RegCloseKey( hsubkey );
    return AmHresultFromWin32(lreturn);
  }
 
  (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szThreadingModel );
  lreturn = RegSetValueEx( hsubkey
                         , TEXT("ThreadingModel")
                         , 0L
                         , REG_SZ
                         , (CONST BYTE *)achTemp
                         , sizeof(TCHAR) * (lstrlen(achTemp)+1) );
 
  // close hkeys
  //
  RegCloseKey( hkey );
  RegCloseKey( hsubkey );
 
  // and return
  //
  return HRESULT_FROM_WIN32(lreturn);
 
}
 
 
//---------------------------------------------------------------------------
//
// AMovieSetupUnregisterServer()
//
// default ActiveMovie dll setup function
// - to use must be called from an exported
//   function named DllRegisterServer()
//
//---------------------------------------------------------------------------
 
STDAPI
AMovieSetupUnregisterServer( CLSID clsServer )
{
  // convert CLSID uuid to string and write
  // out subkey CLSID\{}
  //
  OLECHAR szCLSID[CHARS_IN_GUID];
  HRESULT hr = StringFromGUID2( clsServer
                              , szCLSID
                              , CHARS_IN_GUID );
  ASSERT( SUCCEEDED(hr) );
 
  TCHAR achBuffer[MAX_KEY_LEN];
  (void)StringCchPrintf( achBuffer, NUMELMS(achBuffer), TEXT("CLSID\\%ls"), szCLSID );
 
  // delete subkey
  //
 
  hr = EliminateSubKey( HKEY_CLASSES_ROOT, achBuffer );
  ASSERT( SUCCEEDED(hr) );
 
  // return
  //
  return NOERROR;
}
 
 
//---------------------------------------------------------------------------
//
// AMovieSetupRegisterFilter through IFilterMapper2
//
//---------------------------------------------------------------------------
 
STDAPI
AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata
                          , IFilterMapper2 *                 pIFM2
                          , BOOL                             bRegister  )
{
  DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter")));
 
  // check we've got data
  //
  if( NULL == psetupdata ) return S_FALSE;
 
  const CLSID *filterCategory = &psetupdata->filterCategory;
 
  // unregister filter
  // (as pins are subkeys of filter's CLSID key
  // they do not need to be removed separately).
  //
  DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter")));
  HRESULT hr = pIFM2->UnregisterFilter(
      filterCategory,           // category
      0,                        // default instance name
      *psetupdata->clsID );
 
 
  if( bRegister )
  {
    REGFILTER2 rf2;
    rf2.dwVersion = 1;
    rf2.dwMerit = psetupdata->dwMerit;
    rf2.cPins = psetupdata->nPins;
    rf2.rgPins = psetupdata->lpPin;
    
    // register filter
    //
    DbgLog((LOG_TRACE, 3, TEXT("= = register filter")));
    hr = pIFM2->RegisterFilter(*psetupdata->clsID
                             , psetupdata->strName
                             , 0 // moniker
                             , filterCategory // category
                             , NULL // instance
                             , &rf2);
  }
 
  // handle one acceptable "error" - that
  // of filter not being registered!
  // (couldn't find a suitable #define'd
  // name for the error!)
  //
  if( 0x80070002 == hr)
    return NOERROR;
  else
    return hr;
}
 
 
//---------------------------------------------------------------------------
//
// RegisterAllServers()
//
//---------------------------------------------------------------------------
 
STDAPI
RegisterAllServers( LPCWSTR szFileName, BOOL bRegister )
{
  HRESULT hr = NOERROR;
 
  for( int i = 0; i < g_cTemplates; i++ )
  {
    // get i'th template
    //
    const CFactoryTemplate *pT = &g_Templates[i];
 
    DbgLog((LOG_TRACE, 2, TEXT("- - register %ls"),
           (LPCWSTR)pT->m_Name ));
 
    // register CLSID and InprocServer32
    //
    if( bRegister )
    {
      hr = AMovieSetupRegisterServer( *(pT->m_ClsID)
                                    , (LPCWSTR)pT->m_Name
                                    , szFileName );
    }
    else
    {
      hr = AMovieSetupUnregisterServer( *(pT->m_ClsID) );
    }
 
    // check final error for this pass
    // and break loop if we failed
    //
    if( FAILED(hr) )
      break;
  }
 
  return hr;
}
 
 
//---------------------------------------------------------------------------
//
// AMovieDllRegisterServer2()
//
// default ActiveMovie dll setup function
// - to use must be called from an exported
//   function named DllRegisterServer()
//
// this function is table driven using the
// static members of the CFactoryTemplate
// class defined in the dll.
//
// it registers the Dll as the InprocServer32
// and then calls the IAMovieSetup.Register
// method.
//
//---------------------------------------------------------------------------
 
STDAPI
AMovieDllRegisterServer2( BOOL bRegister )
{
  HRESULT hr = NOERROR;
 
  DbgLog((LOG_TRACE, 2, TEXT("AMovieDllRegisterServer2()")));
 
  // get file name (where g_hInst is the
  // instance handle of the filter dll)
  //
  WCHAR achFileName[MAX_PATH];
 
  // WIN95 doesn't support GetModuleFileNameW
  //
  {
    char achTemp[MAX_PATH];
 
    DbgLog((LOG_TRACE, 2, TEXT("- get module file name")));
 
    // g_hInst handle is set in our dll entry point. Make sure
    // DllEntryPoint in dllentry.cpp is called
    ASSERT(g_hInst != 0);
 
    if( 0 == GetModuleFileNameA( g_hInst
                              , achTemp
                              , sizeof(achTemp) ) )
    {
      // we've failed!
      DWORD dwerr = GetLastError();
      return AmHresultFromWin32(dwerr);
    }
 
    MultiByteToWideChar( CP_ACP
                       , 0L
                       , achTemp
                       , lstrlenA(achTemp) + 1
                       , achFileName
                       , NUMELMS(achFileName) );
  }
 
  //
  // first registering, register all OLE servers
  //
  if( bRegister )
  {
    DbgLog((LOG_TRACE, 2, TEXT("- register OLE Servers")));
    hr = RegisterAllServers( achFileName, TRUE );
  }
 
  //
  // next, register/unregister all filters
  //
 
  if( SUCCEEDED(hr) )
  {
    // init is ref counted so call just in case
    // we're being called cold.
    //
    DbgLog((LOG_TRACE, 2, TEXT("- CoInitialize")));
    hr = CoInitialize( (LPVOID)NULL );
    ASSERT( SUCCEEDED(hr) );
 
    // get hold of IFilterMapper2
    //
    DbgLog((LOG_TRACE, 2, TEXT("- obtain IFilterMapper2")));
    IFilterMapper2 *pIFM2 = 0;
    IFilterMapper *pIFM = 0;
    hr = CoCreateInstance( CLSID_FilterMapper2
                         , NULL
                         , CLSCTX_INPROC_SERVER
                         , IID_IFilterMapper2
                         , (void **)&pIFM2       );
    if(FAILED(hr))
    {
        DbgLog((LOG_TRACE, 2, TEXT("- trying IFilterMapper instead")));
 
        hr = CoCreateInstance(
            CLSID_FilterMapper,
            NULL,
            CLSCTX_INPROC_SERVER,
            IID_IFilterMapper,
            (void **)&pIFM);
    }
    if( SUCCEEDED(hr) )
    {
      // scan through array of CFactoryTemplates
      // registering servers and filters.
      //
      DbgLog((LOG_TRACE, 2, TEXT("- register Filters")));
      for( int i = 0; i < g_cTemplates; i++ )
      {
        // get i'th template
        //
        const CFactoryTemplate *pT = &g_Templates[i];
 
        if( NULL != pT->m_pAMovieSetup_Filter )
        {
          DbgLog((LOG_TRACE, 2, TEXT("- - register %ls"), (LPCWSTR)pT->m_Name ));
 
          if(pIFM2)
          {
              hr = AMovieSetupRegisterFilter2( pT->m_pAMovieSetup_Filter, pIFM2, bRegister );
          }
          else
          {
              hr = AMovieSetupRegisterFilter( pT->m_pAMovieSetup_Filter, pIFM, bRegister );
          }
        }
 
        // check final error for this pass
        // and break loop if we failed
        //
        if( FAILED(hr) )
          break;
      }
 
      // release interface
      //
      if(pIFM2)
          pIFM2->Release();
      else
          pIFM->Release();
 
    }
 
    // and clear up
    //
    CoFreeUnusedLibraries();
    CoUninitialize();
  }
 
  //
  // if unregistering, unregister all OLE servers
  //
  if( SUCCEEDED(hr) && !bRegister )
  {
    DbgLog((LOG_TRACE, 2, TEXT("- register OLE Servers")));
    hr = RegisterAllServers( achFileName, FALSE );
  }
 
  DbgLog((LOG_TRACE, 2, TEXT("- return %0x"), hr));
  return hr;
}
 
 
//---------------------------------------------------------------------------
//
// AMovieDllRegisterServer()
//
// default ActiveMovie dll setup function
// - to use must be called from an exported
//   function named DllRegisterServer()
//
// this function is table driven using the
// static members of the CFactoryTemplate
// class defined in the dll.
//
// it registers the Dll as the InprocServer32
// and then calls the IAMovieSetup.Register
// method.
//
//---------------------------------------------------------------------------
 
 
STDAPI
AMovieDllRegisterServer( void )
{
  HRESULT hr = NOERROR;
 
  // get file name (where g_hInst is the
  // instance handle of the filter dll)
  //
  WCHAR achFileName[MAX_PATH];
 
  {
    // WIN95 doesn't support GetModuleFileNameW
    //
    char achTemp[MAX_PATH];
 
    if( 0 == GetModuleFileNameA( g_hInst
                              , achTemp
                              , sizeof(achTemp) ) )
    {
      // we've failed!
      DWORD dwerr = GetLastError();
      return AmHresultFromWin32(dwerr);
    }
 
    MultiByteToWideChar( CP_ACP
                       , 0L
                       , achTemp
                       , lstrlenA(achTemp) + 1
                       , achFileName
                       , NUMELMS(achFileName) );
  }
 
  // scan through array of CFactoryTemplates
  // registering servers and filters.
  //
  for( int i = 0; i < g_cTemplates; i++ )
  {
    // get i'th template
    //
    const CFactoryTemplate *pT = &g_Templates[i];
 
    // register CLSID and InprocServer32
    //
    hr = AMovieSetupRegisterServer( *(pT->m_ClsID)
                                  , (LPCWSTR)pT->m_Name
                                  , achFileName );
 
    // instantiate all servers and get hold of
    // IAMovieSetup, if implemented, and call
    // IAMovieSetup.Register() method
    //
    if( SUCCEEDED(hr) && (NULL != pT->m_lpfnNew) )
    {
      // instantiate object
      //
      PAMOVIESETUP psetup;
      hr = CoCreateInstance( *(pT->m_ClsID)
                           , 0
                           , CLSCTX_INPROC_SERVER
                           , IID_IAMovieSetup
                           , reinterpret_cast<void**>(&psetup) );
      if( SUCCEEDED(hr) )
      {
        hr = psetup->Unregister();
        if( SUCCEEDED(hr) )
          hr = psetup->Register();
        psetup->Release();
      }
      else
      {
        if(    (E_NOINTERFACE      == hr )
            || (VFW_E_NEED_OWNER == hr ) )
          hr = NOERROR;
      }
    }
 
    // check final error for this pass
    // and break loop if we failed
    //
    if( FAILED(hr) )
      break;
 
  } // end-for
 
  return hr;
}
 
 
//---------------------------------------------------------------------------
//
// AMovieDllUnregisterServer()
//
// default ActiveMovie dll uninstall function
// - to use must be called from an exported
//   function named DllRegisterServer()
//
// this function is table driven using the
// static members of the CFactoryTemplate
// class defined in the dll.
//
// it calls the IAMovieSetup.Unregister
// method and then unregisters the Dll
// as the InprocServer32
//
//---------------------------------------------------------------------------
 
STDAPI
AMovieDllUnregisterServer()
{
  // initialize return code
  //
  HRESULT hr = NOERROR;
 
  // scan through CFactory template and unregister
  // all OLE servers and filters.
  //
  for( int i = g_cTemplates; i--; )
  {
    // get i'th template
    //
    const CFactoryTemplate *pT = &g_Templates[i];
 
    // check method exists
    //
    if( NULL != pT->m_lpfnNew )
    {
      // instantiate object
      //
      PAMOVIESETUP psetup;
      hr = CoCreateInstance( *(pT->m_ClsID)
                           , 0
                           , CLSCTX_INPROC_SERVER
                           , IID_IAMovieSetup
                           , reinterpret_cast<void**>(&psetup) );
      if( SUCCEEDED(hr) )
      {
        hr = psetup->Unregister();
        psetup->Release();
      }
      else
      {
        if(    (E_NOINTERFACE      == hr )
            || (VFW_E_NEED_OWNER == hr ) )
           hr = NOERROR;
      }
    }
 
    // unregister CLSID and InprocServer32
    //
    if( SUCCEEDED(hr) )
    {
      hr = AMovieSetupUnregisterServer( *(pT->m_ClsID) );
    }
 
    // check final error for this pass
    // and break loop if we failed
    //
    if( FAILED(hr) )
      break;
  }
 
  return hr;
}

V303 The function 'lstrlen' is deprecated in the Win64 system. It is safer to use the 'wcslen' function.

V303 The function 'lstrlen' is deprecated in the Win64 system. It is safer to use the 'wcslen' function.

V303 The function 'lstrlen' is deprecated in the Win64 system. It is safer to use the 'wcslen' function.

V303 The function 'lstrlen' is deprecated in the Win64 system. It is safer to use the 'strlen' function.

V303 The function 'lstrlen' is deprecated in the Win64 system. It is safer to use the 'strlen' function.

V522 There might be dereferencing of a potential null pointer 'pIFM'.

V805 Decreased performance. It is inefficient to identify an empty string by using 'lstrlenW(str) == 0' construct. A more efficient way is to check: str[0] == '\0'.

V813 Decreased performance. The 'clsServer' argument should probably be rendered as a constant reference.

V813 Decreased performance. The 'clsServer' argument should probably be rendered as a constant reference.