Помогите с параметрами ActiveX event-а
От: Александр Воронин Россия [70620598]
Дата: 08.10.05 20:33
Оценка:
Здравствуйте!

Угораздило меня полезть в малознакомую мне тему — работа с COM на уровне C++/ATL/MFC. Потому как ни привычный Delphi, ни семейство .NET не пожелали работать с этим актив-иксом Delphi падает при вызове метода, нормально читая проперти, в .NET не приходят event-ы. Примеры есть на VB6 и на нем (точнее на VBA в excel) они работают.

Сделал тестовую программу на MFC с ConnectionPoints по статье
Автор(ы): Евгений Щербатов
Дата: 18.04.2001

Статья посвящена технологии Connection Points в программах на MFC. Автор кратко описывает сущность и назначение этой технологии, а затем демонстрирует создание COM-клиента и COM-сервера на базе MFC с её использованием.
. Работает, но не могу добраться до аргументов обработчикой событий Вопрос в том, как правильно описать функцию-обработчик и использовать в ней переданный параметр... Три дня поиска по сайту и msdn ситуацию не прояснили...

в VBA это выглядело так:
Private Sub on_Iam(ByVal service As BACNETLib.IIam)
'... использую ...
 Debug.Print service.network


В C++ сделал:
.h:
#import "../bacnet/bacnetx.dll" named_guids no_namespace

// ...

    DECLARE_DISPATCH_MAP()
    DECLARE_INTERFACE_MAP()

/* IDL:
    [
      odl,
      uuid(93F6D2DF-7002-11D5-A66F-0050DA883529),
      helpstring("IIam Interface"),
      dual,
      oleautomation
    ]
    interface IIam : IDispatch {

        [id(0x00000005), propget, helpstring("property network")]
        HRESULT network([out, retval] long* pVal);

// ...
struct __declspec(uuid("a4234400-6697-11d5-a66d-0050da883529"))
_IApplicationLayerEvents : IDispatch
{
    //
    // Wrapper methods for error-handling
    //

    // Methods:
    HRESULT Iam (
        struct IIam * service );
*/
    void OnBacnetIam(IIam *srv);


.cpp
BEGIN_DISPATCH_MAP(CBacnetDlg, CDialog)
    DISP_FUNCTION(CBacnetDlg, "Iam", OnBacnetIam, VT_EMPTY, VTS_DISPATCH)
END_DISPATCH_MAP()

BEGIN_INTERFACE_MAP(CBacnetDlg, CDialog)
    INTERFACE_PART(CBacnetDlg, DIID__IApplicationLayerEvents, Dispatch)
END_INTERFACE_MAP()

