*DirectShow* | не работает пример из SDK
Здравствуйте мною глубокоуважаемые обитатели форума, да восхвалится имя ваше (во веки веков). У меня почему-то пример из MSDN перечисления устройств DirectShow захвата видео работает не так, как там описано:
Код:
// есть шаблон com_object<typename Interface>, который выполняет IUnknown::Release(),
// функции stop_error и log_error, которые сообщают результат HRESULT,
// stop* выдаёт исключение в случае ошибки, log* возвращает булевскую удачу-неудачу.
IEnumMoniker *dev_enum_val = 0;
// получаем перечислитель устройств
// com_object<Interface>::com_object<Interface>(Interface** intf, HRESULT hr) проверяет stop_error(hr) и инициализирует
// указатель на интерфейс значением *intf
com_object<IEnumMoniker> dev_enum(&dev_enum_val,
// com_object<Interface>::com_object<Interface>(const GUID&) использует CoCreateInstance для создания объекта
com_object<ICreateDevEnum>(CLSID_SystemDeviceEnum)->CreateClassEnumerator(
CLSID_VideoInputDeviceCategory, &dev_enum_val, 0));
// перебираем устройства внутри категории
IMoniker* dev_item_val=0;
while(!log_error(dev_enum->Next(1, &dev_item_val, 0))
{
com_object<IMoniker> dev_item(&dev_item_val, 0);
// я проверял, dev_item->GetDisplayName(0, 0, &name) даёт правильный результат,
// но дальше всё не по сценарию:
// получаем набор свойств устройства
IPropertyBag* prop_bag = 0;
if(log_error(dev_item->BindToStorage(0, 0, IID_IPropertyBag, (void **)&prop_bag_val)))
{
com_object<IPropertyBag> prop_bag(&prop_bag_val, 0);
// меня устраивает любое из свойств
variant<wstring> friendly_name;
if (
log_error(prop_bag->Read(L"Description", friendly_name.arg(), 0)) || // ошибка: неверный доступ к памяти
log_error(prop_bag->Read(L"FriendlyName", friendly_name.arg(), 0)) || // ошибка: неверный доступ к памяти
log_error(prop_bag->Read(L"Name", friendly_name.arg(), 0))) // ошибка: неверный доступ к памяти
{
// здесь, судя по примеру из MSDN, должно отображаться человеческое имя устройства
// но до сюда не доходит :(
MessageBoxW(Handle, friendly_name.value().c_str(), L"Enum", MB_OK);
}
}
}
вспомогательный код (если понадобится):
Код:
// шаблон com_object
void stop_error(HRESULT hr);
bool log_error(HRESULT hr);
template<typename Interface>
class com_object
{
public:
static const GUID& id();
~com_object() {_ptr->Release();}
com_object(const GUID& type_id, IUnknown* parent=0);
com_object(Interface** outer_interface, HRESULT hr);
com_object(com_object const& other) throw() : _ptr(other._ptr) {_ptr->AddRef();}
template<typename Interface2> com_object(com_object<Interface2> const&);
Interface* operator->() throw() {return _ptr;}
Interface* get() const throw() {return _ptr;}
private:
Interface* _ptr;
};
template<typename Interface>
com_object<Interface>::com_object(const GUID& type_id, IUnknown* parent) : _ptr()
{
stop_error(CoCreateInstance(type_id, parent, CLSCTX_INPROC_SERVER, id(), reinterpret_cast<void**>(&_ptr)));
}
template<typename Interface> com_object<Interface>::com_object(Interface** outer_interface, HRESULT hr) : _ptr(*outer_interface)
{
stop_error(hr);
if (!*outer_interface) throw runtime_error("got null interface");
}
template<typename Interface> template<typename Interface2>
com_object<Interface>::com_object(com_object<Interface2> const& other) : _ptr()
{
stop_error(other.get()->QueryInterface(id(), reinterpret_cast<void**>(_ptr)));
}
// шаблон variant
template<typename DataT>
class variant
{
public:
static const VARTYPE type_id();
~variant() {VariantClear(&_arg);}
variant() {VariantInit(&_arg);}
variant(const variant& v2) {VariantCopy(&_arg, &v2._arg);}
template<typename Data2>
variant(const variant<Data2>& v2) {VariantChangeType(&_arg, &v2._arg, 0, type_id());}
void reset() {VariantClear(&_arg);}
bool is_clear() const {return _arg.vt == VT_EMPTY;}
bool is_null() const {return _arg.vt == VT_NULL;}
bool is_error() const {return _arg.vt == VT_ERROR;}
DataT value() const;
// для вызовов API
VARIANT* arg() {return &_arg;}
private:
VARIANT _arg;
const VARIANT& _assert_value() const {
// проверка что именно нужного типа (а не VT_EMPTY например)
if (_arg.vt!=type_id()) throw logic_error("variant::_assert_value of different type");
return _arg;
}
};
template<> const VARTYPE variant<unsigned>::type_id(){return VT_UI4;}
template<> unsigned variant<unsigned>::value() const {return _assert_value().lVal;}
template<> const VARTYPE variant<int>::type_id() {return VT_I4;}
template<> int variant<int>::value() const {return _assert_value().ulVal;}
template<> const VARTYPE variant<float>::type_id() {return VT_R4;}
template<> float variant<float>::value() const {return _assert_value().fltVal;}
template<> const VARTYPE variant<double>::type_id() {return VT_R8;}
template<> double variant<double>::value() const {return _assert_value().dblVal;}
template<> const VARTYPE variant<wstring>::type_id() {return VT_BSTR;}
template<> wstring variant<wstring>::value() const {return wstring(_assert_value().bstrVal);}
Теперь отдельный вопрос про получение текстового описания сообщения об ошибке: У меня возничает ситуация, когда система не может выдать текстовое сообщение (FormatMessage выдаёт пустую строку). Как с этим бороться? Мне же надо знать, чем он недоволен
Код:
bool log_error(HRESULT hr)
{
if (hr)
{
hr &= 0xffff;
char *ddstr;
if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
0, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*) &ddstr, 0, 0))
{
MessageBoxA(0, ddstr, 0, MB_OK|MB_ICONERROR);
LocalFree(ddstr);
}
else
{
ostringstream ss;
ss << "Undefined error 0x" << hex << hr;
MessageBoxA(0, ss.str().c_str(), 0, MB_OK|MB_ICONERROR);
}
};
return hr==0;
}
void stop_error(HRESULT hr)
{
if (!log_error(hr))
{
throw runtime_error("check_error");
};
}
Специализация шаблона com_object для идентификации интрефейсов (простое правило):
Код:
#include <control.h>
#include <strmif.h>
#include <uuids.h>
template<> GUID const& com_object<ICreateDevEnum>::id() {return IID_ICreateDevEnum;}
template<> GUID const& com_object<IPropertyBag>::id() {return IID_IPropertyBag;}
template<> GUID const& com_object<IBaseFilter>::id() {return IID_IBaseFilter;}
template<> GUID const& com_object<ICaptureGraphBuilder2>::id() {return IID_ICaptureGraphBuilder2;}
template<> GUID const& com_object<IGraphBuilder>::id() {return IID_IGraphBuilder;}
template<> GUID const& com_object<IVideoWindow>::id() {return IID_IVideoWindow;}
template<> GUID const& com_object<IMediaControl>::id() {return IID_IMediaControl;}
|