使用系统设备枚举器
[与此页面关联的功能 DirectShow 是一项旧功能。 它已被 MediaPlayer、 IMFMediaEngine 和 媒体基金会中的音频/视频捕获取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能使用 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
系统设备枚举器提供了一种统一的方法,用于按类别枚举在用户的系统上注册的筛选器。 此外,它区分各个硬件设备,即使同一筛选器支持它们。 这对于使用 Windows 驱动程序模型 (WDM) 和 KSProxy 筛选器的设备特别有用。 例如,用户可能有多个 WDM 视频捕获设备,所有这些设备都受同一筛选器支持。 系统设备枚举器将它们视为单独的设备实例。
系统设备枚举器的工作原理是为特定类别(例如音频捕获或视频压缩)创建枚举器。 类别枚举器为类别中的每个设备返回唯一的名字对象。 类别枚举器自动包括类别中任何相关的即插即用设备。 有关类别的列表,请参阅 筛选类别。
若要使用系统设备枚举器,请执行以下操作:
- 通过调用 CoCreateInstance 创建系统设备枚举器。 CLSID_SystemDeviceEnum CLSID) (类标识符。
- 通过使用所需类别的 CLSID 调用 ICreateDevEnum::CreateClassEnumerator 来获取类别枚举器。 此方法返回 IEnumMoniker 接口指针。 如果类别为空 (或不存在) ,该方法将返回S_FALSE而不是错误代码。 如果是这样,则返回的 IEnumMoniker 指针为 NULL ,取消引用它将导致异常。 因此,在调用 CreateClassEnumerator 时显式测试S_OK,而不是调用通常的 SUCCEEDED 宏。
- 使用 IEnumMoniker::Next 方法枚举每个名字对象。 此方法返回 IMoniker 接口指针。 当 Next 方法到达枚举的末尾时,它还会返回S_FALSE,因此再次检查S_OK。
- 若要检索设备的友好名称 (例如,若要在用户界面) 中显示,请调用 IMoniker::BindToStorage 方法。
- 若要创建并初始化用于管理设备的 DirectShow 筛选器,请在名字对象上调用 IMoniker::BindToObject 。 调用 IFilterGraph::AddFilter 将筛选器添加到图中。
下图演示了此过程。
以下示例演示如何枚举安装在用户系统上的视频压缩器。 为简洁起见,该示例执行最小错误检查。
// Create the System Device Enumerator.
HRESULT hr;
ICreateDevEnum *pSysDevEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void **)&pSysDevEnum);
if (FAILED(hr))
{
return hr;
}
// Obtain a class enumerator for the video compressor category.
IEnumMoniker *pEnumCat = NULL;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEnumCat, 0);
if (hr == S_OK)
{
// Enumerate the monikers.
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))
{
// To retrieve the filter's friendly name, do the following:
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
// Display the name in your UI somehow.
}
VariantClear(&varName);
// To create an instance of the filter, do the following:
IBaseFilter *pFilter;
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,
(void**)&pFilter);
// Now add the filter to the graph.
//Remember to release pFilter later.
pPropBag->Release();
}
pMoniker->Release();
}
pEnumCat->Release();
}
pSysDevEnum->Release();
设备名字对象
对于设备名字对象,可以将名字对象传递给 IFilterGraph2::AddSourceFilterForMoniker 方法,以便为设备创建捕获筛选器。 有关示例代码,请参阅该方法的文档。
IMoniker::GetDisplayName 方法返回名字对象的显示名称。 尽管显示名称是可读的,但你通常不会将其显示给最终用户。 改为从属性包获取友好名称,如前所述。
IMoniker::P arseDisplayName 方法或 MkParseDisplayName 函数可用于为给定筛选器类别创建默认设备名字对象。 使用格式 @device:*:{category-clsid}
为 的显示名称,其中 category-clsid
是类别 GUID 的字符串表示形式。 默认名字对象是设备枚举器为该类别返回的第一个名字对象。