|
|
// Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
//
// regenum.cpp - registration/enumeration part of DMO runtime
//
#include <windows.h>
#include <tchar.h>
#include "dmoreg.h"
#include "guidenum.h"
#include "shlwapi.h"
#include "dmoutils.h"
#define DMO_REGISTRY_HIVE HKEY_CLASSES_ROOT
#define DMO_REGISTRY_PATH TEXT("DirectShow\\MediaObjects")
#define INPUT_TYPES_STR "InputTypes"
#define OUTPUT_TYPES_STR "OutputTypes"
#define SUBTYPES_STR "Subtypes"
#define KEYED_STR "Keyed"
#define CATEGORIES_STR "Categories"
#ifndef CHARS_IN_GUID
#define CHARS_IN_GUID 39
#endif
// Helper copied from shwapi
/*----------------------------------------------------------
Purpose: Recursively delete the key, including all child values and keys. Mimics what RegDeleteKey does in Win95.
Returns: Cond: -- */ DWORD DeleteKeyRecursively( IN HKEY hkey, IN LPCTSTR pszSubKey) { DWORD dwRet; HKEY hkSubKey;
// Open the subkey so we can enumerate any children
dwRet = RegOpenKey(hkey, pszSubKey, &hkSubKey); if (ERROR_SUCCESS == dwRet) { DWORD dwIndex; TCHAR szSubKeyName[MAX_PATH + 1]; DWORD cchSubKeyName = sizeof(szSubKeyName) / sizeof(szSubKeyName[0]); TCHAR szClass[MAX_PATH]; DWORD cbClass = sizeof(szClass) / sizeof(szClass[0]);
// I can't just call RegEnumKey with an ever-increasing index, because
// I'm deleting the subkeys as I go, which alters the indices of the
// remaining subkeys in an implementation-dependent way. In order to
// be safe, I have to count backwards while deleting the subkeys.
// Find out how many subkeys there are
dwRet = RegQueryInfoKey(hkSubKey, szClass, &cbClass, NULL, &dwIndex, // The # of subkeys -- all we need
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (NO_ERROR == dwRet && dwIndex > 0) { // dwIndex is now the count of subkeys, but it needs to be
// zero-based for RegEnumKey, so I'll pre-decrement, rather
// than post-decrement.
while (ERROR_SUCCESS == RegEnumKey(hkSubKey, --dwIndex, szSubKeyName, cchSubKeyName)) { DeleteKeyRecursively(hkSubKey, szSubKeyName); } }
RegCloseKey(hkSubKey);
dwRet = RegDeleteKey(hkey, pszSubKey); }
return dwRet; }
// Automatically calls RegCloseKey when leaving scope
class CAutoHKey { public: CAutoHKey() : m_hKey(NULL) {} ~CAutoHKey() { if (m_hKey) RegCloseKey(m_hKey); } LRESULT Create(HKEY hKey, LPCTSTR szSubKey) { return RegCreateKey(hKey, szSubKey, &m_hKey); } LRESULT Open(HKEY hKey, LPCTSTR szSubKey) { return RegOpenKey(hKey, szSubKey, &m_hKey); } void Close() { if (m_hKey) { RegCloseKey(m_hKey); } m_hKey = NULL; } HKEY m_hKey; HKEY Key() const { return m_hKey; } };
// Automatically calls RegCloseKey when leaving scope
class CAutoCreateHKey { public: CAutoCreateHKey(HKEY hKey, TCHAR* szSubKey, HKEY *phKey) { if (RegCreateKeyEx(hKey, szSubKey, 0, TEXT(""), REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, phKey, NULL) != ERROR_SUCCESS) m_hKey = *phKey = NULL; else m_hKey = *phKey; } ~CAutoCreateHKey() { if (m_hKey) RegCloseKey(m_hKey); } HKEY m_hKey; };
class CAutoOpenHKey { public: CAutoOpenHKey(HKEY hKey, TCHAR* szSubKey, HKEY *phKey, REGSAM samDesired = KEY_READ) { if (RegOpenKeyEx(hKey, szSubKey, 0, samDesired, phKey) != ERROR_SUCCESS) m_hKey = *phKey = NULL; else m_hKey = *phKey; } ~CAutoOpenHKey() { if (m_hKey) RegCloseKey(m_hKey); } HKEY m_hKey; };
HRESULT ReadTypesFromKeys(HKEY hkDMO, LPCTSTR pszTypes, DWORD *pcbData, PVOID *ppvData) { // Collect all the types into 1 value - need to enumerate
// keys and subkeys
LPVOID pMem = CoTaskMemAlloc(0); unsigned int nEntries = 0; DWORD dwTypeIndex; BOOL bSuccess = TRUE; DMO_PARTIAL_MEDIATYPE Type; CAutoHKey hkSrc; if (NOERROR != hkSrc.Open(hkDMO, pszTypes)) { bSuccess = FALSE; } for (dwTypeIndex = 0; bSuccess; dwTypeIndex++) { TCHAR szType[MAX_PATH]; LONG lResult = RegEnumKey(hkSrc.Key(), dwTypeIndex, szType, MAX_PATH); if (NOERROR != lResult) { if (ERROR_NO_MORE_ITEMS != lResult) { bSuccess = FALSE; } break; } if (DMOStrToGuid(szType, &Type.type)) { CAutoHKey kType; kType.Open(hkSrc.Key(), szType); if (NULL == kType.Key()) { bSuccess = FALSE; } else { DWORD dwSubtypeIndex; for (dwSubtypeIndex = 0; bSuccess; dwSubtypeIndex++) { TCHAR szSubtype[MAX_PATH]; lResult = RegEnumKey(kType.Key(), dwSubtypeIndex, szSubtype, MAX_PATH); if (NOERROR != lResult) { if (ERROR_NO_MORE_ITEMS != lResult) { bSuccess = FALSE; } break; } if (DMOStrToGuid(szSubtype, &Type.subtype)) { // Add to our list
LPVOID pMemNew = CoTaskMemRealloc(pMem, (nEntries + 1) * sizeof(DMO_PARTIAL_MEDIATYPE)); if (NULL == pMemNew) { bSuccess = FALSE; } else { pMem = pMemNew; CopyMemory((LPBYTE)pMem + nEntries * sizeof(DMO_PARTIAL_MEDIATYPE), &Type, sizeof(DMO_PARTIAL_MEDIATYPE)); nEntries++; } } } } } } if (bSuccess && nEntries != 0) { *ppvData = pMem; *pcbData = nEntries * sizeof(DMO_PARTIAL_MEDIATYPE); return S_OK; } else { CoTaskMemFree(pMem); return S_FALSE; } }
HRESULT ReadTypes(HKEY hkDMO, LPCTSTR pszTypes, DWORD *pcbData, PVOID *ppvData) { *pcbData = 0;
// Try reading the value first
DWORD cbData; if (NOERROR != RegQueryValueEx(hkDMO, pszTypes, NULL, NULL, NULL, &cbData)) { return ReadTypesFromKeys(hkDMO, pszTypes, pcbData, ppvData); } if (cbData == 0) { return S_OK; } PVOID pvData = (PBYTE)CoTaskMemAlloc(cbData); if (NULL == pvData) { return E_OUTOFMEMORY; } if (NOERROR == RegQueryValueEx(hkDMO, pszTypes, NULL, NULL, (PBYTE)pvData, &cbData)) { *ppvData = pvData; *pcbData = cbData; return S_OK; } else { CoTaskMemFree(pvData); return E_OUTOFMEMORY; } }
/////////////////////////////////////////////////////////////////////////////
//
// DMO Registration code
//
// Registration helper
void CreateObjectGuidKey(HKEY hKey, REFCLSID clsidDMO) { TCHAR szSubkeyName[80];
HKEY hObjectGuidKey; DMOGuidToStr(szSubkeyName, clsidDMO); CAutoCreateHKey kGuid(hKey, szSubkeyName, &hObjectGuidKey); }
// Registration helper
// Registers types\subtypes underneath the object's key
void RegisterTypes(HKEY hObjectKey, TCHAR* szInputOrOutput, ULONG ulTypes, const DMO_PARTIAL_MEDIATYPE* pTypes) { RegSetValueEx(hObjectKey, szInputOrOutput, 0, REG_BINARY, (const BYTE *)pTypes, ulTypes * sizeof(DMO_PARTIAL_MEDIATYPE)); }
//
// Public entry point
//
STDAPI DMORegister( LPCWSTR szName, REFCLSID clsidDMO, REFGUID guidCategory, DWORD dwFlags, // DMO_REGISTERF_XXX
unsigned long ulInTypes, const DMO_PARTIAL_MEDIATYPE *pInTypes, unsigned long ulOutTypes, const DMO_PARTIAL_MEDIATYPE *pOutTypes ) { TCHAR szSubkeyName[80]; if ((clsidDMO == GUID_NULL) || (guidCategory == GUID_NULL)) return E_INVALIDARG;
// Create/open the main DMO key
HKEY hMainKey; CAutoCreateHKey kMain(DMO_REGISTRY_HIVE, DMO_REGISTRY_PATH, &hMainKey); if (hMainKey == NULL) return E_FAIL;
HKEY hCategoriesKey; CAutoCreateHKey kCats(hMainKey, TEXT(CATEGORIES_STR), &hCategoriesKey); if (hCategoriesKey == NULL) return E_FAIL;
// Create/open the category specific subkey underneath the main key
DMOGuidToStr(szSubkeyName, guidCategory); HKEY hCategoryKey; CAutoCreateHKey kCat(hCategoriesKey, szSubkeyName, &hCategoryKey); if (hCategoryKey == NULL) return E_FAIL;
// Deletet the redundant old types keys
DeleteKeyRecursively(hCategoryKey, TEXT(INPUT_TYPES_STR)); DeleteKeyRecursively(hCategoryKey, TEXT(OUTPUT_TYPES_STR));
// If the category key does not have a name yet, add one
DWORD cbName; DWORD dwType;
if ((RegQueryValueEx(hCategoryKey, NULL, NULL, &dwType, NULL, &cbName) != ERROR_SUCCESS) || (cbName <= sizeof(TCHAR)) || (REG_SZ != dwType)) { TCHAR* szName; if (guidCategory == DMOCATEGORY_AUDIO_DECODER) szName = TEXT("Audio decoders"); else if (guidCategory == DMOCATEGORY_AUDIO_ENCODER) szName = TEXT("Audio encoders"); else if (guidCategory == DMOCATEGORY_VIDEO_DECODER) szName = TEXT("Video decoders"); else if (guidCategory == DMOCATEGORY_VIDEO_ENCODER) szName = TEXT("Video encoders"); else if (guidCategory == DMOCATEGORY_AUDIO_EFFECT) szName = TEXT("Audio effects"); else if (guidCategory == DMOCATEGORY_VIDEO_EFFECT) szName = TEXT("Video effects"); else if (guidCategory == DMOCATEGORY_AUDIO_CAPTURE_EFFECT) szName = TEXT("Audio capture effects"); else if (guidCategory == DMOCATEGORY_ACOUSTIC_ECHO_CANCEL) szName = TEXT("Acoustic Echo Canceller"); else if (guidCategory == DMOCATEGORY_AUDIO_NOISE_SUPPRESS) szName = TEXT("Audio Noise Suppressor"); else if (guidCategory == DMOCATEGORY_AGC) szName = TEXT("Automatic Gain Control"); else szName = TEXT("Unknown DMO category"); RegSetValue(hCategoryKey, NULL, REG_SZ, szName, lstrlen(szName) * sizeof(TCHAR)); }
// Create/open the object specific key underneath the category key
DMOGuidToStr(szSubkeyName, clsidDMO);
// Remove the old one
DeleteKeyRecursively(hMainKey, szSubkeyName);
HKEY hObjKey; CAutoCreateHKey kObj(hCategoryKey, szSubkeyName, &hObjKey); if (hObjKey == NULL) return E_FAIL;
// Create/open the object specific key underneath the main key
DMOGuidToStr(szSubkeyName, clsidDMO); // BUGBUG: redundant
HKEY hObjectKey; CAutoCreateHKey kObject(hMainKey, szSubkeyName, &hObjectKey); if (hObjectKey == NULL) return E_FAIL;
// set the default value of the object key to the name of the DMO
#ifdef UNICODE
LPCWSTR sz = szName; #else
char sz[80]; WideCharToMultiByte(0,0,szName,-1,sz,80,NULL,NULL); #endif
if (RegSetValue(hObjectKey, NULL, REG_SZ, sz, lstrlen(sz) * sizeof(TCHAR)) != ERROR_SUCCESS) return E_FAIL;
// If the object is keyed, add a registry value indicating so
if (dwFlags & DMO_REGISTERF_IS_KEYED) { if (RegSetValue(hObjectKey, TEXT(KEYED_STR), REG_SZ, TEXT(""), 0) != ERROR_SUCCESS) return E_FAIL; }
// Register types
if (ulInTypes) { RegisterTypes(hObjectKey, TEXT(INPUT_TYPES_STR), ulInTypes, pInTypes); }
if (ulOutTypes) { RegisterTypes(hObjectKey, TEXT(OUTPUT_TYPES_STR),ulOutTypes,pOutTypes); }
// Nuke the DShow filter cache
DeleteKeyRecursively(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Multimedia\\ActiveMovie\\Filter Cache"));
return NOERROR; }
// helper
void MakeSubkeyName (TCHAR* szSubkeyName, REFGUID guidCategory, REFCLSID clsidDMO) { DMOGuidToStr(szSubkeyName, guidCategory); _tcscat(szSubkeyName, TEXT("\\")); DMOGuidToStr(szSubkeyName + lstrlen(szSubkeyName), clsidDMO); }
//
// Public entry point
//
STDAPI DMOUnregister( REFCLSID clsidDMO, REFGUID guidCategory ) { HRESULT hr;
// open the root DMO key
HKEY hMainKey; CAutoOpenHKey kMain(DMO_REGISTRY_HIVE, DMO_REGISTRY_PATH, &hMainKey, MAXIMUM_ALLOWED); if (hMainKey == NULL) return E_FAIL;
// open the "Categories" key underneath the root key
HKEY hCategoriesKey; CAutoOpenHKey kCats(hMainKey, TEXT(CATEGORIES_STR), &hCategoriesKey, MAXIMUM_ALLOWED); if (hCategoriesKey == NULL) return E_FAIL;
// Iterate through all categories attempting to delete from each one
TCHAR szCategory[80]; DWORD dwIndex = 0; BOOL bDeletedAnything = FALSE; BOOL bDeletedAll = TRUE; DMOGuidToStr(szCategory, guidCategory);
while (RegEnumKey(hCategoriesKey, dwIndex, szCategory, 80) == ERROR_SUCCESS) {
// process the subkey only if it resembles a category GUID
GUID guid; if (DMOStrToGuid(szCategory, &guid)) {
// Try to delete from this category
TCHAR szSubkeyName[256]; MakeSubkeyName(szSubkeyName, guid, clsidDMO); if (guidCategory == GUID_NULL || guid == guidCategory) { if (DeleteKeyRecursively(hCategoriesKey, szSubkeyName) == ERROR_SUCCESS) bDeletedAnything = TRUE; } else { CAutoHKey hk; if (ERROR_FILE_NOT_FOUND != hk.Open(hCategoriesKey, szSubkeyName)) { bDeletedAll = FALSE; } } } dwIndex++; }
if (bDeletedAnything) { hr = S_OK; if (bDeletedAll) { // Now delete this object's key from underneath the root DMO key
TCHAR szGuid[CHARS_IN_GUID]; DMOGuidToStr(szGuid, clsidDMO); if (DeleteKeyRecursively(hMainKey, szGuid) != ERROR_SUCCESS) { hr = S_FALSE; } } } else hr = S_FALSE;
return hr;
} //
// End DMO Registration code
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// DMO Enumeration code
// Some of it leaves room for future improvements in terms of speed
//
// helper
HRESULT ReadName(HKEY hDMOKey, WCHAR szName[80]) { LONG cbSize = 80; #ifdef UNICODE
if (RegQueryValue(hDMOKey, NULL, szName, &cbSize) == ERROR_SUCCESS) return S_OK; #else
char szTmp[80]; if (RegQueryValue(hDMOKey, NULL, szTmp, &cbSize) == ERROR_SUCCESS) { MultiByteToWideChar(0,0,szTmp,-1,szName,80); return S_OK; } #endif
else { szName[0] = L'\0'; // no name - corrupt registry ?
return S_FALSE; } }
// Enumeration helper, does what the name says
void LookupNameAndAddToEnum(HKEY hObjectKey, TCHAR* szGuid, DWORD dwFlags, REFCLSID clsidDMO, CEnumDMOCLSID* pEnum) { // Skip keyed DMOs unless explicitly asked to include them
if (!(dwFlags & DMO_ENUMF_INCLUDE_KEYED)) { // open the DMO's registry key
LONG cbValue; if (RegQueryValue(hObjectKey, TEXT(KEYED_STR), NULL, &cbValue) == ERROR_SUCCESS) return; // DMO is keyed - skip
}
WCHAR szName[80]; if (FAILED(ReadName(hObjectKey, szName))) szName[0] = L'\0';
pEnum->Add(clsidDMO, szName); }
// Check if any of the requested types match
// If no requested types are specified then this is treated
// as a match
BOOL CompareTypes(HKEY hkDMO, unsigned long ulTypes, const DMO_PARTIAL_MEDIATYPE *pTypes, LPCTSTR pszTypesValue) { if (ulTypes == 0) { return TRUE; } DWORD cbData; PVOID pvDMOTypes = NULL; if (S_OK == ReadTypes(hkDMO, pszTypesValue, &cbData, &pvDMOTypes)) { for (unsigned long ulType = 0; ulType < ulTypes; ulType++) { DMO_PARTIAL_MEDIATYPE *pDMOTypes = (DMO_PARTIAL_MEDIATYPE *)pvDMOTypes; while ((PBYTE)(pDMOTypes + 1) <= (PBYTE)pvDMOTypes + cbData) { if (pDMOTypes->type == pTypes[ulType].type || pDMOTypes->type == GUID_NULL || pTypes[ulType].type == GUID_NULL) { if (pTypes[ulType].subtype == GUID_NULL || pDMOTypes->subtype == GUID_NULL || pTypes[ulType].subtype == pDMOTypes->subtype) { CoTaskMemFree(pvDMOTypes); return TRUE; } } pDMOTypes++; } } } CoTaskMemFree(pvDMOTypes); return FALSE; }
// Enumeration helper
HRESULT EnumerateDMOs(HKEY hMainKey, HKEY hCatKey, DWORD dwFlags, unsigned long ulInputTypes, const DMO_PARTIAL_MEDIATYPE *pInputTypes, unsigned long ulOutputTypes, const DMO_PARTIAL_MEDIATYPE *pOutputTypes, CEnumDMOCLSID *pEnum) { DWORD dwIndex = 0; TCHAR szSubkey[80]; while (RegEnumKey(hCatKey, dwIndex, szSubkey, 80) == ERROR_SUCCESS) { // Does this look like an object CLSID ?
CLSID clsidDMO; if (DMOStrToGuid(szSubkey, &clsidDMO)) { // Do the type match?
CAutoHKey hkDMO; if (NOERROR == hkDMO.Open(hMainKey, szSubkey)) { if (CompareTypes(hkDMO.Key(), ulInputTypes, pInputTypes, TEXT(INPUT_TYPES_STR)) && CompareTypes(hkDMO.Key(), ulOutputTypes, pOutputTypes, TEXT(OUTPUT_TYPES_STR))) { LookupNameAndAddToEnum(hkDMO.Key(), szSubkey, dwFlags, clsidDMO, pEnum); } } } dwIndex++; } return S_OK; } //
// Public entry point
//
STDAPI DMOEnum( REFGUID guidCategory, // GUID_NULL for "all"
DWORD dwFlags, // DMO_ENUMF_XXX
unsigned long ulInTypes, const DMO_PARTIAL_MEDIATYPE *pInTypes, // can be NULL only of ulInTypes = 0
unsigned long ulOutTypes, const DMO_PARTIAL_MEDIATYPE *pOutTypes,// can be NULL only of ulOutTypes = 0
IEnumDMO **ppEnum ) { if (ppEnum == NULL) { return E_POINTER; } if (ulInTypes > 0 && pInTypes == NULL || ulOutTypes > 0 && pOutTypes == NULL) { return E_INVALIDARG; }
*ppEnum = NULL;
// open the root key
CAutoHKey kMain; kMain.Open(DMO_REGISTRY_HIVE, DMO_REGISTRY_PATH); if (kMain.Key() == NULL) return E_FAIL;
CEnumDMOCLSID *pEnum = new CEnumDMOCLSID(); if (!pEnum) return E_OUTOFMEMORY;
HRESULT hr = S_OK;
if (guidCategory == GUID_NULL) {
hr = EnumerateDMOs(kMain.Key(), kMain.Key(), dwFlags, ulInTypes, pInTypes, ulOutTypes, pOutTypes, pEnum); } else {
// open the subkey for the specified category and enumerate its subkeys
TCHAR szCategory[CHARS_IN_GUID]; TCHAR szCategoryPath[MAX_PATH]; DMOGuidToStr(szCategory, guidCategory); wsprintf(szCategoryPath, TEXT(CATEGORIES_STR) TEXT("\\%s"), szCategory); CAutoHKey key2; key2.Open(kMain.Key(), szCategoryPath); if (key2.Key()) { hr = EnumerateDMOs(kMain.Key(), key2.Key(), dwFlags, ulInTypes, pInTypes, ulOutTypes, pOutTypes, pEnum); } }
if (SUCCEEDED(hr)) { *ppEnum = (IEnumDMO*) pEnum; hr = S_OK; } else { delete pEnum; } return hr; } // Copy the type information
HRESULT FetchTypeInfo(HKEY hObjKey, LPCTSTR pszTypesValue, unsigned long ulTypesRequested, unsigned long *pulTypesSupplied, DMO_PARTIAL_MEDIATYPE *pTypes) { DWORD cbData; unsigned long ulTypesCopied = 0; PVOID pvData; if (S_OK == ReadTypes(hObjKey, pszTypesValue, &cbData, &pvData)) { ulTypesCopied = min(ulTypesRequested, cbData / sizeof(DMO_PARTIAL_MEDIATYPE)); CopyMemory(pTypes, pvData, ulTypesCopied * sizeof(DMO_PARTIAL_MEDIATYPE)); CoTaskMemFree(pvData); } *pulTypesSupplied = ulTypesCopied; return ulTypesCopied != 0 ? S_OK : S_FALSE; }
// Mediatype helper
HRESULT FetchMediatypeInfo(HKEY hObjKey, unsigned long ulInputTypesRequested, unsigned long *pulInputTypesSupplied, DMO_PARTIAL_MEDIATYPE *pInputTypes, unsigned long ulOutputTypesRequested, unsigned long *pulOutputTypesSupplied, DMO_PARTIAL_MEDIATYPE *pOutputTypes) {
HRESULT hr1 = S_OK; if (ulInputTypesRequested) { hr1 = FetchTypeInfo(hObjKey, TEXT(INPUT_TYPES_STR), ulInputTypesRequested, pulInputTypesSupplied, pInputTypes); } else { *pulInputTypesSupplied = 0; } HRESULT hr2 = S_OK; if (ulOutputTypesRequested) { hr2 = FetchTypeInfo(hObjKey, TEXT(OUTPUT_TYPES_STR), ulOutputTypesRequested, pulOutputTypesSupplied, pOutputTypes); } else { *pulOutputTypesSupplied = 0; } if ((hr1 == S_OK) && (hr2 == S_OK)) return S_OK; else return S_FALSE; }
//
// Public entry point
//
STDAPI DMOGetTypes( REFCLSID clsidDMO, unsigned long ulInputTypesRequested, unsigned long *pulInputTypesSupplied, DMO_PARTIAL_MEDIATYPE *pInputTypes, unsigned long ulOutputTypesRequested, unsigned long *pulOutputTypesSupplied, DMO_PARTIAL_MEDIATYPE *pOutputTypes ) { // open the DMO root registry key
HKEY hMainKey; CAutoOpenHKey kMain(DMO_REGISTRY_HIVE, DMO_REGISTRY_PATH, &hMainKey); if (hMainKey == NULL) return E_FAIL;
// open the object specific guid key
TCHAR szGuid[80]; DMOGuidToStr(szGuid, clsidDMO); HKEY hObjKey; CAutoOpenHKey kObj(hMainKey, szGuid, &hObjKey); if (!hObjKey) return E_FAIL;
return FetchMediatypeInfo(hObjKey, ulInputTypesRequested, pulInputTypesSupplied, pInputTypes, ulOutputTypesRequested, pulOutputTypesSupplied, pOutputTypes); }
STDAPI DMOGetName(REFCLSID clsidDMO, WCHAR szName[80]) { // open the DMO root registry key
HKEY hMainKey; CAutoOpenHKey kMain(DMO_REGISTRY_HIVE, DMO_REGISTRY_PATH, &hMainKey); if (hMainKey == NULL) return E_FAIL;
// open the object specific guid key
TCHAR szGuid[80]; DMOGuidToStr(szGuid, clsidDMO); HKEY hObjKey; CAutoOpenHKey kObj(hMainKey, szGuid, &hObjKey); if (!hObjKey) return E_FAIL;
return ReadName(hObjKey, szName); }
//
// End DMO Enumeration code
//
/////////////////////////////////////////////////////////////////////////////
|