668 lines
20 KiB
C++
668 lines
20 KiB
C++
/****************************************************************************
|
|
*
|
|
* File: showinfo.cpp
|
|
* Project: DxDiag (DirectX Diagnostic Tool)
|
|
* Author: Mike Anderson (manders@microsoft.com)
|
|
* Purpose: Gather information about DirectShow on this machine
|
|
*
|
|
* (C) Copyright 2001 Microsoft Corp. All rights reserved.
|
|
*
|
|
****************************************************************************/
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <strmif.h> // Generated IDL header file for streams interfaces
|
|
#include <uuids.h> // declaration of type GUIDs and well-known clsids
|
|
#include <assert.h>
|
|
#include "sysinfo.h"
|
|
#include "fileinfo.h" // for GetFileVersion
|
|
#include "showinfo.h"
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* Helper IAMFilterData - cut and paste from dshow\h\fil_data.c
|
|
*
|
|
****************************************************************************/
|
|
/* verify that the <rpcndr.h> version is high enough to compile this file*/
|
|
#ifndef __REQUIRED_RPCNDR_H_VERSION__
|
|
#define __REQUIRED_RPCNDR_H_VERSION__ 440
|
|
#endif
|
|
|
|
#include "rpc.h"
|
|
#include "rpcndr.h"
|
|
|
|
#ifndef __RPCNDR_H_VERSION__
|
|
#error this stub requires an updated version of <rpcndr.h>
|
|
#endif // __RPCNDR_H_VERSION__
|
|
|
|
#ifndef COM_NO_WINDOWS_H
|
|
#include "windows.h"
|
|
#include "ole2.h"
|
|
#endif /*COM_NO_WINDOWS_H*/
|
|
|
|
#ifndef __fil_data_h__
|
|
#define __fil_data_h__
|
|
|
|
#ifdef __cplusplus
|
|
extern "C"{
|
|
#endif
|
|
|
|
/* Forward Declarations */
|
|
|
|
#ifndef __IAMFilterData_FWD_DEFINED__
|
|
#define __IAMFilterData_FWD_DEFINED__
|
|
typedef interface IAMFilterData IAMFilterData;
|
|
#endif /* __IAMFilterData_FWD_DEFINED__ */
|
|
|
|
|
|
/* header files for imported files */
|
|
#include "unknwn.h"
|
|
#include "strmif.h"
|
|
|
|
void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t);
|
|
void __RPC_USER MIDL_user_free( void __RPC_FAR * );
|
|
|
|
/* interface __MIDL_itf_fil_data_0000 */
|
|
/* [local] */
|
|
|
|
|
|
|
|
|
|
extern RPC_IF_HANDLE __MIDL_itf_fil_data_0000_v0_0_c_ifspec;
|
|
extern RPC_IF_HANDLE __MIDL_itf_fil_data_0000_v0_0_s_ifspec;
|
|
|
|
#ifndef __IAMFilterData_INTERFACE_DEFINED__
|
|
#define __IAMFilterData_INTERFACE_DEFINED__
|
|
|
|
/* interface IAMFilterData */
|
|
/* [unique][uuid][object] */
|
|
|
|
|
|
EXTERN_C const IID IID_IAMFilterData;
|
|
|
|
#if defined(__cplusplus) && !defined(CINTERFACE)
|
|
|
|
MIDL_INTERFACE("97f7c4d4-547b-4a5f-8332-536430ad2e4d")
|
|
IAMFilterData : public IUnknown
|
|
{
|
|
public:
|
|
virtual HRESULT STDMETHODCALLTYPE ParseFilterData(
|
|
/* [size_is][in] */ BYTE __RPC_FAR *rgbFilterData,
|
|
/* [in] */ ULONG cb,
|
|
/* [out] */ BYTE __RPC_FAR *__RPC_FAR *prgbRegFilter2) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE CreateFilterData(
|
|
/* [in] */ REGFILTER2 __RPC_FAR *prf2,
|
|
/* [out] */ BYTE __RPC_FAR *__RPC_FAR *prgbFilterData,
|
|
/* [out] */ ULONG __RPC_FAR *pcb) = 0;
|
|
|
|
};
|
|
|
|
#else /* C style interface */
|
|
|
|
typedef struct IAMFilterDataVtbl
|
|
{
|
|
BEGIN_INTERFACE
|
|
|
|
HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )(
|
|
IAMFilterData __RPC_FAR * This,
|
|
/* [in] */ REFIID riid,
|
|
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
|
|
|
|
ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )(
|
|
IAMFilterData __RPC_FAR * This);
|
|
|
|
ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )(
|
|
IAMFilterData __RPC_FAR * This);
|
|
|
|
HRESULT ( STDMETHODCALLTYPE __RPC_FAR *ParseFilterData )(
|
|
IAMFilterData __RPC_FAR * This,
|
|
/* [size_is][in] */ BYTE __RPC_FAR *rgbFilterData,
|
|
/* [in] */ ULONG cb,
|
|
/* [out] */ BYTE __RPC_FAR *__RPC_FAR *prgbRegFilter2);
|
|
|
|
HRESULT ( STDMETHODCALLTYPE __RPC_FAR *CreateFilterData )(
|
|
IAMFilterData __RPC_FAR * This,
|
|
/* [in] */ REGFILTER2 __RPC_FAR *prf2,
|
|
/* [out] */ BYTE __RPC_FAR *__RPC_FAR *prgbFilterData,
|
|
/* [out] */ ULONG __RPC_FAR *pcb);
|
|
|
|
END_INTERFACE
|
|
} IAMFilterDataVtbl;
|
|
|
|
interface IAMFilterData
|
|
{
|
|
CONST_VTBL struct IAMFilterDataVtbl __RPC_FAR *lpVtbl;
|
|
};
|
|
|
|
|
|
|
|
#ifdef COBJMACROS
|
|
|
|
|
|
#define IAMFilterData_QueryInterface(This,riid,ppvObject) \
|
|
(This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
|
|
|
|
#define IAMFilterData_AddRef(This) \
|
|
(This)->lpVtbl -> AddRef(This)
|
|
|
|
#define IAMFilterData_Release(This) \
|
|
(This)->lpVtbl -> Release(This)
|
|
|
|
|
|
#define IAMFilterData_ParseFilterData(This,rgbFilterData,cb,prgbRegFilter2) \
|
|
(This)->lpVtbl -> ParseFilterData(This,rgbFilterData,cb,prgbRegFilter2)
|
|
|
|
#define IAMFilterData_CreateFilterData(This,prf2,prgbFilterData,pcb) \
|
|
(This)->lpVtbl -> CreateFilterData(This,prf2,prgbFilterData,pcb)
|
|
|
|
#endif /* COBJMACROS */
|
|
|
|
|
|
#endif /* C style interface */
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE IAMFilterData_ParseFilterData_Proxy(
|
|
IAMFilterData __RPC_FAR * This,
|
|
/* [size_is][in] */ BYTE __RPC_FAR *rgbFilterData,
|
|
/* [in] */ ULONG cb,
|
|
/* [out] */ BYTE __RPC_FAR *__RPC_FAR *prgbRegFilter2);
|
|
|
|
|
|
void __RPC_STUB IAMFilterData_ParseFilterData_Stub(
|
|
IRpcStubBuffer *This,
|
|
IRpcChannelBuffer *_pRpcChannelBuffer,
|
|
PRPC_MESSAGE _pRpcMessage,
|
|
DWORD *_pdwStubPhase);
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE IAMFilterData_CreateFilterData_Proxy(
|
|
IAMFilterData __RPC_FAR * This,
|
|
/* [in] */ REGFILTER2 __RPC_FAR *prf2,
|
|
/* [out] */ BYTE __RPC_FAR *__RPC_FAR *prgbFilterData,
|
|
/* [out] */ ULONG __RPC_FAR *pcb);
|
|
|
|
|
|
void __RPC_STUB IAMFilterData_CreateFilterData_Stub(
|
|
IRpcStubBuffer *This,
|
|
IRpcChannelBuffer *_pRpcChannelBuffer,
|
|
PRPC_MESSAGE _pRpcMessage,
|
|
DWORD *_pdwStubPhase);
|
|
|
|
|
|
|
|
#endif /* __IAMFilterData_INTERFACE_DEFINED__ */
|
|
|
|
|
|
/* Additional Prototypes for ALL interfaces */
|
|
|
|
/* end of Additional Prototypes */
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* Helper IAMFilterData - cut and paste from dshow\h\fil_data_i.c
|
|
*
|
|
****************************************************************************/
|
|
#ifdef __cplusplus
|
|
extern "C"{
|
|
#endif
|
|
|
|
|
|
#ifndef __IID_DEFINED__
|
|
#define __IID_DEFINED__
|
|
|
|
typedef struct _IID
|
|
{
|
|
unsigned long x;
|
|
unsigned short s1;
|
|
unsigned short s2;
|
|
unsigned char c[8];
|
|
} IID;
|
|
|
|
#endif // __IID_DEFINED__
|
|
|
|
#ifndef CLSID_DEFINED
|
|
#define CLSID_DEFINED
|
|
typedef IID CLSID;
|
|
#endif // CLSID_DEFINED
|
|
|
|
const IID IID_IAMFilterData = {0x97f7c4d4,0x547b,0x4a5f,{0x83,0x32,0x53,0x64,0x30,0xad,0x2e,0x4d}};
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* Forward declaration
|
|
*
|
|
****************************************************************************/
|
|
HRESULT GenerateFilterList(ShowInfo* pShowInfo);
|
|
HRESULT EnumerateFilterPerCategory(ShowInfo* pShowInfo, CLSID* clsid, WCHAR* wszCatName);
|
|
HRESULT GetFilterInfo(IMoniker* pMon, IAMFilterData* pFD, FilterInfo* pFilterInfo);
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* GetBasicShowInfo - Get minimal info on DirectShow
|
|
*
|
|
****************************************************************************/
|
|
HRESULT GetBasicShowInfo(ShowInfo** ppShowInfo)
|
|
{
|
|
ShowInfo* pShowInfoNew;
|
|
|
|
pShowInfoNew = new ShowInfo;
|
|
if (pShowInfoNew == NULL)
|
|
return E_OUTOFMEMORY;
|
|
ZeroMemory(pShowInfoNew, sizeof(ShowInfo));
|
|
*ppShowInfo = pShowInfoNew;
|
|
|
|
return GenerateFilterList(pShowInfoNew);
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* DestroyShowInfo
|
|
*
|
|
****************************************************************************/
|
|
VOID DestroyShowInfo(ShowInfo* pShowInfo)
|
|
{
|
|
if (!pShowInfo) return;
|
|
|
|
if (pShowInfo->m_dwFilters)
|
|
{
|
|
FilterInfo* pFilterInfo;
|
|
FilterInfo* pFilterInfoNext;
|
|
|
|
pFilterInfo = pShowInfo->m_pFilters;
|
|
while(pFilterInfo)
|
|
{
|
|
pFilterInfoNext = pFilterInfo->m_pFilterInfoNext;
|
|
delete pFilterInfo;
|
|
pFilterInfo = pFilterInfoNext;
|
|
}
|
|
}
|
|
delete pShowInfo;
|
|
}
|
|
|
|
HRESULT GenerateFilterList(ShowInfo* pShowInfo)
|
|
{
|
|
HRESULT hr;
|
|
ICreateDevEnum* pSysDevEnum = NULL;
|
|
IEnumMoniker* pMonEnum = NULL;
|
|
IMoniker* pMon = NULL;
|
|
ULONG cFetched;
|
|
|
|
pShowInfo->m_dwFilters = 0;
|
|
hr = CoCreateInstance(CLSID_SystemDeviceEnum,
|
|
NULL,
|
|
CLSCTX_INPROC,
|
|
IID_ICreateDevEnum,
|
|
(void **)&pSysDevEnum);
|
|
if FAILED(hr)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Use the meta-category that contains a list of all categories.
|
|
// This emulates the behavior of Graphedit.
|
|
hr = pSysDevEnum->CreateClassEnumerator(CLSID_ActiveMovieCategories, &pMonEnum, 0);
|
|
pSysDevEnum->Release();
|
|
if FAILED(hr)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Enumerate over every category
|
|
while (hr = pMonEnum->Next(1, &pMon, &cFetched), hr == S_OK)
|
|
{
|
|
IPropertyBag *pPropBag;
|
|
|
|
// Associate moniker with a file
|
|
hr = pMon->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR wszCatName[1024] = L"";
|
|
CLSID clsidCategory;
|
|
VARIANT var;
|
|
var.vt = VT_BSTR;
|
|
|
|
// Get friendly name
|
|
hr = pPropBag->Read(L"FriendlyName", &var, 0);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
wcscpy(wszCatName, var.bstrVal);
|
|
SysFreeString(var.bstrVal);
|
|
}
|
|
// Get CLSID string from property bag
|
|
hr = pPropBag->Read(L"CLSID", &var, 0);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (CLSIDFromString(var.bstrVal, &clsidCategory) == S_OK)
|
|
{
|
|
if (TEXT('\0') == wszCatName[0])
|
|
{
|
|
wcscpy(wszCatName, var.bstrVal);
|
|
}
|
|
}
|
|
SysFreeString(var.bstrVal);
|
|
}
|
|
|
|
pPropBag->Release();
|
|
|
|
// Start to enumerate the filters for this one category
|
|
hr = EnumerateFilterPerCategory(pShowInfo, &clsidCategory, wszCatName);
|
|
}
|
|
|
|
pMon->Release();
|
|
}
|
|
|
|
pMonEnum->Release();
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT EnumerateFilterPerCategory(ShowInfo* pShowInfo, CLSID* clsid, WCHAR* wszCatName)
|
|
{
|
|
HRESULT hr;
|
|
ICreateDevEnum* pSysDevEnum = NULL;
|
|
IEnumMoniker *pMonEnum = NULL;
|
|
IMoniker *pMon = NULL;
|
|
ULONG cFetched;
|
|
|
|
#ifdef RUNNING_VC
|
|
// WMP bug 29936: Voxware codec corrupt: MSMS001 : corrupted heap
|
|
// This causes this call int3 when inside a debugger so skip
|
|
const CLSID clsidACMClassManager = {0x33d9a761,0x90c8,0x11d0,{0xbd,0x43,0x00,0xa0,0xc9,0x11,0xce,0x86}};
|
|
if( *clsid == clsidACMClassManager )
|
|
return S_OK;
|
|
#endif
|
|
|
|
hr = CoCreateInstance(CLSID_SystemDeviceEnum,
|
|
NULL,
|
|
CLSCTX_INPROC,
|
|
IID_ICreateDevEnum,
|
|
(void **)&pSysDevEnum);
|
|
if FAILED(hr)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
hr = pSysDevEnum->CreateClassEnumerator(*clsid, &pMonEnum, 0);
|
|
pSysDevEnum->Release();
|
|
if FAILED(hr)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// If there are no filters of a requested category, don't do anything.
|
|
if(NULL == pMonEnum)
|
|
{
|
|
// could added a string to denote an empty category
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
FilterInfo** ppFilterInfo;
|
|
FilterInfo* pFilterInfoNew;
|
|
|
|
ppFilterInfo = &(pShowInfo->m_pFilters);
|
|
while (NULL != *ppFilterInfo)
|
|
ppFilterInfo = &((*ppFilterInfo)->m_pFilterInfoNext);
|
|
|
|
|
|
// Enumerate all items associated with the moniker
|
|
while(pMonEnum->Next(1, &pMon, &cFetched) == S_OK)
|
|
{
|
|
// get a new record for FilterInfo
|
|
pFilterInfoNew = new FilterInfo;
|
|
if (pFilterInfoNew == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
ZeroMemory(pFilterInfoNew, sizeof(FilterInfo));
|
|
*ppFilterInfo = pFilterInfoNew;
|
|
ppFilterInfo = &(pFilterInfoNew->m_pFilterInfoNext);
|
|
pShowInfo->m_dwFilters++;
|
|
|
|
// set category clsid and friendly name
|
|
pFilterInfoNew->m_ClsidCat = *clsid;
|
|
#ifdef _UNICODE
|
|
wcscpy(pFilterInfoNew->m_szCatName, wszCatName);
|
|
#else
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
wszCatName,
|
|
-1,
|
|
pFilterInfoNew->m_szCatName,
|
|
sizeof(pFilterInfoNew->m_szCatName),
|
|
0,
|
|
0);
|
|
#endif
|
|
|
|
IPropertyBag *pPropBag;
|
|
|
|
// associate moniker with a file
|
|
hr = pMon->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VARIANT var;
|
|
var.vt = VT_BSTR;
|
|
|
|
// get filter's friendly name
|
|
hr = pPropBag->Read(L"FriendlyName", &var, 0);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
#ifdef _UNICODE
|
|
wcscpy(pFilterInfoNew->m_szName, var.bstrVal);
|
|
#else
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
var.bstrVal,
|
|
-1,
|
|
pFilterInfoNew->m_szName,
|
|
sizeof(pFilterInfoNew->m_szName),
|
|
0,
|
|
0);
|
|
#endif
|
|
SysFreeString(var.bstrVal);
|
|
}
|
|
|
|
// get filter's CLSID
|
|
hr = pPropBag->Read(L"CLSID", &var, 0);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
if(CLSIDFromString(var.bstrVal, &(pFilterInfoNew->m_ClsidFilter)) == S_OK)
|
|
{
|
|
// use the guid if we can't get the friendly name
|
|
if (TEXT('\0') == pFilterInfoNew->m_szName[0])
|
|
{
|
|
#ifdef _UNICODE
|
|
wcscpy(pFilterInfoNew->m_szName, var.bstrVal);
|
|
#else
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
var.bstrVal,
|
|
-1,
|
|
pFilterInfoNew->m_szName,
|
|
sizeof(pFilterInfoNew->m_szName),
|
|
0,
|
|
0);
|
|
#endif
|
|
}
|
|
}
|
|
SysFreeString(var.bstrVal);
|
|
}
|
|
pPropBag->Release();
|
|
}
|
|
|
|
|
|
// start grabbing filter info
|
|
IAMFilterData *pFD;
|
|
hr = CoCreateInstance(CLSID_FilterMapper,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IAMFilterData,
|
|
(void **)&pFD);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = GetFilterInfo(pMon, pFD, pFilterInfoNew);
|
|
pFD->Release();
|
|
}
|
|
else
|
|
{
|
|
// Must not be on DX8 or above...
|
|
}
|
|
|
|
pMon->Release();
|
|
}
|
|
|
|
pMonEnum->Release();
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT GetFilterInfo(IMoniker* pMon, IAMFilterData* pFD, FilterInfo* pFilterInfo)
|
|
{
|
|
HRESULT hr;
|
|
|
|
IPropertyBag *pPropBag;
|
|
hr = pMon->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropBag);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
VARIANT varFilData;
|
|
varFilData.vt = VT_UI1 | VT_ARRAY;
|
|
varFilData.parray = 0; // docs say zero this
|
|
|
|
BYTE *pbFilterData = NULL;
|
|
DWORD dwcbFilterDAta = 0; // 0 if not read
|
|
hr = pPropBag->Read(L"FilterData", &varFilData, 0);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
if( varFilData.vt == (VT_UI1 | VT_ARRAY) )
|
|
{
|
|
dwcbFilterDAta = varFilData.parray->rgsabound[0].cElements;
|
|
if( SUCCEEDED( SafeArrayAccessData(varFilData.parray, (void **)&pbFilterData) ) )
|
|
{
|
|
BYTE *pb = NULL;
|
|
hr = pFD->ParseFilterData(pbFilterData, dwcbFilterDAta, &pb);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
REGFILTER2** ppRegFilter = (REGFILTER2**)pb;
|
|
REGFILTER2* pFil = NULL;
|
|
pFil = *ppRegFilter;
|
|
|
|
if( pFil != NULL && pFil->dwVersion == 2 )
|
|
{
|
|
pFilterInfo->m_dwMerit = pFil->dwMerit; // set merit
|
|
wsprintf(pFilterInfo->m_szVersion, TEXT("v%d"), pFil->dwVersion); // set version
|
|
|
|
//
|
|
// Display the filter's filename
|
|
//
|
|
// Read filter's CLSID from property bag. This CLSID string will be
|
|
// used to find the filter's filename in the registry.
|
|
VARIANT varFilterClsid;
|
|
varFilterClsid.vt = VT_BSTR;
|
|
|
|
hr = pPropBag->Read(L"CLSID", &varFilterClsid, 0);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
TCHAR szKey[512];
|
|
|
|
// Convert BSTR to string
|
|
WCHAR *wszFilterClsid;
|
|
TCHAR szFilterClsid[1024];
|
|
wszFilterClsid = varFilterClsid.bstrVal;
|
|
|
|
#ifdef _UNICODE
|
|
wcscpy(szFilterClsid, wszFilterClsid);
|
|
#else
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
wszFilterClsid,
|
|
-1,
|
|
szFilterClsid,
|
|
sizeof(szFilterClsid),
|
|
0,
|
|
0);
|
|
#endif
|
|
|
|
// Create key name for reading filename registry
|
|
wsprintf(szKey, TEXT("Software\\Classes\\CLSID\\%s\\InprocServer32\0"),
|
|
szFilterClsid);
|
|
|
|
// Variables needed for registry query
|
|
HKEY hkeyFilter=0;
|
|
DWORD dwSize=MAX_PATH;
|
|
BYTE szFilename[MAX_PATH];
|
|
int rc=0;
|
|
|
|
// Open the CLSID key that contains information about the filter
|
|
rc = RegOpenKey(HKEY_LOCAL_MACHINE, szKey, &hkeyFilter);
|
|
if (rc == ERROR_SUCCESS)
|
|
{
|
|
rc = RegQueryValueEx(hkeyFilter, NULL, // Read (Default) value
|
|
NULL, NULL, szFilename, &dwSize);
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
{
|
|
wsprintf(pFilterInfo->m_szFileName, TEXT("%s"), szFilename); // set file name & version
|
|
GetFileVersion(pFilterInfo->m_szFileName, pFilterInfo->m_szFileVersion, NULL, NULL, NULL, NULL);
|
|
}
|
|
|
|
rc = RegCloseKey(hkeyFilter);
|
|
}
|
|
|
|
SysFreeString(varFilterClsid.bstrVal);
|
|
}
|
|
|
|
int iPinsInput = 0;
|
|
int iPinsOutput = 0;
|
|
|
|
for(UINT iPin = 0; iPin < pFil->cPins; iPin++)
|
|
{
|
|
if(pFil->rgPins2[iPin].dwFlags & REG_PINFLAG_B_OUTPUT)
|
|
{
|
|
iPinsOutput++;
|
|
}
|
|
else
|
|
{
|
|
iPinsInput++;
|
|
}
|
|
}
|
|
|
|
pFilterInfo->m_dwInputs = iPinsInput; // set input
|
|
pFilterInfo->m_dwOutputs = iPinsOutput; // set output
|
|
|
|
}
|
|
|
|
CoTaskMemFree( (BYTE*) pFil );
|
|
}
|
|
|
|
SafeArrayUnaccessData(varFilData.parray);
|
|
}
|
|
}
|
|
|
|
VariantClear(&varFilData);
|
|
}
|
|
|
|
pPropBag->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|