The System Device Enumerator provides a uniform way to enumerate, by category, the filters registered on a user's system. Moreover, it differentiates between individual hardware devices, even if the same filter supports them. This is particularly useful for devices that use the Windows Driver Model (WDM) and the KSProxy filter. For example, the user might have several WDM video capture devices, all supported by the same filter. The System Device Enumerator treats them as separate device instances.
系统设备枚举器提供统一的方法通过注册在用户系统中的类别来枚举,而且能区别单个硬件设备,即使同一个 filter 支持他们。对于使用 WDM 和 KSProxy filter 的设备来说这一点特别有用。例如,用户可以有多个被同一个 filter 的支持的 WDM 视频采集设备。设备枚举器把他们当作单独的设备实例看待。
The System Device Enumerator works by creating an enumerator for a specific category, such as audio capture or video compression. The category enumerator returns a unique moniker for each device in the category. The category enumerator automatically includes any relevant Plug and Play devices in the category. For a list of categories, see Filter Categories .
设备枚举器为指定的类别创建一个枚举器,例如音频采集或者视频压缩。类别枚举器为每一个设备返回一个唯一的名字。枚举器自动包含类别中的一些即插即用设备。
To use the System Device Enumerator, do the following:
要使用系统设备枚举器,按一下步骤:
1. Create the system device enumerator by calling CoCreateInstance . The class identifier (CLSID) is CLSID_SystemDeviceEnum.
2. 调用 CoCreateInstance 创建系统设备枚举器。 CLSID 是 CLSID_SystemDeviceEnum 。
3. Obtain a category enumerator by calling ICreateDevEnum::CreateClassEnumerator with the CLSID of the desired category. This method returns an IEnumMoniker interface pointer. If the category is empty (or does not exist), the method returns S_FALSE rather than an error code. If so, the returned IEnumMoniker pointer is NULL and dereferencing it will cause an exception. Therefore, explicitly test for S_OK when you call CreateClassEnumerator , instead of calling the usual SUCCEEDED macro.
4. 调用 ICreateDevEnum::CreateClassEnumerator 获得一个类别枚举器。这个方法返回一个 IEnumMoniker 接口指针。如果类别是空的或者不存在,这个方法就返回 S_FALSE 而不是错误码。假如返回的 IEnumMoniker 指针是空的话,废除它将产生一个异常。因此,当调用 CreateClassEnumerator 的时候明确的测试 S_OK ,通常使用 SUCCEEDED 宏。
5. Use the IEnumMoniker::Next method to enumerate each moniker. This method returns an IMoniker interface pointer. When the Next method reaches the end of the enumeration, it also returns S_FALSE, so again check for S_OK.
6. 使用 IEnumMoniker::Next 方法来枚举每一个名字。这个方法返回一个 IMoniker 接口指针。当 Next 到达末尾,就会返回 S_FALSE ,所以也要检查 S_OK.
7. To retrieve the friendly name of the device (for example, to display in the user interface), call the IMoniker::BindToStorage method.
8. 要获得设备的友名,调用 IMoniker::BindToStorage 方法。
9. To create and initialize the DirectShow filter that manages the device, call IMoniker::BindToObject on the moniker. Call IFilterGraph::AddFilter to add the filter to the graph.
10. 创建并初始化一个 DirectShow filter ,用来管理设备,在别名上上调用 IMoniker::BindToObject 。调用 IFilterGraph::AddFilter 把这个 filter 添加到 graph 中。
The following diagram illustrates this process.
下面的插图演示这个过程:
The following example shows how to enumerate the video compressors installed on the user's system. For brevity, the example performs minimal error checking.
接下来的例子显示如何枚举一个安装在用户系统中的视频压缩器。例子只进行了最少的错误检查。
// 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();
Device Monikers
For device monikers, you can pass the moniker to the IFilterGraph2::AddSourceFilterForMoniker method to create a capture filter for the device. For example code, see the documentation for that method.
你可以传递别名给 IFilterGraph2::AddSourceFilterForMoniker 函数来为设备创建一个采集 filter 。
The IMoniker::GetDisplayName method returns the display name of the moniker. Although the display name is readable, you would not typically display it to an end-user. Get the friendly name from the property bag instead, as described previously.
IMoniker::GetDisplayName 方法返回别名的显示名称。尽管显示名称是易读的,你也不愿把他显示到终端。
从属性包中获得友名来代替显示名称。
The IMoniker::ParseDisplayName method or the MkParseDisplayName function can be used to create a default device moniker for a given filter category. Use a display name with the form @device:*:{category-clsid}
, where category-clsid
is the string representation of the category GUID. The default moniker is the first moniker returned by the device enumerator for that category.
IMoniker::ParseDisplayName 方法或者 MKParseDisplayName 方法可以被用来为给定 filter 类别创建默认的设备别名。使用 @device:*:{category-clsid} 结构作为显示名。 category-clsid 代表类别 GUID 。默认别名是设备枚举器返回的第一个别名。