Приемник событий
От: Kitty  
Дата: 13.06.07 14:37
Оценка:
Я хочу организовать прием событий идущих от COM объекта загруженного в OleConteiner. Обработка события будет происходить в Invoke.
Для начала реализовала класс:

#ifndef UDispatchH
#define UDispatchH
//---------------------------------------------------------------------------

#include <ComCtrls.hpp>
//---------------------------------------------------------------------------

class CMyCoolEventHandler : public IDispatch
{

public:

    CMyCoolEventHandler(REFIID  idd) : m_idd(idd)
    {
    }

    //CMyCoolEventHandler(){};
virtual ~ CMyCoolEventHandler(){};

 STDMETHODIMP_ (DWORD)AddRef();
 STDMETHODIMP_ (DWORD)Release();
 STDMETHODIMP QueryInterface(REFIID riid, void** ppv);


 STDMETHODIMP GetTypeInfoCount(UINT *pctinfo);
 STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
 STDMETHODIMP GetIDsOfNames (REFIID riid,  LPOLESTR *rgszNames,  UINT cNames,  LCID lcid,  DISPID *rgdispid);
 STDMETHODIMP Invoke(DISPID dispIdMember,
                  REFIID riid,
                  LCID lcid,
                  WORD wFlags,
                  DISPPARAMS* pDispParams,
                  VARIANT* pVarResult,
                  EXCEPINFO * pExcepInfo,
                  UINT * puArgErr);
private:
  REFIID  m_idd;
  ULONG m_ref;

};

#endif


Реализация класса:

#include <vcl.h>
#pragma hdrstop

#include "UDispatch.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

STDMETHODIMP_ (DWORD)CMyCoolEventHandler::AddRef()
{
  return ++m_ref;
}

STDMETHODIMP_ (DWORD)CMyCoolEventHandler::Release()
{
  --m_ref;
  if(m_ref==0)
    {
     delete this;
     return 0;
    }
   return m_ref;
}

STDMETHODIMP CMyCoolEventHandler::QueryInterface(REFIID riid, void** ppv)
{
  if(riid == IID_IUnknown)
     *ppv = (IUnknown*)this;

  else if(riid == IID_IDispatch)
     *ppv = (IDispatch*)this;


  else if(riid == m_idd)
       *ppv = this;

  else
       {
        *ppv = NULL;
        return E_NOINTERFACE;
       }
  ((IUnknown*)(*ppv))->AddRef();
  return S_OK;
}

STDMETHODIMP CMyCoolEventHandler::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
  ppTInfo = NULL;
  return S_OK;
}

STDMETHODIMP CMyCoolEventHandler::GetTypeInfoCount(UINT *pctinfo)
{
  *pctinfo = 0;
  return S_OK;
}

STDMETHODIMP CMyCoolEventHandler::GetIDsOfNames (REFIID riid,  LPOLESTR *rgszNames,  UINT cNames,  LCID lcid,  DISPID *rgdispid)
{
  return S_OK;
}

STDMETHODIMP CMyCoolEventHandler::Invoke(DISPID dispIdMember,
                  REFIID riid,
                  LCID lcid,
                  WORD wFlags,
                  DISPPARAMS* pDispParams,
                  VARIANT* pVarResult,
                  EXCEPINFO * pExcepInfo,
                  UINT * puArgErr)
{
 ShowMessage("Произошло событие");
 return S_OK;
}


Помогите, пожалуйста, написать код клиента:


//календарь C:\Program Files\Microsoft Office\OFFICE11\MSCAL.OCX
//календарь имеет интрефейс событий DCalendarEvents

//сам код:
//clsid получу от OleConteiner
IConnectionPointContainer* pICPC = NULL;
CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IConnectionPointContainer, (void**)&pICPC);

IConnectionPoint * pCP = NULL;
//здесь первым параметром в FindConnectionPoint надо писать IID_IDispatch или DIID календаря DIID_DCalendarEvents?
pICPC->FindConnectionPoint(Что тут?, &pCP);

ULONG cookie;
//что передать в g_sink(...)?
CMyCoolEventHandler g_sink(Что тут?);
pCP->Advise(&g_sink, &cookie);

//и дальше что пичать?
Re: Приемник событий
От: Аноним  
Дата: 14.06.07 00:21
Оценка:
Здравствуйте, Kitty, Вы писали:

