Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   [решено] *DirectShow* | не работает пример из SDK (http://forum.oszone.net/showthread.php?t=151965)

pva 01-10-2009 08:33 1231732

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


Delirium 01-10-2009 08:38 1231736

Цитата:

Цитата pva
У меня почему-то пример из MSDN »

А какая версия MSDN? Их документация часто страдает опечатками и неточностями.

pva 01-10-2009 12:52 1231889

Цитата:

Цитата Delirium
А какая версия MSDN? »

Которая у них на сайте в онлайне

Проблема решена очень просто: ти ли я недоглядел, то ли они лоханулись, если сделать всё по аналогии с описанием группы интерфейсов IEnumXXXX, то получается так:
Код:

// дописал wostream& operator<<(wostream&, const GUID&);
// дописал log_message(const wstring&); которая добавляет строчку в ListView

    unsigned long cnt_fetched = 0;
    IMoniker* dev_item_val[1]; // здесь изменение
    // беру только по одному объекту за раз (хотя можно и по 100 взять),
    // только чтобы соблюсти правила безопасных исключений C++

    while (log_error(filter_mons->Next(1, dev_item_val, &cnt_fetched)) && cnt_fetched)
    {
        com_object<IMoniker> dev_item(&dev_item_val[0], 0);

        {
            GUID dev_guid;
            wchar_t* str_name;
            stop_error(dev_item->GetClassID(&dev_guid));
            stop_error(dev_item->GetDisplayName(0, 0, &str_name));

            wostringstream ss;
            ss << dev_guid << str_name;
            __alloc->Free(str_name);

            log_message(ss.str());
        }

        IPropertyBag* prop_bag_val;
        com_object<IPropertyBag> prop_bag(&prop_bag_val,
            dev_item->BindToStorage(0, 0, IID_IPropertyBag, (void**)&prop_bag_val));

        variant<wstring> var_str;
        if (log_error(prop_bag->Read(L"FriendlyName", var_str.arg(), 0)))
        {
            log_message(var_str.value());
        }
    }

И ещё использовал IFilterMapper2 чтобы получить список моникеров устройств. По крайней мере так сработало правильно.
Появились новые вопросы, некоторые помещу в другое темы; Тов. модератор, если сочтёшь нужным, собери обратно в одну тему

Вопрос: имя фильтра DirectShow содержит 2 классида: категория и устройство. Как их можно попрость COM узнать, что соответствует этим классидам? Через IPropertyBag? как узнать, какие вообще свойства есть в IPropertyBag (у меня не получилось создать IPropertyBag2, который это умеет)?

pva 03-10-2009 12:47 1233388

пример заработал, был косяк в месте IEnumMoniker, нашёл способ получить описание фильтров: http://forum.oszone.net/thread-151991.html
чтобы получить список категорий: http://msdn.microsoft.com/en-us/libr...55(VS.85).aspx

вот что меня удивляет - это как с этим косяком у других работает, кто исходники в инете выкладывает.. у меня ни один не заработал


Время: 14:57.

Время: 14:57.
© OSzone.net 2001-