Здравствуйте LoneTiger, вы писали:
LT>Тогда вопрос: а где бы про все эти хитрости почитать? Я вот, например, не сталкивался нигде с упоминанием того факта, что в IDispatch нельзя использовать out. Откуда эта информация?
Ну, кое что есть у нас на сайте
www.optim.ru/sc , а можно и здесь. Основной материал в MSDN (но мало и найти тяжело), Iinside OLE помогает... но главное это хорошенько потрахаться. Обычно достаточно года 3-4. :( Особо помогает трах с VB (5 — 6).
LT>Да я просил объяснить, КАК это будет работать. Как это работает с IDispatch, я понимаю. Как это будет работать в случае обычного недуального интерфейса, я, честно говоря, не представляю. Можно хотя бы ссылочку какую-нибудь?
Дык я тебе и обяснил так же как с диспачем.
Вот примеры кода из нашего ascDB:
[
uuid(06E6E491-CCEF-11d3-AEA9-004095E1F072),
helpstring("ascColumn Class")
]
coclass ascColumn
{
[default] interface IascColumn;
[default, source] interface _IascColumnEvents;
};
[
object,
uuid(06E6E490-CCEF-11d3-AEA9-004095E1F072),
helpstring("_IascColumnEvents Interface"),
pointer_default(unique)
]
interface _IascColumnEvents : IUnknown
{
[id(acdName), helpstring("method AfterNameChanged")]
HRESULT AfterNameChanged([in] BSTR NewName);
[id(acdType), helpstring("method AfterTypeChanged")]
HRESULT AfterTypeChanged([in] ASC_COLUMN_DATA_TYPE NewType);
...
};
template <class T>
class CProxy_IascColumnsEvents : public IConnectionPointImpl<T, &IID__IascColumnsEvents, CComDynamicUnkArray>
{
//Warning this class may be recreated by the wizard.
public:
HRESULT Fire_AfterNameChanged(LONG ColumnNumber, BSTR NewName)
{
T* pT = static_cast<T*>(this);
if(pT->EventsFreezed())
return S_FALSE;
HRESULT ret = S_FALSE;
int nConnections = m_vec.GetSize();
for (int nConnectionIndex = 0; nConnectionIndex < nConnections && SUCCEEDED(ret); nConnectionIndex++){
pT->Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
_IascColumnsEvents* p_IascColumnsEvents = reinterpret_cast<_IascColumnsEvents*>(sp.p);
if (p_IascColumnsEvents != NULL)
ret = p_IascColumnsEvents->AfterNameChanged(ColumnNumber, NewName);
}
ASC_RETURN_FAILED(ret);
return S_OK;
}
HRESULT Fire_AfterTypeChanged(LONG ColumnNumber, ASC_COLUMN_DATA_TYPE NewType)
{
T* pT = static_cast<T*>(this);
if(pT->EventsFreezed())
return S_FALSE;
HRESULT ret = S_FALSE;
int nConnections = m_vec.GetSize();
for (int nConnectionIndex = 0; nConnectionIndex < nConnections && SUCCEEDED(ret); nConnectionIndex++){
pT->Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
_IascColumnsEvents* p_IascColumnsEvents = reinterpret_cast<_IascColumnsEvents*>(sp.p);
if (p_IascColumnsEvents != NULL)
ret = p_IascColumnsEvents->AfterTypeChanged(ColumnNumber, NewType);
}
ASC_RETURN_FAILED(ret);
return S_OK;
}
...
};
В классе к которому подключаются события добавляем:
BEGIN_CONNECTION_POINT_MAP(CascColumns)
CONNECTION_POINT_ENTRY(IID__IascColumnsEvents)
END_CONNECTION_POINT_MAP()
И наследуем его от:
CProxy_IascColumnsEvents
Клиент реализует интерфейс _IascColumnsEvents и подключается через Advise. Собственно все! И никакой разницы с диспачным вариантом. А вот с дуал-интерфейсом это прокатит только если и клиент и сервер написан на сях. VB реализует только диспачную часть и при вызове нормальной произойдет AV. Если же вызывать только диспачную часть, то нахреда делать сам интерфейс дуальным.