Форум: "Потрепаться";
Текущий архив: 2005.07.25;
Скачать: [xml.tar.bz2];
ВнизC++ Абстрактность неабстрактоного класса Найти похожие ветки
← →
Juice © (2005-07-04 12:45) [0]Знаю что тут много хорошо знающих c++, поэтому извините за тематику. С++ Builder.
С помощью мастера File/New/ActiveX/Automation Object я создал класс TMyOutlookEventsImpl. При попытке создания экземпляра этого класса (EventInterface = new TMyOutlookEventsImpl
) выдается ошибка :
[C++ Error] Unit1.cpp(30): E2352 Cannot create instance of abstract class "TMyOutlookEventsImpl"
[C++ Error] Unit1.cpp(113): E2353 Class "TMyOutlookEventsImpl" is abstract because of "__stdcall TMyOutlookEventsImpl::AddRef() = 0"
Насколько я понимаю , мне самостоятельно надо определить функцию-член AddRef ? Странно конечно, ведь она должна быть определена в билдеровских библиотеках ...
Я попытался обьявить ее так :
virtual ULONG STDMETHODCALLTYPE TMyOutlookEventsImpl::AddRef()
{
//AddRef();
}
Проблема осталась. И в чем смысл всей этой билдеровской жути ? Я перевожу код по обработке сообщений ole-сервера из Delphi, где все было создано аналогичным образом и работает отлично.
← →
Ega23 © (2005-07-04 13:59) [1]Могу ошибаться, но в С++ вроде как запрещено создание инстансов абстрактных классов. Более того, класс считается абстрактным, если у него есть хотя бы один абстрактный метод.
Попробуй создать потомка от своего класса и переопредели все абстрактные методы предка.
← →
wicked © (2005-07-04 14:36) [2]> Juice ©
попробуй в имплементации класса вызывать методы предка - ты же наследуешься от IUnknown...
или, как более жизнеспособный вариант - реализовать reference count самому (AddRef(), Release(), QueryInterface())...
ЗЫ почему из изящной COM сделали такое страшилище (ATL) - ума не приложу... но комплекс неполноценности гложет нещадно... ;)
> Ega23 © (04.07.05 13:59) [1]
не ошибся - абстрактные инстансы нигде не вольно создавать... а поинтеры на них - сколько угодно... на том весь COM для си++ держится...
← →
Juice © (2005-07-04 18:25) [3]Спасибо, так оно и было, унаследовал класс, определил три этих метода - заработало. Теперь другая проблема -
Есть такой код:
Variant oApp, oNs1;
oApp = CreateOleObject("outlook.application");
oNs1 = oApp.OleFunction("GetNameSpace", "MAPI");
IConnectionPointContainer * oContain = dynamic_cast<IConnectionPointContainer*>( oNs1.OlePropertyGet("SyncObjects").OleFunction("Item",1) ); // Вот тут ошибка, что мол каст невозможен
Но как преобразовать вариант в IConnectionPointContainer* ? Мне дальше по ходу программы нужно работать с Item именно как с IConnectionPointContainer.
← →
Ломброзо © (2005-07-04 18:37) [4]Juice © (04.07.05 18:25)
Спасибо, так оно и было, унаследовал класс, определил три этих метода - заработало. Теперь другая проблема -
Есть такой код:
Variant oApp, oNs1;
oApp = CreateOleObject("outlook.application");
oNs1 = oApp.OleFunction("GetNameSpace", "MAPI");
IConnectionPointContainer * oContain = dynamic_cast<IConnectionPointContainer*>( oNs1.OlePropertyGet("SyncObjects").OleFunction("Item",1) ); // Вот тут ошибка, что мол каст невозможен
Но как преобразовать вариант в IConnectionPointContainer* ? Мне дальше по ходу программы нужно работать с Item именно как с IConnectionPointContainer.
фффФФФфф. Всё мучаетесь? Ню-ню.
Вариант 1.
QueryInterface"ом опросить этот Ваш итем на IConnectionPointContainer
IDispatch *pDisp = oNs1.OlePropertyGet("SyncObjects").OleFunction("Item",1);
IConnectionPointContainer *pContainer = null;
HRESULT hr = pDisp->QueryInterface(__uuidof(IConnectionPointContainer), (void**)&pContainer);
анализируем hr и проверяем pContainer на null. Далее аналогично цепочке требуем IConnectionPoint и т.д.
Блин, всё это в MSDN есть.
2. Я уже упоминал темплейт IDispEventImpl<>. В этом случае вообще всё просто: включаем ATL, пишем класс, который подсовываем этому темплейту, реализуем методы-колбэки при помощи ATL-ных макросов. Пример не дам, писал давно и ничего без MSDN не вспомню.
--------
DMJS 0.6 | http://dmjsclient.narod.ru
← →
Ломброзо © (2005-07-04 18:41) [5]Поцказка: у Variant должно быть поле pdispVal. Которое суть IDispatch. не знаю, как у борландовой реализации, но в ATL есть три класса: VARIANT, _variant_t и CComVariant, во всех трёх имеется способ достучаться до IDispatch.
← →
Ломброзо © (2005-07-04 18:49) [6]В общем, дуйте на msdn.microsoft.com, поиск по ключевым словам BEGIN_SINK_MAP, END_SINK_MAP, SINK_ENTRY, IDispEventImpl
← →
Juice © (2005-07-04 19:27) [7]
> Блин, всё это в MSDN есть.
Тема очень сложная, пробовал читать, очень сложно что-то понять.
>
> 2. Я уже упоминал темплейт IDispEventImpl<>. В этом случае
> вообще всё просто: включаем ATL, пишем класс, который подсовываем
> этому темплейту, реализуем методы-колбэки при помощи ATL-ных
> макросов. Пример не дам, писал давно и ничего без MSDN не
> вспомню.
Я с ATL никогда не работал, боюсь что это еще сложнее будет, тем более что проблема уже почти решена.
Я воспользовался вашей подсказкой и программа компильнулась (ура!)
Однако, осталась последняя, как мне кажется, проблема: ничего не происходит. Вот весь значимый код:
IConnectionPoint* ESink;
oApp = CreateOleObject("outlook.application");
oNs = oApp.OleFunction("GetNameSpace", "MAPI");
IDispatch *pDisp = oNs.OlePropertyGet("SyncObjects").OleFunction("Item",1);
IConnectionPointContainer *pContainer = NULL;
HRESULT hr = pDisp->QueryInterface(__uuidof(IConnectionPointContainer), (void**)&pContainer);
if (EventInterface == NULL) EventInterface = new TMyOutlookEvents;
switch ( pContainer->FindConnectionPoint(Outlook_tlb::DIID_SyncObjectEvents, &ESink) )
{
case S_OK : ShowMessage("OK"); break;
case E_POINTER : ShowMessage("POINTER"); break;
case CONNECT_E_NOCONNECTION : ShowMessage("NOCONNECTION"); break;
}
IDispatch *pDisp1 = EventInterface;
IUnknown *pUnkSink = NULL;
HRESULT hr1 = pDisp1->QueryInterface(__uuidof(IMyOutlookEvents), (void**)&pUnkSink);
//switch ( ESink->Advise(dynamic_cast<IUnknown*>(EventInterface), FUserID) )
switch ( ESink->Advise(pUnkSink, FUserID) )
{
case S_OK : ShowMessage("S_OK"); break;
case E_POINTER : ShowMessage("E_POINTER"); break;
case CONNECT_E_ADVISELIMIT : ShowMessage("CONNECT_E_ADVISELIMIT"); break;
case CONNECT_E_CANNOTCONNECT : ShowMessage("CONNECT_E_CANNOTCONNECT"); break;
default : ShowMessage("OTHER!");
}
oNs.OlePropertyGet("SyncObjects").OleFunction("Item",1).OleFunction("Start");
Выводится "OK", затем "OTHER!". Получается что проблема с адвайсом ? Но что ж там такое может быть ? Как видите я пробовал получать пердаваемый этой функции интерфейс иначе.
← →
Juice © (2005-07-04 20:26) [8]Кажется проблема в том как я реализовал функцию QueryInterface :
HRESULT STDMETHODCALLTYPE TMyOutlookEvents::QueryInterface(REFIID riid, void** ppObj)
{
if (riid == IID_IUnknown)
{
*ppObj = static_cast<IUnknown*>(this);
}
else if (riid == IID_IMyOutlookEvents)
{
*ppObj = static_cast<IMyOutlookEvents*>(this);
}
else
{
*ppObj = NULL;
return E_NOINTERFACE ;
}
AddRef();
return S_OK;
}
Страницы: 1 вся ветка
Форум: "Потрепаться";
Текущий архив: 2005.07.25;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.012 c