HRESULT _result=S_OK;
IConnectionPointContainer* _connection = NULL;
IConnectionPoint* _point = NULL;
DWORD _cookie;
bool _connected=false;

_result = OBJECT_WITH_EVENTS->QueryInterface(IID_IConnectionPointContainer, (void**)&_connection);

if(SUCCEEDED(_result))
{
    //DIID_IEvents - event interface;
    _result = _connection->FindConnectionPoint(DIID_IEvents, &_point); 
    
    if (SUCCEEDED(_result))
    {
        _result = _point->Advise(POINTER_TO_IUNKNOWN_INTERFACE_OF_EVENT_HANDLER_OBJECT, &_cookie);

        if(SUCCEEDED(_result))
        {
            //Connected...
            _connected=true;
        };

        _point->Release();
    }
    _point->Release();
}

//...

if(_connected)
   _point->Unadvise();


AND

class YOUR_EVENT_HANDLER : public IDispEventImpl / IDispEventSimpleImpl<...>
{
 //...

 BEGIN_SINK_MAP
    SINK_ENTRY/SINK_ENTRY_EX/SINK_ENTRY_INFO
 END_SINK_MAP
};
Re: Приемник событий
От: Vi2 Удмуртия http://www.adem.ru
Дата: 14.06.07 04:07
Оценка:
Здравствуйте, Kitty, Вы писали:

K>Я хочу организовать прием событий идущих от COM объекта загруженного в OleConteiner. Обработка события будет происходить в Invoke.

K>Помогите, пожалуйста, написать код клиента:
K>//календарь C:\Program Files\Microsoft Office\OFFICE11\MSCAL.OCX
K>//календарь имеет интрефейс событий DCalendarEvents

K>//сам код:
K>//clsid получу от OleConteiner
K>IConnectionPointContainer* pICPC = NULL;
K>CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IConnectionPointContainer, (void**)&pICPC);

Так контрол не создается — его тоже нужно запрашивать у контейнера, так же как ты у него хочешь запросить clsid. Ну а дальше, получив OBJECT_WITH_EVENTS, действуй, как Аноним уже написал.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[2]: Приемник событий
От: Kitty  
Дата: 14.06.07 07:36
Оценка:
Код написанный Анонимом, мне не понятен. Что такое OBJECT_WITH_EVENTS и т.д.
Я пишу в Builder и ползуюсь книгой Трельсона.

Помогите написать приемник, например для конкретного ActiveX календаря:
Класс для соединения описан в моеем первом сообщении. Теперь пишу клиента:


//календарь C:\Program Files\Microsoft Office\OFFICE11\MSCAL.OCX
//календарь имеет интрефейс событий DCalendarEvents


//clsid полуучмла от OleConteiner-а в который загружен календарь:
AnsiString NameOfClass = OleContainer1->OleClassName;
wchar_t ConvertInID[255];
StringToWideChar(NameOfClass, ConvertInID, 255);
CLSID clsid;
CLSIDFromProgID(ConvertInID,&clsid);

IConnectionPointContainer* pICPC = NULL;
CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IConnectionPointContainer, (void**)&pICPC);

IConnectionPoint * pCP = NULL;
//здесь первым параметром в FindConnectionPoint надо писать IID_IDispatch или DIID календаря DIID_DCalendarEvents?
//если тут надо писать DIID_DCalendarEvents, то как его динамически получить?
pICPC->FindConnectionPoint(Что тут?, &pCP);

ULONG cookie;
//что передать в g_sink(...)?
CMyCoolEventHandler g_sink(Что тут?);
pCP->Advise(&g_sink, &cookie);


Вообщем как будет выглядеть приемник для календаря: C:\Program Files\Microsoft Office\OFFICE11\MSCAL.OCX ?
Re[3]: Приемник событий
От: Vi2 Удмуртия http://www.adem.ru
Дата: 14.06.07 08:52
Оценка:
Здравствуйте, Kitty, Вы писали:

K>Код написанный Анонимом, мне не понятен. Что такое OBJECT_WITH_EVENTS и т.д.

K>Я пишу в Builder и ползуюсь книгой Трельсона.

Это тот объект, который будет генерить события. Т.е. его можно было бы подставить в твой код для получения вместо pICPC:
IUnknown * OBJECT_WITH_EVENTS = NULL;
CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IUnknown, (void**)&OBJECT_WITH_EVENTS);

