Поделиться через


Использование перечислителя системных устройств

[Функция, связанная с этой страницей DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngine, и аудио/ видео захвата в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует использовать в новом коде MediaPlayer, IMFMediaEngine и аудио/видеозахват в Media Foundation вместо DirectShow, когда это возможно. Корпорация Майкрософт предлагает переписать существующий код, в котором используются устаревшие API, чтобы по возможности использовать новые API.]

Перечислитель системных устройств предоставляет единый способ перечисления фильтров, зарегистрированных в системе пользователя, по категориям. Кроме того, он различает отдельные аппаратные устройства, даже если один и тот же фильтр поддерживает их. Это особенно полезно для устройств, использующих модель драйвера Windows (WDM) и фильтр KSProxy. Например, у пользователя может быть несколько устройств захвата видео WDM, которые поддерживаются одинаковым фильтром. Перечислитель системных устройств обрабатывает их как отдельные экземпляры устройств.

Перечислитель системных устройств создает перечислитель для определенной категории, например для захвата звука или сжатия видео. Перечислитель категорий возвращает уникальный моникер для каждого устройства в категории. Перечислитель категорий автоматически включает все соответствующие устройства Plug and Play в категорию. Список категорий см. в разделе Категории фильтра.

Чтобы использовать перечислитель системных устройств, сделайте следующее:

  1. Создайте перечислитель системных устройств, вызвав CoCreateInstance. Идентификатор класса (CLSID) CLSID_SystemDeviceEnum.
  2. Получите перечислитель категорий, вызвав метод ICreateDevEnum::CreateClassEnumerator с CLSID нужной категории. Этот метод возвращает указатель интерфейса IEnumMoniker . Если категория пуста (или не существует), метод возвращает S_FALSE, а не код ошибки. Если это так, возвращенный указатель IEnumMoniker имеет значение NULL , и его разыменовывание вызовет исключение. Поэтому явным образом проверьте наличие S_OK при вызове CreateClassEnumerator вместо вызова обычного макроса SUCCEEDED .
  3. Используйте метод IEnumMoniker::Next для перечисления каждого моникера. Этот метод возвращает указатель интерфейса IMoniker . Когда метод Next достигает конца перечисления, он также возвращает S_FALSE, поэтому снова проверка для S_OK.
  4. Чтобы получить понятное имя устройства (например, для отображения в пользовательском интерфейсе), вызовите метод IMoniker::BindToStorage .
  5. Чтобы создать и инициализировать фильтр 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 категории. Моникер по умолчанию — это первый моникер, возвращаемый перечислителем устройства для этой категории.