786 lines
24 KiB
C++
786 lines
24 KiB
C++
|
// 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
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|