Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.07.25;
Скачать: CL | DM;

Вниз

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;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.039 c
1-1120648034
td
2005-07-06 15:07
2005.07.25
объявить процедуру


1-1120547296
Slaga
2005-07-05 11:08
2005.07.25
Можно ли экспортировать из dll - overload процедуры


14-1120485130
raidan
2005-07-04 17:52
2005.07.25
Амнистии


3-1118820940
d_oleg
2005-06-15 11:35
2005.07.25
TClientDataSet - параметры полей


14-1120423608
Knight
2005-07-04 00:46
2005.07.25
П-270 в Москве и Питере...