Только я не гарантирую, что этот объект будет генерировать или работать, т.к. контролы создаются не так, а запрашиваются у OleContainer1. Как-то так или подобно:
IUnknown * OBJECT_WITH_EVENTS = NULL;
OleContainer1.GetObject(&OBJECT_WITH_EVENTS);

Это тебе нужно проконсультироваться у объекта OleContainer1.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[4]: Приемник событий
От: Kitty  
Дата: 14.06.07 12:22
Оценка:
Vi2>Только я не гарантирую, что этот объект будет генерировать или работать, т.к. контролы создаются не так, а запрашиваются у OleContainer1. Как-то так или подобно:
Vi2>
Vi2>IUnknown * OBJECT_WITH_EVENTS = NULL;
Vi2>OleContainer1.GetObject(&OBJECT_WITH_EVENTS);
Vi2>

Vi2>Это тебе нужно проконсультироваться у объекта OleContainer1.

Растолкуйте, пожалуйста, подробнее, что вы имеете ввиду. Что значит "контролы"?
Re[5]: Приемник событий
От: Аноним  
Дата: 14.06.07 12:45
Оценка:
Здравствуйте, Kitty, Вы писали:

K>Растолкуйте, пожалуйста, подробнее, что вы имеете ввиду. Что значит "контролы"?


IOleContainer может содержать несколько обьектов/контролов(другими словами ActiveX) не только твой календарь, поэтому нужно копать к нему через:
EnumObjects
   Returns all ActiveX controls through an enumerator with IEnumUnknown, but not necessarily all objects (because there's no guarantee that all objects are ActiveX controls; some may be regular Windows controls).
Re[4]: Приемник событий
От: Kitty  
Дата: 14.06.07 13:41
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, Kitty, Вы писали:


K>>Код написанный Анонимом, мне не понятен. Что такое OBJECT_WITH_EVENTS и т.д.

K>>Я пишу в Builder и ползуюсь книгой Трельсона.

Vi2>Это тот объект, который будет генерить события. Т.е. его можно было бы подставить в твой код для получения вместо pICPC:

Vi2>
Vi2>IUnknown * OBJECT_WITH_EVENTS = NULL;
Vi2>CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IUnknown, (void**)&OBJECT_WITH_EVENTS);
Vi2>

Vi2>Только я не гарантирую, что этот объект будет генерировать или работать, т.к. контролы создаются не так, а запрашиваются у OleContainer1. Как-то так или подобно:
Vi2>
Vi2>IUnknown * OBJECT_WITH_EVENTS = NULL;
Vi2>OleContainer1.GetObject(&OBJECT_WITH_EVENTS);
Vi2>

Vi2>Это тебе нужно проконсультироваться у объекта OleContainer1.

Из того что я поняла мне, что надо вытянуть IUnknown у OleContainer1? Так?:

IUnknown * OBJECT_WITH_EVENTS = NULL;
OleContainer1->GetInterface(IID_IUnknown, (void**)&OBJECT_WITH_EVENTS);
Re[5]: Приемник событий
От: Kitty  
Дата: 14.06.07 15:15
Оценка: 1 (1)
Похоже это должно выглядеть так:

bool _connected = false; 
    HRESULT _result = S_OK; 

    _result = OleContainer1->OleObjectInterface->QueryInterface(IID_IConnectionPointContainer, (void**)&pICPC); 

    if(SUCCEEDED(_result)) 
    { 
        _result = pICPC->FindConnectionPoint(IID_IDispatch, &pCP); 

        if (SUCCEEDED(_result)) 
        { 
            _result = pCP->Advise(&g_sink, &cookie); 

            if(SUCCEEDED(_result)) 
            { 
                //Connected... 
                _connected=true; 
            }; 
            pCP->Release(); 
        } 
        pCP->Release(); 
    }
Re[6]: Приемник событий
От: Kitty  
Дата: 15.06.07 08:49
Оценка:
Большое спасибо за помощь!
Вообщем сработало вижу свое сообщение из Invoke. Остался один вопрос.
Весь код клиента стал таким:

TForm1 *Form1; 
CMyCoolEventHandler g_sink; //объявлен в первом сообщении
IConnectionPointContainer* pICPC; 
IConnectionPoint * pCP; 