void CBacnetDlg::OnBacnetIam(IIam *srv)
{
  long x = srv->network;
  // тут падаем:( ... network - "long IIam::network"


В обработчик вроде бы нормально все передается, в Watches видно IDispatch и IUnknown "содержимое" Iam. При обращении к проперти — как правило "Неверное значение ESP — возможно неправильное соглашение о вызове" или First-chance exception и выход из метода/отладчика.
---
wbr, Alexander Voronin
mailto:
Re: Помогите с параметрами ActiveX event-а
От: Vi2 Удмуртия http://www.adem.ru
Дата: 10.10.05 06:34
Оценка: 4 (1)
Здравствуйте, Александр Воронин, Вы писали:

АВ>BEGIN_DISPATCH_MAP(CBacnetDlg, CDialog)
АВ>    DISP_FUNCTION(CBacnetDlg, "Iam", OnBacnetIam, VT_EMPTY, VTS_DISPATCH)
АВ>END_DISPATCH_MAP()

АВ>BEGIN_INTERFACE_MAP(CBacnetDlg, CDialog)
АВ>    INTERFACE_PART(CBacnetDlg, DIID__IApplicationLayerEvents, Dispatch)
АВ>END_INTERFACE_MAP()

АВ>void CBacnetDlg::OnBacnetIam(IIam *srv)
АВ>{
АВ>  long x = srv->network;
АВ>  // тут падаем:( ... network - "long IIam::network"

VTS_DISPATCH означает передачу именно IDispatch* указателя. Поэтому перед использованием в качестве IIam нужно сделать QueryInterface. Поэтому лучше привести к нормальному (ожидаемому) виду void CBacnetDlg::OnBacnetIam(IDispatch *srv). Тогда и ошибка обращения будет очевидной.

К тому же, DIID означает dispinterface, параметры которого передаются в VARIANTах, в которых можно передать или IUnknown*, или IDispatch*. Никаких других типов указателя передать не получится. Перевод в нужный интерфейс осуществляется обработчиком Invoke при распаковке по библиотеке типов. В твоем же случае распаковка идет по указанному тобой параметру, т.е. VTS_DISPATCH. Соответственно, обработчик понятия не имеет о интерфейсе IIam.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[2]: Помогите с параметрами ActiveX event-а
От: Александр Воронин Россия [70620598]
Дата: 10.10.05 07:23
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>VTS_DISPATCH означает передачу именно IDispatch* указателя. Поэтому перед использованием в качестве IIam нужно сделать QueryInterface. Поэтому лучше привести к нормальному (ожидаемому) виду void CBacnetDlg::OnBacnetIam(IDispatch *srv). Тогда и ошибка обращения будет очевидной.


О! То что надо! Заработало —
OnIam(IIam *service)
{
    IIamPtr serv;
    service->QueryInterface(&serv);
//...
    serv->Release();


В догонку — что делать с указателями — правильно ли я зоову Release() или оно само сделается для smart_ptr..?

---
wbr, Alexander Voronin
mailto:
Re[3]: Помогите с параметрами ActiveX event-а
От: Vi2 Удмуртия http://www.adem.ru
Дата: 10.10.05 11:33
Оценка:
Здравствуйте, Александр Воронин, Вы писали:

АВ>В догонку — что делать с указателями — правильно ли я зоову Release() или оно само сделается для smart_ptr..?


Правильно, хотя IMHO это и лишнее: я предпочитаю использовать нормальный ход вещей, когда деструктор освободит используемый указатель. OTOH, Release() явно показывает освобождение. Так что это дело вкуса.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[4]: Помогите с параметрами ActiveX event-а
От: Александр Воронин Россия [70620598]
Дата: 10.10.05 11:39
Оценка:
Здравствуйте, Vi2, Вы писали:


Vi2>Правильно, хотя IMHO это и лишнее: я предпочитаю использовать нормальный ход вещей, когда деструктор освободит используемый указатель. OTOH, Release() явно показывает освобождение. Так что это дело вкуса.


Пока пробовал — выяснил — "не правильно": получается first-chance exception по логам VS, судя по всему в недрах auto_ptr. Но есс-но ничего не падает Так что нормальный ход вещей — он как-то приятнее
---
wbr, Alexander Voronin
mailto:
Re[5]: Помогите с параметрами ActiveX event-а
От: serge_levin Россия  
Дата: 10.10.05 16:18
Оценка:
Здравствуйте, Александр Воронин, Вы писали:

АВ>Пока пробовал — выяснил — "не правильно": получается first-chance exception по логам VS, судя по всему в недрах auto_ptr. Но есс-но ничего не падает Так что нормальный ход вещей — он как-то приятнее


Правильно. Ибо не надо при использовании Smart Pointers (IXXXPtr) делать явный вызов Release — указатель сам в своем деструкторе его вызовет.
... << RSDN@Home 1.1.3 stable >>
Re[5]: Помогите с параметрами ActiveX event-а
От: Vi2 Удмуртия http://www.adem.ru
Дата: 11.10.05 04:07
Оценка:
Здравствуйте, Александр Воронин, Вы писали:

АВ>Пока пробовал — выяснил — "не правильно": получается first-chance exception по логам VS, судя по всему в недрах auto_ptr. Но есс-но ничего не падает Так что нормальный ход вещей — он как-то приятнее


Посмотрел более внимательно:
    ~_com_ptr_t() throw()
    { 
        _Release(); 
    }
    void _Release() throw()
    {
        if (m_pInterface != NULL) { m_pInterface->Release(); }
    }

    void Release() throw(_com_error)
    {
        if (m_pInterface == NULL) { _com_issue_error(E_POINTER); }
        m_pInterface->Release();
        m_pInterface = NULL;
    }

Разница в поведении, когда переменная serv содержит NULL после его заполнения. Release() генерит прерывание E_POINTER. А ~_com_ptr_t нет. Так что, действительно, лучше его не использовать. НО! Нужно исходный код модифицировать:
    IIamPtr serv;
    if( SUCCEEDED(service->QueryInterface(&serv) )
    {
        //...
        serv->Release();
    }

И здесь снова вызов Release ПРАВИЛЬНЫЙ. Но опять же это дело вкуса.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.