Приведение пойнтера на интерфейс к пойнтеру на объект класса
От: -=chp=- Россия http://chpfilms.boom.ru
Дата: 12.11.04 18:47
Оценка:
Есть класс:

class ATL_NO_VTABLE CSignal : //!< Signal object
public IDispatchImpl<ISignal, &IID_ISignal, &LIBID_UnitVwLib>,
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CSignal>
{
...
}


Создаю объект класса.

ISignal *p = NULL;
if (CSignal::CreateInstance(&p) == S_OK && p != NULL)
{

Хочу получить по пойнтеру на интерфейс пойнтер на объект класса. Дабы использовать методы которые не торчат через интерфейс. Работает. Но в случае если я определяю _ATL_DEBUG_INTERFACES все перестает работать потому что приведение работает некорректно (приводится не к тому чему ожидалось). Чувствую что я серьезно напортачил с архитектурой .

m_pSignal = (CSignal *)p;
...
}

Собственно чего хочется — есть интерфейс который видно через IDispatch. И есть некий скрытый интерфейс, который никому не видно кроме собственно этого компонента. Как это реализуется идеологически правильно?

Заодно можно ли сделать идеологически правильной мою схему с приведениями типов или в морг?
Re: Приведение пойнтера на интерфейс к пойнтеру на объект кл
От: migel  
Дата: 12.11.04 21:16
Оценка:
Здравствуйте, -=chp=-, Вы писали:


C>Заодно можно ли сделать идеологически правильной мою схему с приведениями типов или в морг?

Дык заведи просто внутренний интерфейс и назначь ему приватный — гуид
Что-то типа такого

extern const IID IID_IInternalPageSafe;
MIDL_INTERFACE("0A9CEC92-62B1-47dc-B5A3-E3F0E76E5BD2")
IInternalPageSafe : public IUnknown
{
    virtual CXFormObject* GetUnderlayingForm() = 0;
};

// CPage

class ATL_NO_VTABLE CPage : 
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CPage, &CLSID_Page>,
    public IPersistStorageImpl<CPage>,
    public IPersistStreamInitImpl<CPage>,
    public IPersistPropertyBagImpl<CPage>,
    public IDispatchImpl<IPage, &IID_IPage, &LIBID_XFormLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
    public IInternalPageSafe,
    public IPropertyNotifySink
{
BEGIN_COM_MAP(CPage)
    COM_INTERFACE_ENTRY(IPage)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(IInternalPageSafe)
}


// {0A9CEC92-62B1-47dc-B5A3-E3F0E76E5BD2}
static const GUID IID_IInternalPageSafe =
{ 0xa9cec92, 0x62b1, 0x47dc, { 0xb5, 0xa3, 0xe3, 0xf0, 0xe7, 0x6e, 0x5b, 0xd2 } };

Дальше используй обычно через QueryInterface()

        CComPtr<IInternalPageSafe> spSafe;
        // pPage - объект который реализует скрытый интерфейс
        if (FAILED(pPage->QueryInterface(IID_IInternalPageSafe, (void**)&spSafe)))
            return E_NOINTERFACE;
... << RSDN@Home 1.1.4 beta 3 rev. 190>>
Re[2]: Приведение пойнтера на интерфейс к пойнтеру на объект
От: Ivan Россия www.rsdn.ru
Дата: 16.11.04 11:44
Оценка:
Здравствуйте, migel, Вы писали:

> m_pSignal = (CSignal *)p;

это неправильно. если CSignal реализует несколько интерфейсов, то указатели на разные интерфейсы будут отличаться друг от друга и от адреса самого объекта.

M>Дык заведи просто внутренний интерфейс и назначь ему приватный — гуид


гораздо проще:
BEGIN_COM_MAP(CSignal)
   COM_INTERFACE_ENTRY(ISignal)
   COM_INTERFACE_ENTRY_IID(CLSID_Signal, CSignal)
END_COM_MAP()


технология вполне нормальная, но есть пара особенностей:
— не работает если есть маршалинг
— при включенном ATL_DEBUG_INTERFACES QueryInterface будет возвращать указатель на QIThunk, его нужно убирать вручную, например, так:
ISignal* pItf = ...;
CSignal* pSignal = 0;

pItf->QueryInterface(CLSID_Signal, &pSignal);
#ifdef _ATL_DEBUG_INTERFACES
    _QIThunk* pThunk = reinterpret_cast<_QIThunk*>(pSignal);
    pSignal = reinterpret_cast<CSignal*>(pThunk->m_pUnk);
    _AtlDebugInterfacesModule.DeleteThunk(pThunk);
#endif

...
pSignal->Release();
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.