Re[10]: Вызов событий COM из разных потоков
От: silart  
Дата: 23.11.09 06:22
Оценка:
Здравствуйте, Аркадий!

Вот ваша функция генерации событий:

template <class T> HRESULT
TEvents_UpTask<T>::Fire_OnListenStart(void)
{
  DWORD dw;

  T * pT = (T*)this;
  pT->Lock();
  IUnknown ** pp = m_vec.begin();
  while (pp < m_vec.end())
  {
    if (*pp != NULL)
    {
      dw = (DWORD)pp;

      IDispatch* dp;
      HRESULT hr = gp_GIT->GetInterfaceFromGlobal(m_GitPointers[dw], IID_IDispatch, (void**)&dp);
      if (SUCCEEDED(hr))
      {
        IUpTaskEvents* Event;
        hr = dp->QueryInterface(DIID_IUpTaskEvents, (void**)&Event);
        if (SUCCEEDED(hr))
        {
            Event->OnListenStart();
        }
      }
    }
    pp++;
  }
  pT->Unlock();
}


Я сравнил ее с моей, которая сейчас работает.
Попробуйте удалить строки, стоящие после получения интерфейса из GIT:

      if (SUCCEEDED(hr))
      {
        IUpTaskEvents* Event;
        hr = dp->QueryInterface(DIID_IUpTaskEvents, (void**)&Event);
        if (SUCCEEDED(hr))
        {
            Event->OnListenStart();
        }
      }

Т. е. я не запрашиваю у интерфейса, полученного из GIT конкретный disp-интерфейс, а использую интерфейс IDispatch напрямую.

Вот моя реализация:

Функция вызывается при старте и остановке потока.
bool EventManager::InitDone(bool fInitDone)
{
HRESULT hr;

    if (fInitDone)
    {
        hr = CoInitialize(NULL);

        // Получаем интерфейс событий
        DWORD cookie = m_connectionPoint->cookie();
        m_eventSink = getEventSink(cookie);

        m_IsStoped = false;
    }
    else
    {
        CoUninitialize();

        m_IsStoped = true;
    }

return true;
}


Функция, получающая Event Sink из GIT.
ml::com::com_ptr<IDispatch, IID_IDispatch> EventManager::getEventSink(DWORD cookie)
{
    HRESULT hr;
    ml::com::com_ptr<IDispatch, IID_IDispatch> eventSink;
    ml::com::com_ptr<IGlobalInterfaceTable, IID_IGlobalInterfaceTable> GIT;

    hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, 
        CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (void **)&GIT);

    ML_ASSERT( SUCCEEDED(hr) );

    hr = GIT->GetInterfaceFromGlobal(cookie, IID_IDispatch, 
        reinterpret_cast<void **>(&eventSink));

    ML_ASSERT( SUCCEEDED(hr) );

return eventSink;
}


Функция потока, вызывается периодически потоком, генерирует события.
void EventManager::Routine()
{
HRESULT hr = E_FAIL;
tstring name;
vector<ml::com::Variant> args;
DISPID dispid;

    // Блокировка потока, если список стал пустым
    if ( m_eventList.empty() )
    {
        mutex::scoped_lock lock(monitor);
        m_NewEvent.wait(lock);
    }

    // Берем новое событие из очереди
    if ( !ExtractEvent(name, args) )
        return;

    // Готовим для него все необходимое
    BStr memberName( TtoW::from(name).c_str() );
    DispParams dp(args);

    hr = m_typeInfo->GetIDsOfNames( memberName, 1, &dispid);
    ML_ASSERT( SUCCEEDED(hr) );

    // Вызываем.
    hr = m_eventSink->Invoke(dispid, IID_NULL,
        GetUserDefaultLCID(), DISPATCH_METHOD, 
        dp.get(), NULL, NULL, NULL);
    ML_ASSERT( SUCCEEDED(hr) );
}


Т. е. у меня поток в начальный момент времени при старте получает Event Sink, сохраняет его в переменной внутри класса, при этом полученный интерфейс Event Sink'а используется напрямую.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.