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