閱讀882 返回首頁    go 阿裏雲 go 技術社區[雲棲]


如何使用係統設備枚舉器

係統設備枚舉器為我們按類型枚舉已注冊在係統中的Fitler提供了統一的方法。而且它能夠區分不同的硬件設備,即便是同一個Filter支持它們。這對那些使用Windows驅動模型和KSProxy Filter的設備來說是非常有用的。係統設備枚舉器對它們按不同的設備實例進行對待(譯注:雖然它們支持相同Filter)。
  當我們利用係統設備枚舉器查詢設備的時候,係統設備枚舉器為特定類型的設備(如,音頻捕獲和視頻壓縮)生成了一張枚舉表(Enumerator)。類型枚舉器(Category enumerator)為每個這種類型的設備返回一個Moniker,類型枚舉器自動把每一種即插即用的設備包含在內。
  按如下的步驟使用係統設備枚舉器:
  1. 調用方法CoCreateInstance生成係統設備枚舉器。類標識(CLSID)為CLSID_SystemDeviceEnum。
  2. 調用ICreateDevEnum::CreateClassEnumerator方法生成類型枚舉器,參數為你想要得到的類型的CLSID,該方法返回一個IEnumMoniker接口指針,如果指定的類型(是空的)或不存在,函數ICreateDevEnum::CreateClassEnumerator將返回S_FALSE而不是錯誤代碼,同時IEnumMoniker指針(譯注:通過參數返回)也是空的,這就要求我們在調用CreateClassEnumerator的時候明確用S_OK進行比較而不是使用宏SUCCEEDED。
  3. 使用IEnumMoniker::Next方法依次得到IEnumMoniker指針中的每個moniker。該方法返回一個IMoniker接口指針。當Next到達枚舉的底部,它的返回值仍然是S_FALSE,這裏我們仍需要用S_OK來進行檢驗。
  4. 想要得到該設備較為友好的名稱(例如想要在用戶界麵中進行顯示),調用IMoniker::BindToStorage方法。
  5. 如果想要生成並初始化管理該設備的Filter調用3返回指針的IMonitor::BindToObject方法,接下來調用IFilterGraph::AddFilter把該Filter添加到視圖中。
  下圖說明了上述步驟:
  下麵的代碼示例了如何枚舉用戶係統中的視頻壓縮器,為了簡化,隻給出了很少的錯誤檢查。
  
  //生成係統設備枚舉器.
  HRESULT hr;
  ICreateDevEnum *pSysDevEnum = NULL;
  hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
   IID_ICreateDevEnum, (void **)&pSysDevEnum);
  if (FAILED(hr))
  {
   return hr;
  }
  // 獲得視頻壓縮的類枚舉器(Class enumerator).
  IEnumMoniker *pEnumCat = NULL;
  hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEnumCat, 0);
  if (hr == S_OK)
  {
   // 枚舉其中的 moniker.
   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))
   {
   //如下,得到Filter的友好名稱:
   VARIANT varName;
   VariantInit(&varName);
   hr = pPropBag->Read(L"FriendlyName", &varName, 0);
   if (SUCCEEDED(hr))
   {
   //在你的用戶界麵上麵顯示.
   }
   VariantClear(&varName);
   // 如下,生成該filter的實例:
   IBaseFilter *pFilter;
   hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,
   (void**)&pFilter);
   //將Filter加入到Graph.
   //後麵必須記得釋放pFilter.
   pPropBag->Release();
   }
   pMoniker->Release();
   }
   pEnumCat->Release();
  }
  pSysDevEnum->Release();
  
  設備Moniker
  IMoniker::GetDisplayName方法返回moniker的名字。你可以把這個名字傳遞給IFilterGraph2::AddSourceFilterForMoniker,這樣可以生成該設備的捕獲Filter。
  
  LPOLESTR strName = NULL;
  IBaseFilter pSrc = NULL;
  hr = pMoniker->GetDisplayName(NULL, NULL, &strName);
  if (SUCCEEDED(hr))
  {
   // 得到IFilterGraph2的Filter Graph Manager.
   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.
  
  雖然,用上述方法得到的名字也有較好的可讀性,但是我們一般不把它顯示給用戶,如前麵所示,我們一般用從IPropertyBag得到的名字。
  方法IMoniker::ParseDisplayName和MkParseDisplayName可以用來生成指定filter類型的設備的moniker。名字以“@device:*:{category-clsid}”,代表了類型的GUID,默認的moniker是設備枚舉器中的第一個moniker。
  
  //視頻捕獲類型
  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 Filter.
   pMoniker->Release();
  }

最後更新:2017-04-03 14:54:18

  上一篇:go Heap updates are NOT ENABLED
  下一篇:go directdraw顯示yuv420(YV12)