Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: COM/DCOM/ActiveX/ATL/CORBA > Проблема с событиями в com


Автор: al_capone 25.2.2009, 18:34
Добрый вечер.
Cразу хочу предупредить, что я новичок в com.
Есть ActiveX c ThreadingModel=Apartment. Он может получать данные из сети, а прочитанные данные возвращать через events.
Я написал функцию которую крутит отдельный поток:
Код


int MyClass::grabTh(void* pParam)
{
    MyClass* pThis = static_cast<MyClass*>(pParam);
    //init COM and ATL
    CATLinitializer initObj; 
        
    try
    {
        //instance VWDataAccessCtrl object
        IVWDataAccessCtrlPtr pDataAcces(CLSID_VWDataAccessCtrl);
        
        //create and connect event handler to  source
        CVWEventsProxy eventsProxy(pDataAcces, pThis);

        //connecting to host
        pDataAcces->put_Url(CComBSTR("192.168.0.6:5002"));
        pDataAcces->put_Blocking(FALSE);
        HRESULT hr = pDataAcces->Connect();

        //TODO: conditional variable wait
        MessageBox(0,"mess","mess",0);
        pDataAcces->Disconnect();
    }
    catch (const _com_error& e)
    {
        
    }

    return 0;
}




тут создается объект COM от которого идут события (VWDataAccessCtrl ), создается объект CVWEventsProxy отнаследованный от IDispEventImpl, и в конструкторе он еще подключается к pDataAcces. Т.е. события должны приходить в eventsProxy.

Я столкнулся с двумя проблемами в этом коде:
1)Когда эта функция один раз отрабатывает, поток уничтожается, когда же я заново создаю поток и выполняется этот код, при инициализации COM (CoInitialize(NULL)) в дебаге выскакивает противный assert вот в этом месте

Код

    CAtlModule() throw()
    {
        // Should have only one instance of a class 
        // derived from CAtlModule in a project.
        ATLASSERT(_pAtlModule == NULL);



после него CoInitialize возвращает S_OK. Соответственно в релизе никаких нареканий в работе нет. Что мне с этим делать?

2)Основная проблема: Если я уберу MessageBox и поставлю sleep, например, или буду делать что то левое, то события не вызываются.Насколько я понял, когда я создаю “STA поток”, то в этом потоке выполняется и обработчик сообщений (оконные сообщения) для обектов com (насколько я понял events вызываются в ответ на сообщения). Когда же я делаю sleep() (или любое другое действие). Поток приостанавливается и обработчик соответственно тоже, поэтому не работает. (не вдумываетесь в последние 2 предложения)

Если вам лень объяснять что и почему, буду рад просто ссылке, но именно по теме.
Спасибо за внимание.

Автор: jonie 26.2.2009, 09:11
как я понимаю ситуацию: у вас есть блокирующий вызов accept(), и после коннекта вы делаете новый поток, куда пропихиваете COMобъект MyClass через параметр pParam. Так делать нельзя - у вас MyClass создан в потоке не принадлежащему апартаменту где создан объект (у вас же STA, а не MTA => один поток на апартамент). Для проброса нужно использовать маршалинг(CoMarshal чета тут функцию) (или, если вы точно уверены что делаете, и у вас inproc сервер, тогда можно GIT использовать (появилось в win2000 вроде) (и получать указатель уже через cookie)) - гугл по слову RegisterInterfaceInGlobal.

http://www.compdoc.ru/prog/cpp/com/ch5/ch510.shtml

Автор: al_capone 26.2.2009, 09:57
нет, извиняюсь за весьма непонятный код, нужно было упростить код и все не нужное отсеять. Наверное слово proxy вас отвлекает от истины. Ситуация такая: чтобы не делать весьма непонятные мне вещи типа маршалинга, я сделал отдельный поток для работы с ком объектом, в этом потоке я его создаю, потом подключаюсь к событиям, потом вызываю connect com объекта. с этого момента данные должны приходить через события.  через некоторое время  делается дисконект в этом же потоке, и и ком объект уничтожается. т.е. с объектом работает только один поток и только одна функция (код которой в первом комменте). 

Автор: xvr 26.2.2009, 15:21
По п1 - что такое CATLinitializer ? Сдается мне, что оно должно быть в main.
По п2 нужно сделать цикл обработки сообщений (GetMessage/ProcessMessage) вместо MessageBox (или отказаться от ATM, сделать например FreeThreaded, но может и не помочь)

Автор: al_capone 26.2.2009, 15:45
1)вот
Код

    
       class CATLinitializer : public boost::noncopyable
    {
    public:
        CATLinitializer();
        ~CATLinitializer();

    private:
        HRESULT m_hrCOM;
        HRESULT m_hrATL;
        CComModule _Module;
    };


/////////////////////////////////////////////////////
    CATLinitializer::CATLinitializer() :
    m_hrCOM(S_FALSE),
    m_hrATL(S_FALSE)
{
    m_hrCOM = CoInitialize(NULL);
    assert(!FAILED(m_hrCOM));

    m_hrATL = _Module.Init(NULL, GetModuleHandle(NULL));
    assert(!FAILED(m_hrATL));
}

////////////////////////////////////////////////////////
CATLinitializer::~CATLinitializer()
{
    if (SUCCEEDED(m_hrATL))
    {
        _Module.Term();
    }

    if (SUCCEEDED(m_hrCOM))
    {
        CoUninitialize();
    }
}


2)а можно пример как сделать обработчик сообщений? просто смотри, у меня это все происходит в длл, причем в таком что там нет ни mfc ни com ни atl. Это единственная функция где используется что то такое.

Автор: xvr 26.2.2009, 19:33
1) Строка 22 (m_hrATL = _Module.Init(NULL, GetModuleHandle(NULL));) здесь лишняя - ее надо выполнить только 1 раз на всю программу, а не каждый раз на каждый thread
2) Обработчик совершенно стандартный:
Код

    MSG msg;

    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

Цитата

просто смотри, у меня это все происходит в длл, причем в таком что там нет ни mfc ни com ни atl. Это единственная функция где используется что то такое.
Этот цикл нужен для самой системы COM, ни mfc ни atl здесь не при чем. А COM у тебя используется - ты же event'ы через eventsProxy хочешь получать? А рассылает их как раз COM

Автор: al_capone 26.2.2009, 20:06
ок, большое спасибо, работает!!! основная проблема решена.
Теперь выявилась еще одна проблема, компонента работает нестабильно, после первого фрейма уходит в нирвану, потом в output вылезают ошибки типа тайм-аут сработал. Если этот самый код поместить в mfc exe (например при нажатии кнопки чтобы выполнялось все) то так работает отлично. Я знаю что информации явно недостаточно но соображения есть где копать?
еще раз, спасибо!

Автор: xvr 26.2.2009, 21:07
Цитата(al_capone @ 26.2.2009,  20:06)
Теперь выявилась еще одна проблема, компонента работает нестабильно, после первого фрейма уходит в нирвану, потом в output вылезают ошибки типа тайм-аут сработал. Если этот самый код поместить в mfc exe (например при нажатии кнопки чтобы выполнялось все) то так работает отлично. Я знаю что информации явно недостаточно но соображения есть где копать?

Причин может быть вагон и маленькая тележка  smile  Например multithread проблемы - синхронизация и разделение ресурсов
Нужна более подробная информация о программе

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)