Код:
Код: Выделить всё
// есть шаблон com_object, который выполняет IUnknown::Release(),
// функции stop_error и log_error, которые сообщают результат HRESULT,
// stop* выдаёт исключение в случае ошибки, log* возвращает булевскую удачу-неудачу.
IEnumMoniker *dev_enum_val = 0;
// получаем перечислитель устройств
// com_object::com_object(Interface** intf, HRESULT hr) проверяет stop_error(hr) и инициализирует
// указатель на интерфейс значением *intf
com_object dev_enum(&dev_enum_val,
// com_object::com_object(const GUID&) использует CoCreateInstance для создания объекта
com_object(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 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 prop_bag(&prop_bag_val, 0);
// меня устраивает любое из свойств
variant 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
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 com_object(com_object const&);
Interface* operator->() throw() {return _ptr;}
Interface* get() const throw() {return _ptr;}
private:
Interface* _ptr;
};
template
com_object::com_object(const GUID& type_id, IUnknown* parent) : _ptr()
{
stop_error(CoCreateInstance(type_id, parent, CLSCTX_INPROC_SERVER, id(), reinterpret_cast(&_ptr)));
}
template com_object::com_object(Interface** outer_interface, HRESULT hr) : _ptr(*outer_interface)
{
stop_error(hr);
if (!*outer_interface) throw runtime_error("got null interface");
}
template template
com_object::com_object(com_object const& other) : _ptr()
{
stop_error(other.get()->QueryInterface(id(), reinterpret_cast(_ptr)));
}
// шаблон variant
template
class variant
{
public:
static const VARTYPE type_id();
~variant() {VariantClear(&_arg);}
variant() {VariantInit(&_arg);}
variant(const variant& v2) {VariantCopy(&_arg, &v2._arg);}
template
variant(const variant& 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::type_id(){return VT_UI4;}
template unsigned variant::value() const {return _assert_value().lVal;}
template const VARTYPE variant::type_id() {return VT_I4;}
template int variant::value() const {return _assert_value().ulVal;}
template const VARTYPE variant::type_id() {return VT_R4;}
template float variant::value() const {return _assert_value().fltVal;}
template const VARTYPE variant::type_id() {return VT_R8;}
template double variant::value() const {return _assert_value().dblVal;}
template const VARTYPE variant::type_id() {return VT_BSTR;}
template wstring variant::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 Специализация шаблона com_object для идентификации интрефейсов (простое правило):
Код:
Код: Выделить всё
#include
#include
#include
template GUID const& com_object::id() {return IID_ICreateDevEnum;}
template GUID const& com_object::id() {return IID_IPropertyBag;}
template GUID const& com_object::id() {return IID_IBaseFilter;}
template GUID const& com_object::id() {return IID_ICaptureGraphBuilder2;}
template GUID const& com_object::id() {return IID_IGraphBuilder;}
template GUID const& com_object::id() {return IID_IVideoWindow;}
template GUID const& com_object::id() {return IID_IMediaControl;}