//--------------------------------------------------------------------------- 
__fastcall TForm1::TForm1(TComponent* Owner) 
        : TForm(Owner) 
{ 
} 
//--------------------------------------------------------------------------- 
void __fastcall TForm1::Button1Click(TObject *Sender) 
{ 
   try 
  { 
    OleContainer1->Destroying(); 
    OleContainer1->CreateObject("MSCAL.Calendar.7",false); 
    OleContainer1->DoVerb(ovUIActivate); 
  } 
    catch(...) 
    { 
     ShowMessage("Не удалось загрузить: C:\Program Files\Microsoft Office\OFFICE11\MSCAL.OCX"); 
    } 
} 
//--------------------------------------------------------------------------- 

//---------------------------------------------------------------------------
//включить события 
void __fastcall TForm1::Button3Click(TObject *Sender) 
{ 
   ULONG cookie; 
    
   if(pICPC != NULL) 
   { 
      pICPC->Release(); 
      pICPC = NULL; 
   } 
   if (pCP != NULL) 
   { 
      pCP->Unadvise(cookie); 
      pCP->Release(); 
      pCP = NULL; 
   } 

    HRESULT _result = S_OK; 

    _result = OleContainer1->OleObjectInterface->QueryInterface(IID_IConnectionPointContainer, (void**)&pICPC); 

    if(SUCCEEDED(_result)) 
    { 
        _result = pICPC->FindConnectionPoint(IID_IDispatch, &pCP); 

        if (SUCCEEDED(_result)) 
        { 
            _result = pCP->Advise(&g_sink, &cookie); 

            if(SUCCEEDED(_result)) 
            { 
                //Connected... 
            } 
        } 
    }


} 
//--------------------------------------------------------------------------- 
void __fastcall TForm1::FormCreate(TObject *Sender) 
{ 
 CoInitialize (NULL); 
} 
//--------------------------------------------------------------------------- 
void __fastcall TForm1::FormDestroy(TObject *Sender) 
{ 
  CoUninitialize (); 
} 
//---------------------------------------------------------------------------


Подскажите как получить имя произошедщего события и как можно получить его параметры? Например занести их в массив Variant.
Re[7]: Приемник событий
От: Vi2 Удмуртия http://www.adem.ru
Дата: 15.06.07 09:35
Оценка:
Здравствуйте, Kitty, Вы писали:

K>Подскажите как получить имя произошедщего события и как можно получить его параметры? Например занести их в массив Variant.


По "DISPID dispIdMember" в вызове Invoke можно найти имя события, порывшись в библиотеке типов контрола, а в DISPPARAMS * pDispParams уже лежат упакованные и переданные параметры.

К тому же dispIdMember является хорошим синонимом для имени события.


PS
Мы уже писали о том, что обработка произвольного события произвольного контрола — занятие малоприятное.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[8]: Приемник событий
От: Kitty  
Дата: 15.06.07 09:58
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, Kitty, Вы писали:


K>>Подскажите как получить имя произошедщего события и как можно получить его параметры? Например занести их в массив Variant.


Vi2>По "DISPID dispIdMember" в вызове Invoke можно найти имя события, порывшись в библиотеке типов контрола, а в DISPPARAMS * pDispParams уже лежат упакованные и переданные параметры.


Vi2>К тому же dispIdMember является хорошим синонимом для имени события.



Vi2>PS

Vi2>Мы уже писали о том, что обработка произвольного события произвольного контрола — занятие малоприятное.


Спасибо большое за помощь!
У меня возникла проблема. Почему-то мой код работает только для календаря.
Буру, например, другие ActiveX-ы которые есть на моем компьюторе. Все они имеют диспинтерфейсы. Вот те, который брала произвольно:
"VIActiveXForm.VIForm" C:\PROGRA~1\MICROC~1\MPLABI~1\VDI\MPVDI.dll
"VCF1.VCF1Ctrl.1" C:\WINDOWS\system32\vcf132.ocx
"CERTWIZ.CertWizCtrl.1" C:\WINDOWS\system32\inetsrv\certwiz.ocx
Например пробую использовать VCF1.VCF1Ctrl.1, соотвественно код:


OleContainer1->CreateObject("VCF1.VCF1Ctrl.1",false);
//******************************************************


