COM, ATL

System Device Enumerator 의 사용법 - 모니커 사용 예

디버그정 2008. 9. 14. 09:03

System Device Enumerator 의 사용법

System Device Enumerator 는, 사용자의 시스템에 등록되어 있는 필터를 카테고리 마다 열거하기 위한 통일된 방법을 제공한다. 게다가 같은 필터가 복수의 장치를 지원 하고 있는 경우에서도, 각각의 하드웨어 장치를 구별할 수 있다. 이것은, Windows Driver Model (WDM) 및 KSProxy 필터를 사용하는 장치의 경우에 특히 유용하다. 예를 들어, 사용자가 복수의 WDM 비디오 캡춰 장치를 가져, 그것들 모든 것이 같은 필터에 의해 지원 되는 일이 있다. System Device Enumerator 는, 이것들을 다른 장치 인터페이스로서 취급한다.

System Device Enumerator 는, 오디오 캡춰나 비디오 압축 등, 특정 카테고리전용의 열거자를 생성 하는 것으로 기능한다. 카테고리 열거자는, 그 카테고리내의 각 장치에 대한 일의의 모니카를 돌려준다. 또, 관련이 있는 플러그 앤 플레이 장치를 자동적으로 카테고리에 포함한다. 카테고리의 리스트에 대해서는, 「필터 카테고리」를 참조할것.

System Device Enumerator 를 사용하려면 , 다음의 처리를 실시한다.

  1. CoCreateInstance 를 호출해 System Device Enumerator 를 생성 한다. 클래스 식별자 (CLSID)는 CLSID_SystemDeviceEnum 이다.
  2. 목적의 카테고리의 CLSID 를 사용해 ICreateDevEnum::CreateClassEnumerator 를 호출해, 카테고리 열거자를 입수한다. 이 메서드는 IEnumMoniker 인터페이스 포인터를 돌려준다. 카테고리가 하늘인 (또는 존재하지 않는다) 경우, 메서드는 에러 코드는 아니고 S_FALSE 를 돌려준다. 이 경우, 돌려받는 IEnumMoniker 포인터는 NULL 이며, 참조 해제 하면 예외가 발생한다. 따라서,CreateClassEnumerator 를 호출할 때는, 보통의 SUCCEEDED 매크로를 호출하는 것이 아니라, S_OK 일지 어떨지를 명시적으로 테스트하는 것.
  3. IEnumMoniker::Next 메서드를 사용해 각 모니카를 열거한다. 이 메서드는 IMoniker 인터페이스 포인터를 돌려준다. Next 메서드가 열거의 마지막에 달하면 S_FALSE 도 돌려주므로, 한번 더 S_OK 일지 어떨지를 체크한다.
  4. 장치의 프렌들리명을 얻어오려면 (예를 들어, 사용자 인터페이스에 표시하기 위해(때문에)),IMoniker::BindToStorage 메서드를 호출한다.
  5. 장치를 관리하는 DirectShow 필터를 생성 해, 초기화하려면 , 모니카에 대해서 IMoniker::BindToObject 를 호출한다. 그래프에 필터를 추가하려면 ,IFilterGraph::AddFilter 를 호출한다.

다음의 그림에 이 처리를 나타낸다.

장치의 열거

다음 예는 사용자의 시스템에 인스톨 되고 있는 비디오 압력을 열거하는 방법을 나타내고 있다. 간략화를 위해, 이 코드에서는 최소한의 에러 체크 밖에 실시하지 않는다.

// 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;
}

// 비디오 압력 카테고리의 클래스 열거자를 얻어온다.
IEnumMoniker *pEnumCat = NULL;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEnumCat, 0);

if (hr == S_OK) 
{
    // 모니카를 열거한다.
    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))
        {
            // 필터의 프렌들리명을 얻어오려면, 다음의 처리를 실시한다.
            VARIANT varName;
            VariantInit(&varName);
            hr = pPropBag->Read(L"FriendlyName", &varName, 0);
            if (SUCCEEDED(hr))
            {
                // 하등의 방법으로 UI 에 이름을 표시한다.
            }
            VariantClear(&varName);

            // 필터의 인스턴스를 생성 하려면 , 다음의 처리를 실시한다.
            IBaseFilter *pFilter;
            hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,
                (void**) &pFilter);
            // 여기서 그래프에 필터를 추가한다.
            // 다음에 잊지 않고 pFilter 를 릴리즈 하는 것.
            pPropBag->Release();
        }
        pMoniker->Release();
    }
    pEnumCat->Release();
}
pSysDevEnum->Release();

디바이스 모니커

IMoniker::GetDisplayName 메서드는 모니카의 표시명을 돌려준다. 디바이스 모니커의 경우, 표시명을 IFilterGraph2::AddSourceFilterForMoniker 에 건네주면 장치의 캡춰 필터를 생성 할 수 있다.

LPOLESTR strName = NULL;
IBaseFilter pSrc = NULL;
hr = pMoniker->GetDisplayName(NULL, NULL, &strName);
if (SUCCEEDED(hr))
{
    // 필터 그래프 매니저에 IFilterGraph2 를 문의한다.
    IFilterGraph2 *pFG2 = NULL;
    hr = pGraph->QueryInterface(IID_IFilterGraph2, (void**) &pFG2);
    if (SUCCEEDED(hr))
    {
        hr = pFG2->AddSourceFilterForMoniker(pMoniker, 0, L"Source", &pSrc);
        pFG2->Release();
    }
    CoTaskMemFree(strName);
}

// 성공하면 잊지 않고 pSrc 를 릴리즈 하는 것.

표시명은 읽기 가능하지만, 보통은 최종 사용자에 표시하지 않는다. 전에 설명한 것처럼, 대신에 프로퍼티 가방으로부터 프렌들리명을 얻어온다.

특정의 필터 카테고리의 디폴트 디바이스 모니커를 생성 할 때는,IMoniker::ParseDisplayName 메서드 또는 MkParseDisplayName 함수를 사용할 수 있다. 표시명에는 @device:*:{category-clsid} 를 사용한다. category-clsid 는 카테고리 GUID 의 캐릭터 라인 표현이다. 디폴트 모니카는, 그 카테고리의 장치 열거 자식이 돌려주는 최초의 모니카이다.

예를 들어, 다음 코드는 비디오 캡춰 카테고리의 디폴트 모니카를 생성 한다.

// 비디오 캡춰 카테고리.
WCHAR szMon[] = L"@device:*:{860BB310-5D01-11d0-BD3B-00A0C911CE86}";
IBindCtx *pBindCtx;
hr = CreateBindCtx(0, &pBindCtx);

ULONG chEaten = 0;
IMoniker *pMoniker = 0;
hr = MkParseDisplayName(pBindCtx, szMon, &chEaten, &pMoniker);
pBindCtx->Release();
if (SUCCEEDED(hr))
{
    // 표시명을 얻어온다인가, DirectShow 필터에 바인드 한다.
    pMoniker->Release();
}