Есть класс:
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. И есть некий скрытый интерфейс, который никому не видно кроме собственно этого компонента. Как это реализуется идеологически правильно?
Заодно можно ли сделать идеологически правильной мою схему с приведениями типов или в морг?
Здравствуйте, -=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>>
Здравствуйте, 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();