Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Наследование com-интерфейсов, Ошибки при QueryInterface 
:(
    Опции темы
Proxin
Дата 20.9.2016, 22:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 362
Регистрация: 21.6.2008

Репутация: нет
Всего: 3



Всем привет, возник вопрос. Хочу создать com-интрефейс, и от него же унаследовать ещё один
Код

interface __declspec(uuid("...")) IMyInterface
{
virtual char fA() = 0;
}

interface __declspec(uuid("..")) ISomeOther : public virtual IMyInterface
{
virtual char fB() = 0;
}


Делаю их реализацию
Код

class CMyInterface : public virtual IMyInterface
{
 ...
 virtual char fA();
 ...
}
class CSomeOther : public CMyInterface,  public ISomeOther
{
 ...
 virtual char fB();
 ..
};


Но при попытке вызвать QueryInterface для интерфейса ISomeOther и IMyInterface из delphi, с указателем на мой объект класса CSomeOther и CMyInterface соответственно, вылетает исключение. В чём здесь ошибка? Мне нужно что-то типа виртуального наследования классов в с++, чтобы в ISomeOther можно было вызывать и fA(), и fB(). Насколько прочитал, это невозможно, в com-интерфейсах класс-реализатор должен явно имплементировать все методы интерфейсов, на которые он опирается. Что с этим можно сделать?

Это сообщение отредактировал(а) Proxin - 20.9.2016, 22:39
PM MAIL   Вверх
xvr
Дата 21.9.2016, 11:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 6984
Регистрация: 28.8.2007
Где: Химки, Московская обл

Репутация: 8
Всего: 222



Как у вас реализован метод QueryInterface в классах CMyInterface и CSomeOther ? В последнем он должен уметь отдавать оба интерфейса (IMyInterface и ISomeOther), а в первом - только один (IMyInterface)

Цитата(Proxin @  20.9.2016,  22:37 Найти цитируемый пост)
Насколько прочитал, это невозможно, в com-интерфейсах класс-реализатор должен явно имплементировать все методы интерфейсов, на которые он опирается.

Имплементировать можно по разному, в том числе и с помощью наследования реализации (что вы и пытались сделать)

PM MAIL   Вверх
Proxin
Дата 21.9.2016, 13:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 362
Регистрация: 21.6.2008

Репутация: нет
Всего: 3



в, общем, вот так вот у меня
Код

interface IMyInterface : public virtual IUnknown
{
...
char __cdecl fA( void ) = 0;
...
};

interface ISomeOther : public virtual IMyInterface
{
...
char __cdecl fB( void ) = 0;
...
};

class CMyInterface : public virtual IMyInterface
{
 public:
 CMyInterface() { };
 virtual ~CMyInterface() { };
 virtual        HRESULT            __stdcall                                    QueryInterface( const IID &riid, void** ppvObject );
 virtual        ULONG            __stdcall                                    AddRef( void );
 virtual        ULONG            __stdcall                                    Release( void );
 ...
 virtual char __cdecl fA();
};

class CSomeOther : public CMyInterface, public ISomeOther
{
 public:
 CMyInterface() { };
 virtual ~CMyInterface() { };
 virtual        HRESULT            __stdcall                                    QueryInterface( const IID &riid, void** ppvObject );
 ...
 virtual char __cdecl fB();
};

...

HRESULT        __stdcall                                                    CMyInterface::QueryInterface( const IID &riid, void** ppvObject )
{
    if    ( riid == __uuidof(IUnknown) )
        *ppvObject                                                                =    (IUnknown*)this;
    else if ( riid == __uuidof(IMyInterface) )
        *ppvObject                                                                =    (IMyInterface*)this;
    else
    {
        *ppvObject                                                                =    NULL;
        return                                                                    E_NOINTERFACE;
    }
    ((IUnknown*)*ppvObject)->AddRef();
    return                                                                        S_OK;
}

...

HRESULT        __stdcall                                                    CSomeOther::QueryInterface( const IID &riid, void** ppvObject )
{
    if    ( riid == __uuidof(IUnknown) )
        *ppvObject                                                                =    (IUnknown*)this;
    else if ( riid == __uuidof(IMyInterface) )
        *ppvObject                                                                =    (IMyInterface*)this;
    else if ( riid == __uuidof(ISomeOther) )
        *ppvObject                                                                =    (ISomeOther*)this;
    else
    {
        *ppvObject                                                                =    NULL;
        return                                                                    E_NOINTERFACE;
    }
    ((IUnknown*)*ppvObject)->AddRef();
    return                                                                        S_OK;
}
....
// дальше код для примера
IUnknown* p = (IUnknown*)new CSomeOther();
ISomeOther* pSomeOther = NULL;
p->QueryInterface(__uuidof(ISomeOther),(void**)&pSomeOther);

входит в метод QueryInterface обьекта CSomeOther, вылетает на строке AddRef()
upd
понял, кажется, в чём ошибка, но как её избежать - нет. АddRef надо проводить непосредственно к тому типу, которого есть этот объект. Если брать IUnknown, то ловлю акцесс виолейшон в c++, и, соответсвтенно, приведение полученого указателя методом IInterface(Ptr) в процедуре supports ( в дельфи ) и даёт исключение. Как с этим быть?
почесав голову, добавляю. в дельфи получилось сделать IUnknown(Ptr).QueryInterface(ISomeOther,pSomeOther), Ptr получил простой экспортируемой функцией из dlll, которая возварщает мне объект типа IUnknown*, который получен с помощью dynamic_cast. с++ в ответ на QueryInterface мне передаёт dynamic_cast<ISomeOther*>(this).
но при этом при вызове метода pB из pSomeOther со свежеполученного интерфейса опять валится av. интерфейс в дельфи задекларирован так же, как  и в c++, с поправками:
Код

IMyInterface = interface(IUnknown)
[".."]
function pA() : AnsiChar; cdecl;
end;
ISomeOther = interface(IMyInterface)
[".."]
function pB() : AnsiChar; cdecl;
end;


Это сообщение отредактировал(а) Proxin - 21.9.2016, 14:49
PM MAIL   Вверх
xvr
Дата 21.9.2016, 17:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 6984
Регистрация: 28.8.2007
Где: Химки, Московская обл

Репутация: 8
Всего: 222



В в качестве ppvObject случайно не NULL передали?

Цитата(Proxin @  21.9.2016,  13:16 Найти цитируемый пост)
 АddRef надо проводить непосредственно к тому типу, которого есть этот объект.

Не обязательно. У вас один и тот же экземпляр AddRef на все ваши интерфейсы. так что ломаться не должно. кстати, в QueryInterface можно просто позвать AddRef, без всяких указателей.

Цитата(Proxin @  21.9.2016,  13:16 Найти цитируемый пост)
 приведение полученого указателя методом IInterface(Ptr) в процедуре supports ( в дельфи ) и даёт исключение.

Не должно. Проверьте, что в Ptr

Цитата(Proxin @  21.9.2016,  13:16 Найти цитируемый пост)
которая возварщает мне объект типа IUnknown*, который получен с помощью dynamic_cast.

А вот это неправильно. У вас по факту 2 штуки IUnknown интерфейсов - один в составе IMyInterface, второй в составе ISomeOther. QuaryInterface должна возвращать один и тот же указатель для запросов IUnknown через любой из своих интерфейсов. dynamic_cast это не гарантирует.

Цитата(Proxin @  21.9.2016,  13:16 Найти цитируемый пост)
с++ в ответ на QueryInterface мне передаёт dynamic_cast<ISomeOther*>(this).

Не вижу в коде QueryInterface никаких dynamic_cast

Кстати, а как у вас сами объекты (CMyInterface и CSomeOther) создаются? Может они вообще не инициализированны?  Тогда будет валится.

PM MAIL   Вверх
Proxin
Дата 21.9.2016, 18:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 362
Регистрация: 21.6.2008

Репутация: нет
Всего: 3



Нет, у меня объекты в с++ dll создаются по-нормальному.
Код

CSomeOther* pSomeOther = new CSomeOther();

вычистил все динамик-касты, ради интереса, QueryInterface у меня, как в предыдущем сообщении. Попробовал тут же получить указатель на свой интерфейс для последующего использования, как хочу сделать в дельфи.
Код

IUnknown* __cdecl GetSomeOther(void)
{
 return (IUnknown*)pSomeOther;
}

...

IUnknown* iMyOther = GetSomeOther();
ISomeOther* newSomeOtherInterface = NULL;
iMyOther->QueryInterface(__uuidof(ISomeOther),(void**)&newSomeOtherInterface);
newSomeOtherInterface->pA();
newSomeOtherInterface->pB();

всё работает, как часы.
тут же в дельфи делаю ( программа - хост для сишной длл, длл полностью загружена и инициализирована )
Код

var
  SomeOther : ISomeOther = NIL;
  MyUnknownPointer : IUnknown;
...

MyUnknownPointer = GetSomeOther();
IUnknown(MyUnknownPointer).QueryInterface(ISomeOther,SomeOther);
// в результате приходит S_OK, дебаггер показывает, что присваивание вызывается, в СSomeOther::QueryInterface входит как надо, в SomeOther появляется указатель на мой объект pSomeOther из с++ dll
SomeOther.pA(); // при выполнении возникает acess violation at 0x0
SomeOther.pB(); // при выполнении возникает acess violation at 0x0

И что с этим делать? Все мозги уже себе сломал.
И да, при одиночном наследовании ( только от IUnknown, без второго уровня, и, соответственно без virtual в реализации сишных классов ) интерфейсы вышеозначенным путём в дельфи возвращаются и используются абсолютно корректно.

Это сообщение отредактировал(а) Proxin - 21.9.2016, 21:42
PM MAIL   Вверх
xvr
Дата 21.9.2016, 22:07 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 6984
Регистрация: 28.8.2007
Где: Химки, Московская обл

Репутация: 8
Всего: 222



Ой! Только сейчас заметил:
Код

interface IMyInterface : public virtual IUnknown ...
interface ISomeOther : public virtual IMyInterface ...
class CMyInterface : public virtual IMyInterface ...
это работать не будет. Уберите virtual из списка родителей. Должно быть
Код

interface IMyInterface : public IUnknown ...
interface ISomeOther : public IMyInterface ...
class CMyInterface : public IMyInterface ...


virtual в наследовании делает нечто, что несовместимо ни с кем (в том числе и с COM)

PM MAIL   Вверх
Proxin
Дата 21.9.2016, 23:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 362
Регистрация: 21.6.2008

Репутация: нет
Всего: 3



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

class CSomeOther : public CMyInterface, public ISomeOther

при создании экземпляра через new при компиляции вываливается " can not create, because IMyInterface::pA() = 0". Или не канифолить себе мозги, а заново описать метод pA(), который явно вызывает this->CMyInterface::pA()? Пока вкуриваю Inside the Com от Дэйла Роджерсона, он, в частности, предлагает создание экземпляра класса-агрегатора с суперсчётчиком ссылок, и перенаправлением всех методов вручную в этот m_ImyInterface. Неужели это единственный способ?

Это сообщение отредактировал(а) Proxin - 21.9.2016, 23:35
PM MAIL   Вверх
xvr
Дата 22.9.2016, 00:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 6984
Регистрация: 28.8.2007
Где: Химки, Московская обл

Репутация: 8
Всего: 222



Цитата(Proxin @  21.9.2016,  23:35 Найти цитируемый пост)
при создании экземпляра через new при компиляции вываливается " can not create, because IMyInterface::pA() = 0".

Не должно вроде. Можете показать реальный кусок кода, где описаны классы?

PM MAIL   Вверх
Google
  Дата 23.5.2019, 18:43 (ссылка)  





  Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: COM/DCOM/ActiveX/ATL/CORBA | Следующая тема »


 




[ Время генерации скрипта: 0.0856 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.