Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Скрестить Callback и Events в COM объекте, Скрестить Callback и Events в COM объект 
:(
    Опции темы
xvr
Дата 6.7.2009, 15:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 8
Всего: 223



Вам нужно в каждом thread'е, в котором вызывается Advise из вашего IConnectionPointContainer'а создавать невидимое окно с оконной функцией, которая в ответ на некоторое сообщение (например WM_USER) будет вызывать FireEvent. Handle'ы на все созданные окна нужно сложить в массив и рассылать по ним этот самый WN_USER на каждый callback. При shutdown'е всей этой бодяги надо не забыть разрушить все окна.

PM MAIL   Вверх
ivs4
Дата 7.7.2009, 08:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 27
Регистрация: 19.7.2004

Репутация: нет
Всего: нет



Как я понимаю, Advise вызывается клиентской стороной для передачи своего интерфейса, через который в свою очередь вызывается ивент.
Вот, что я подумал. Что если в ф-ции SetCallBack производить следующтие действия.
Создать новый поток, передать в этот поток указатель на CMyClass, в потоке работает цикл сообщений, при срабатывании CallBack посылаем в порожденный поток сообщение и в этом потоке вызывается  Fire_CallbackDone. В данной схеме возможно еще понадобиться маршалинг. 
А вообще как можно отследить когда вызван advise, чтобы тогда создать этот поток не в SetCallBack а там.


Это сообщение отредактировал(а) ivs4 - 7.7.2009, 09:16
PM MAIL ICQ   Вверх
xvr
Дата 7.7.2009, 09:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 8
Всего: 223



Вызывается Advise клиентской стороной но из вашего объекта (это метод интерфейса IConnectionPointContainer, который имплементирован в вашем классе)
Создание отдельного потока в CallBack у себя не поможет - при этом придется маршалить к себе в поток VBA'ный объект - приемник событий, а именно он после именно такого маршалинга и не работал  smile 

И вообще, все методы всех интерфейсов вашего объекта будут вызываться в одном потоке (это обеспечивает COM, если вы конечно не поставили у вашего класса Neutral Threaded модель)
Из этого же потока должны вызываться все event'ы (FireEvent). В этом же потоке VBS будет САМ крутить цикл обработки сообщений


Это сообщение отредактировал(а) xvr - 7.7.2009, 09:24
PM MAIL   Вверх
ivs4
Дата 7.7.2009, 09:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 27
Регистрация: 19.7.2004

Репутация: нет
Всего: нет



Тогда не понятно куда ставить цикл сообщений, если его надо ставить в поток где вызываются все методы интерфейсов. В методы его не поставишь. Где вызывается Advise, честно говоря, я не вижу.

Добавлено через 6 минут и 22 секунды
Или же все тщетно - не вызвать из Callback событие?
PM MAIL ICQ   Вверх
xvr
Дата 7.7.2009, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 8
Всего: 223



Цитата(ivs4 @ 7.7.2009,  09:37)
Тогда не понятно куда ставить цикл сообщений, если его надо ставить в поток где вызываются все методы интерфейсов.

Никуда его не надо ставить - он уже есть в VBA
Цитата

Где вызывается Advise, честно говоря, я не вижу.
В Advise надо ставить создание окна (при условии, что на текущем thread'е оно еще не создавалась) Сам Advise вызывается из VBA, так что его вызова вы не увидите. Создание окна нужно вставить в САМ Advise, а не в место его вызова. 
Как то так:

Код

class YourCOMClass :
    public IDispatchImpl<...>,
    public CComObjectRoot,
    public CProxyYourCOM_Event< YourCOMClass >,
    public IConnectionPointContainerImpl<YourCOMClass>
{
...

  STDMETHOD(Advise) (IUnknown* pUnkSink,    DWORD* pdwCookie)
   {
     // Create WINDOWS here (if need to)
     return CProxyYourCOM_Event< YourCOMClass >::Advise(pUnkSink,pdwCookie);
   }

}



Цитата

Добавлено @ 09:43
Или же все тщетно - не вызвать из Callback событие?
Надежда умирает последней  smile 
PM MAIL   Вверх
ivs4
Дата 10.7.2009, 17:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 27
Регистрация: 19.7.2004

Репутация: нет
Всего: нет



Попробовал вызов события через передачу сообщения в ф-цию окна. Теперь работает все без маршалинга и hres=0, но все равно, к сожалени ИВЕНТ не вызывется. Может что не то сделал?

Код


UINT WM_EVNT=RegisterWindowMessage("MYEVENTMESSAGE");

class ATL_NO_VTABLE CMyClass : 
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CMyClass, &CLSID_MyClass>,
    public ISupportErrorInfo,
    public IConnectionPointContainerImpl<CMyClass>,
    public IDispatchImpl<IMyClass, &IID_IMyClass, &LIBID_TRANSACLib>,
    public CProxy_IMyClassEvents< CMyClass >
{
public:
    CMyClass()
    {
    }

    
    STDMETHOD(Advise)(IUnknown* pUnkSink, DWORD* pdwCookie){
        WNDCLASSEX  wndc;
        wndc.cbSize=sizeof(WNDCLASSEX);
        wndc.style=CS_HREDRAW|CS_VREDRAW;
        wndc.lpfnWndProc=(WNDPROC)WindowProc;
        wndc.cbWndExtra=0;
        wndc.cbClsExtra=0;
        wndc.hInstance=hInst;
        wndc.hIcon=NULL;
        wndc.hCursor=NULL;
        wndc.hbrBackground=NULL;
        wndc.lpszMenuName=NULL;
        wndc.lpszClassName="TEST";
        wndc.hIconSm=NULL;
        if(RegisterClassEx(&wndc)==0)
            return CONNECT_E_CANNOTCONNECT;
        hWnd=CreateWindow("TEST",NULL,WS_OVERLAPPED,0,0,100,100,0,0,hInst,NULL);
        DWORD dwErr=GetLastError();
        if (hWnd==NULL){
            return CONNECT_E_CANNOTCONNECT;
        }
        //ShowWindow(hWnd, SW_SHOW);
                //UpdateWindow(hWnd);
        return CProxy_IMyClassEvents< CMyClass >::Advise(pUnkSink,pdwCookie);
    }

    static LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg, WPARAM wParam,LPARAM lParam){

        if (uMsg==WM_EVNT){
            CMyClass *ptr;
            ptr=(CMyClass*)wParam;
            VARIANTARG var;
            var.lVal=777;
            var.vt=VT_I4;
            obj->Fire_CallBackDone(var);
            return 0;
        }
        else{
        switch( uMsg ){
                case WM_DESTROY:
                PostQuitMessage( 0 );
                return 0;
        }
        }

        return CallWindowProc( (WNDPROC)DefWindowProc, hWnd, uMsg, wParam, lParam );
    }


    static CMyClass *obj;

static void __stdcall SASCallback (long nTransactionResult, long nTransactionExtendedErrorCode, long nTransactionReplyCode, DWORD dwTransId, double dOrderNum, LPCSTR lpcstrTransactionReplyMessage);


Код

void __stdcall CMyClass::Callback (long var){
    LRESULT lres=PostMessage(hWnd,WM_EVNT,0,0);    
}

PM MAIL ICQ   Вверх
xvr
Дата 10.7.2009, 22:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 8
Всего: 223



Вроде все правильно (не считая того, что класс окна нужно регистрировать только 1 раз).
А obj->Fire_CallBackDone вызывается?
Может какие то несостыковки в Appartament моделях объекта и приложения?


PM MAIL   Вверх
ivs4
Дата 11.7.2009, 23:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 27
Регистрация: 19.7.2004

Репутация: нет
Всего: нет



Попробовал еще вот этот вариант:
http://support.microsoft.com/kb/196026/
все равно не вызывается событие.

В Fire_CallBackDone

Код

HRESULT hres=pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);

возвращает 0, но без события.

Может что-то не то с этой библиотекой откуда вызывается CallBack? Хотя не должно. Сообщение доходит до обработчика и файр вызывается.
PM MAIL ICQ   Вверх
ivs4
Дата 12.7.2009, 17:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 27
Регистрация: 19.7.2004

Репутация: нет
Всего: нет



Удалось заставить заработать событие в VBA. Для этого в VBA в то место где ожидается срабатывание события добавил следующую ф-ция засыпания на 1 секунду.

Код


SleepVB(1)
...

Sub SleepVB(Seconds)
  Dim Start
  Start = Timer 
  Do While Timer < Start + Seconds
    DoEvents
  Loop
End Sub


Скорее всего сообщение ассоциированное с Invoke не обрабатвается. Конечно нет желания ставить такую обработку в клиентском коде. Как бы это обойти?
PM MAIL ICQ   Вверх
xvr
Дата 12.7.2009, 19:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 8
Всего: 223



А как VBA'ная прога ждет события? Если она в это время что то считает, то событие не будет принято - события принимаются только в Idle состоянии. 
Можно заставить их принимать и не в Idle, но тогда надо явно крутить цикл обработки событий, что SleepVB и делает (в DoEvents)

PM MAIL   Вверх
ivs4
Дата 13.7.2009, 21:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 27
Регистрация: 19.7.2004

Репутация: нет
Всего: нет



А другого варианта как цикл DoEvents в VBA нет?
Я знаю, что майкрософтовский  winsock сервер работает не так. Там событие прихода вызывается асинхронно.

Это сообщение отредактировал(а) ivs4 - 13.7.2009, 21:51
PM MAIL ICQ   Вверх
xvr
Дата 14.7.2009, 09:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 8
Всего: 223



Цитата(ivs4 @ 13.7.2009,  21:47)
А другого варианта как цикл DoEvents в VBA нет?

Есть. Написать нормальный обработчик в VBA. Точнее - обеспечить что бы VBA приложение работало так, как рассчитана модель событий VBA. Все события в VBA сериализуются, т.е. пока не закончится обработка одного, обработка другого не начнется (если не звать принудительно DoEvents)
Цитата

Я знаю, что майкрософтовский  winsock сервер работает не так. Там событие прихода вызывается асинхронно.
winsock (=Win32 API) != VBA. Но и там события приходят либо в функции ожидания (WaitFor*Object) либо через сообщения к окнам, что опять же требует наличия работающего цикла обработки сообщений  smile 
PM MAIL   Вверх
ivs4
Дата 16.7.2009, 07:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 27
Регистрация: 19.7.2004

Репутация: нет
Всего: нет



Спасибо за ответы. Полагаю тема исчерпана.
PM MAIL ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: COM/DCOM/ActiveX/ATL/CORBA | Следующая тема »


 




[ Время генерации скрипта: 0.1257 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.