//далее наш код:
void __fastcall TForm1::Button3Click(TObject *Sender)
{


   if(pICPC != NULL)
   {
      pICPC->Release();
      pICPC = NULL;
   }
   if (pCP != NULL)
   {
      pCP->Unadvise(cookie);
      pCP->Release();
      pCP = NULL;
   }

    HRESULT _result = S_OK;

    _result = OleContainer1->OleObjectInterface->QueryInterface(IID_IConnectionPointContainer, (void**)&pICPC);

    if(SUCCEEDED(_result))
    {
        _result = pICPC->FindConnectionPoint(IID_IDispatch, &pCP); //DIID__DVCF1Events 

        if (SUCCEEDED(_result))
        {
            _result = pCP->Advise(&g_sink, &cookie);

            if(SUCCEEDED(_result))
            {
                //Connected... 
            } 
        }
    } 


}


Не работает, не инициализируется pCP в FindConnectionPoint...
Пробовала так:
#include <VCF1.hpp>
//далее в коде
_result = pICPC->FindConnectionPoint(DIID__DVCF1Events , &pCP); тоже не работает.
Не могу понять, почему работает для календаря, а для других ActiveX-ов нет.
Растолкуйте, пожалуйста, что не так?
Re[9]: Приемник событий
От: Vi2 Удмуртия http://www.adem.ru
Дата: 15.06.07 10:28
Оценка:
Здравствуйте, Kitty, Вы писали:

K>Не могу понять, почему работает для календаря, а для других ActiveX-ов нет.

K>Растолкуйте, пожалуйста, что не так?

Анализируйте коды возврата при каждом обращении к методам интерфейсов — там находится вся информация.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[10]: Приемник событий
От: Kitty  
Дата: 15.06.07 10:50
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, Kitty, Вы писали:


K>>Не могу понять, почему работает для календаря, а для других ActiveX-ов нет.

K>>Растолкуйте, пожалуйста, что не так?

Vi2>Анализируйте коды возврата при каждом обращении к методам интерфейсов — там находится вся информация.


Вообщем удалось вызвать события и для сетки VCF1.VCF1Ctrl.1.
Объект правильно надо было создать так:
CMyCoolEventHandler g_sink(DIID__DVCF1Events);
ну и вызов:

result = OleContainer1->OleObjectInterface->QueryInterface(IID_IConnectionPointContainer, (void**)&pICPC); 

    if(SUCCEEDED(_result)) 
    { 
        _result = pICPC->FindConnectionPoint(DIID__DVCF1Events, &pCP); 

        if (SUCCEEDED(_result)) 
        { 
            _result = pCP->Advise(&g_sink, &cookie); 

            if(SUCCEEDED(_result)) 
            { 
                //Connected... 
            } 
        } 
    }


Я знаю, что есть методы читающие библиотеку типов. Подскажите примером, как я могу программно получить GUID диспинтрефейса, чтобы создовать динамически объект CMyCoolEventHandler g_sink(GUID интрефейса с событиями); ?
Re[11]: Приемник событий
От: Vi2 Удмуртия http://www.adem.ru
Дата: 15.06.07 11:00
Оценка: +1 :)
Здравствуйте, Kitty, Вы писали:

K>Я знаю, что есть методы читающие библиотеку типов. Подскажите примером, как я могу программно получить GUID диспинтрефейса, чтобы создавать динамически объект CMyCoolEventHandler g_sink(GUID интерфейса с событиями); ?


Теперь учить тебя — только портить.

Вот тебе слова для поиска — IProvideClassInfo (или IProvideClassInfo2), ITypeInfo::GetContainingTypeLib. Есть такая функция AtlGetObjectSourceInterface, где весь этот механизм представлен.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[12]: Приемник событий
От: Kitty  
Дата: 15.06.07 11:28
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, Kitty, Вы писали:


K>>Я знаю, что есть методы читающие библиотеку типов. Подскажите примером, как я могу программно получить GUID диспинтрефейса, чтобы создавать динамически объект CMyCoolEventHandler g_sink(GUID интерфейса с событиями); ?


Vi2>Теперь учить тебя — только портить.


Vi2>Вот тебе слова для поиска — IProvideClassInfo (или IProvideClassInfo2), ITypeInfo::GetContainingTypeLib. Есть такая функция AtlGetObjectSourceInterface, где весь этот механизм представлен.


Спасибо за информацию, буду пробывать разобраться.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.