Microsoft DirectX 8.1 (C++)

Using the System Device Enumerator

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.

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. 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.
  3. 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.
  4. To retrieve the friendly name of the device (for example, to display in the user interface), call the IMoniker::BindToStorage method.
  5. To create and initialize the DirectShow filter that manages the device, call IMoniker::BindToObject on the moniker.

The following diagram illustrates this process.

Enumerating Devices

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

// 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;
    ULONG cFetched;
    while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
    {
        IPropertyBag *pPropBag;
        pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);

        // To retrieve the friendly name of the filter, 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;
        pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pFilter);
        // Now add the filter to the graph. Remember to release pFilter later.
    
        // Clean up.
        pPropBag->Release();
        pMoniker->Release();
    }
    pEnumCat->Release();
}
pSysDevEnum->Release();

After calling BindToObject, call IFilterGraph::AddFilter to add the filter to the graph.