如何使用係統設備枚舉器
係統設備枚舉器為我們按類型枚舉已注冊在係統中的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