Uso del enumerador de dispositivos del sistema

[La característica asociada a esta página, DirectShow, es una característica heredada. Se ha reemplazado por MediaPlayer, IMFMediaEngine y Captura de audio/vídeo en Media Foundation. Esas características se han optimizado para Windows 10 y Windows 11. Microsoft recomienda encarecidamente que el nuevo código use MediaPlayer, IMFMediaEngine y Audio/Video Capture en Media Foundation en lugar de DirectShow, siempre que sea posible. Microsoft sugiere que el código existente que usa las API heredadas se reescriba para usar las nuevas API si es posible.

El enumerador de dispositivos del sistema proporciona una manera uniforme de enumerar, por categoría, los filtros registrados en el sistema de un usuario. Además, diferencia entre dispositivos de hardware individuales, incluso si el mismo filtro los admite. Esto es especialmente útil para los dispositivos que usan el modelo de controlador de Windows (WDM) y el filtro KSProxy. Por ejemplo, el usuario puede tener varios dispositivos de captura de vídeo WDM, todos compatibles con el mismo filtro. El Enumerador de dispositivos del sistema los trata como instancias de dispositivo independientes.

El enumerador de dispositivos del sistema funciona mediante la creación de un enumerador para una categoría específica, como la captura de audio o la compresión de vídeo. El enumerador de categorías devuelve un moniker único para cada dispositivo de la categoría. El enumerador de categorías incluye automáticamente todos los dispositivos Plug and Play pertinentes de la categoría. Para obtener una lista de categorías, vea Categorías de filtro.

Para usar el enumerador de dispositivos del sistema, haga lo siguiente:

  1. Cree el enumerador de dispositivos del sistema llamando a CoCreateInstance. El identificador de clase (CLSID) es CLSID_SystemDeviceEnum.
  2. Obtenga un enumerador de categorías llamando a ICreateDevEnum::CreateClassEnumerator con el CLSID de la categoría deseada. Este método devuelve un puntero de interfaz IEnumMoniker . Si la categoría está vacía (o no existe), el método devuelve S_FALSE en lugar de un código de error. Si es así, el puntero IEnumMoniker devuelto es NULL y desreferenciarlo provocará una excepción. Por lo tanto, pruebe explícitamente para S_OK al llamar a CreateClassEnumerator, en lugar de llamar a la macro SUCCEEDED habitual.
  3. Use el método IEnumMoniker::Next para enumerar cada moniker. Este método devuelve un puntero de interfaz IMoniker . Cuando el método Next llega al final de la enumeración, también devuelve S_FALSE, por lo que, de nuevo, compruebe si hay S_OK.
  4. Para recuperar el nombre descriptivo del dispositivo (por ejemplo, para mostrar en la interfaz de usuario), llame al método IMoniker::BindToStorage .
  5. Para crear e inicializar el filtro DirectShow que administra el dispositivo, llame a IMoniker::BindToObject en el moniker. Llame a IFilterGraph::AddFilter para agregar el filtro al grafo.

En el siguiente diagrama se muestra este proceso.

enumeración de dispositivos

En el ejemplo siguiente se muestra cómo enumerar los compresores de vídeo instalados en el sistema del usuario. Por motivos de brevedad, en el ejemplo se realiza una comprobación de errores mínima.

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

Monikers de dispositivo

En el caso de los monikers de dispositivo, puedes pasar el moniker al método IFilterGraph2::AddSourceFilterForMoniker para crear un filtro de captura para el dispositivo. Para obtener código de ejemplo, consulte la documentación de ese método.

El método IMoniker::GetDisplayName devuelve el nombre para mostrar del moniker. Aunque el nombre para mostrar es legible, normalmente no lo mostraría a un usuario final. Obtenga el nombre descriptivo del contenedor de propiedades en su lugar, como se ha descrito anteriormente.

El método IMoniker::P arseDisplayName o la función MkParseDisplayName se pueden usar para crear un moniker de dispositivo predeterminado para una categoría de filtro determinada. Use un nombre para mostrar con el formulario @device:*:{category-clsid}, donde category-clsid es la representación de cadena del GUID de categoría. El moniker predeterminado es el primer moniker devuelto por el enumerador de dispositivos para esa categoría.