//------------------------------------------------------------------------------

// File: DllSetup.cpp

//

// Desc: DirectShow base classes.

//

// Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.

//------------------------------------------------------------------------------





#include "streams.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, LPTSTR 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));



    // create key

    //

    HKEY hkey;

    wsprintf(achTemp, TEXT("CLSID\\%ls"), szCLSID);

    LONG lreturn = RegCreateKey(HKEY_CLASSES_ROOT

        , (LPCTSTR)achTemp

        , &hkey);

    if(ERROR_SUCCESS != lreturn) {

        return AmHresultFromWin32(lreturn);

    }



    // set description string

    //



    wsprintf(achTemp, TEXT("%ls"), szDescription);

    lreturn = RegSetValue(hkey

        , (LPCTSTR)NULL

        , REG_SZ

        , achTemp

        , sizeof(achTemp)/sizeof(achTemp[0]));

    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;



    wsprintf(achTemp, TEXT("%ls"), szServerType);

    lreturn = RegCreateKey(hkey

        , achTemp

        , &hsubkey);

    if(ERROR_SUCCESS != lreturn) {

        RegCloseKey(hkey);

        return AmHresultFromWin32(lreturn);

    }



    // set Server string

    //

    wsprintf(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);

    }



    wsprintf(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];

    wsprintf(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;





    // 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(0,                        // default 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

            , 0 // 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

            , sizeof(achFileName)/sizeof(TCHAR));

    }



    //

    // 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

            , sizeof(achFileName)/sizeof(TCHAR));

    }



    // 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;

}



