windows-nt/Source/XPSP1/NT/multimedia/directx/dxdiag/showinfo.cpp
2020-09-26 16:20:57 +08:00

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