系统设备调查器提供了一个统一的方法去列举出系统中用户所有按类型注册的过滤器。系统设备调查器通过创建一个指定类型调查器(比如音频捕获类型或者视频压缩类型) (enumerator)来工作,这个调查器会返回系统中所有该类设备的唯一名称。
按一下步骤操作去使用设备调查器:
1. 调用CoCreateInstance 创建系统设备调查器。
类标识(CLSID)参数是CLSID_SystemDeviceEnum.
2. 调用ICreateDevEnum::CreateClassEnumerator 创建你想要的指定类型调查器,在类标识(CLSID)参数中指定你想要列举的设备类型。调用该方法后,将返回一个IenumMoniker指针。如果指定类型设备为空或者不存在该设备,将返回S_FALSE。同时IenumMoniker指针为NULL并且会造成一个异常。所有,在调用该方法的时候,要检查其返回值是否为S_OK,而不要使用SUCCEEDED宏去检测。
3. 使用 IEnumMoniker::Next 方法去列举出每个设备名称。该方法将返回一个Imoniker接口指针。当Next方法列举出最后一个设备名称后,它将返回S_FALSE,为S_OK表示还有设备没有列举完。
4. 调用IMoniker::BindToStorage 方法去获得设备的名称。
5. 调用IMoniker::BindToObject去创建并初始化DirectShow过滤器去管理选择的设备。调用IFilterGraph::AddFilter把创建的过滤器加到过滤器图表中。
下图显示处理流程
下面代码演示了列举出用户系统上安装的视频压缩设备。为了方便阅读,该例只加了最基本的错误检查。
// 创建系统设备调查器
HRESULT hr;
ICreateDevEnum *pSysDevEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void **)&pSysDevEnum);
if (FAILED(hr))
{
return hr;
}
// 获得视频压缩类型的制定类型调查器
IEnumMoniker *pEnumCat = NULL;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEnumCat, 0);
if (hr == S_OK)
{
//列举所有设备
IMoniker *pMoniker = NULL;
ULONG cFetched;
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag *pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
if (SUCCEEDED(hr))
{
// 获得设备名称
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
// 在你的程序中显示设备名称
}
VariantClear(&varName);
// 创建过滤器
IBaseFilter *pFilter;
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,
(void**)&pFilter);
// 把过滤器加入到过滤器图表中
//记住在以后要释放掉pFilter指向的过滤器对象
pPropBag->Release();
}
pMoniker->Release();
}
pEnumCat->Release();
}
pSysDevEnum->Release();
设备 Monikers
IMoniker::GetDisplayName 方法将返回moniker的显示名称(display name)。对于设备monikers,你可以通过显示名称,使用IFilterGraph2::AddSourceFilterForMoniker方法为设备,创建一个捕获过滤器。
LPOLESTR strName = NULL;
IBaseFilter pSrc = NULL;
hr = pMoniker->GetDisplayName(NULL, NULL, &strName);
if (SUCCEEDED(hr))
{
// 为IFilterGraph2查找过滤器图表管理器
IFilterGraph2 *pFG2 = NULL;
hr = pGraph->QueryInterface(IID_IFilterGraph2, (void**)&pFG2);
if (SUCCEEDED(hr))
{
hr = pFG2->AddSourceFilterForMoniker(pMoniker, 0, L"Source", &pSrc);
pFG2->Release();
}
CoTaskMemFree(strName);
}
// 如果成功,要记住释放掉pSrc
虽然,设备显示名称便于阅读理解,你可能不会向用户显示该名称。而是用设备的Friendly名称显示给用户。
IMoniker::ParseDisplayName 方法和MkParseDisplayName函数可用于从获得的指定类型过滤器中创建一个默认的设备名称(moniker),它可以从类标识(GUID)中解析出显示名称(display name)。类标识表示方法为@device:*:{category-clsid}。默认的设备名称就是指定类型设备调查器中的第一个名称。
下面例子,创建视频捕获类设备的默认设备名称。
// 视频捕获类
WCHAR szMon[] = L"@device:*:{860BB310-5D01-11d0-BD3B-00A0C911CE86}";
IBindCtx *pBindCtx;
hr = CreateBindCtx(0, &pBindCtx);
ULONG chEaten = 0;
IMoniker *pMoniker = 0;
hr = MkParseDisplayName(pBindCtx, szMon, &chEaten, &pMoniker);
pBindCtx->Release();
if (SUCCEEDED(hr))
{
//获得显示名称(display name),或建立一个DirectShow 过滤器。
pMoniker->Release();
}