Re[8]: Вызов событий COM из разных потоков
От: Аркадий Россия  
Дата: 20.11.09 15:46
Оценка:
Здравствуйте, silart, Вы писали:

S>
S>ConnectionPoint::ConnectionPoint(IConnectionPointContainer* pIConnectionPointContainer, IID iid)
S>:    m_dwNextCookie(0), event_id(iid)
S>{
S>    ML_ASSERT(pIConnectionPointContainer != NULL);

S>    pContainer = pIConnectionPointContainer; // AddRef is not needed.

S>    HRESULT hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable,
S>        NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (void **)&pGIT);

S>    ML_ASSERT( SUCCEEDED(hr) );
S>}

S>ConnectionPoint::~ConnectionPoint()
S>{
    pGIT->>Release();
S>}

S>STDMETHODIMP ConnectionPoint::GetConnectionInterface(IID* piid)
S>{
S>     if (piid == NULL)
S>     {
S>         return E_POINTER;
S>     }

S>    *piid = event_id;
S>    return S_OK;
S>}

S>STDMETHODIMP ConnectionPoint::GetConnectionPointContainer(IConnectionPointContainer** ppIConnectionPointContainer)
S>{
S>    if (ppIConnectionPointContainer == NULL)
S>    {
S>        return E_POINTER;
S>    }

S>    *ppIConnectionPointContainer = pContainer;
S>    pContainer->AddRef();
S>    return S_OK;
S>}

S>STDMETHODIMP ConnectionPoint::Advise(IUnknown* pIUnknownSink, DWORD* pdwCookie)
S>{
S>com_ptr<IUnknown, IID_IUnknown> pI;
S>HRESULT hr;

S>    if (pIUnknownSink == NULL || pdwCookie == NULL)
S>    {
S>        *pdwCookie = 0;
S>        return E_POINTER;
S>    }

S>    hr = pIUnknownSink->QueryInterface(event_id, (void**)&pI);

S>    if (SUCCEEDED(hr))
S>    {
S>        hr = pGIT->RegisterInterfaceInGlobal(pI, IID_IDispatch, &m_dwNextCookie);

S>        ML_ASSERT( SUCCEEDED(hr) );
S>        return S_OK;
S>    }
S>    else
S>    {
S>        return CONNECT_E_CANNOTCONNECT;
S>    }
S>}

S>STDMETHODIMP ConnectionPoint::Unadvise(DWORD dwCookie)
S>{
S>    pGIT->RevokeInterfaceFromGlobal(m_dwNextCookie);
S>    return S_OK;
S>}
S>


Прочитав этот Ваш пример, я сделал то же самое. Переопределил методы Advise и Unadvise, добавив в них занесение интерфейса в GIT.
Действительно, интерфейс регистрируется в GIT, hr = S_OK, а потом удачно дерегистрируется.
И интерфейс достается из GIT без проблем. Но при отработке ничего не происходит. Почему это может быть, Вы, скорее всего, уже обошли этот вопрос.
Вот код:

template <class T>
STDMETHODIMP TEvents_UpTask<T>::Advise(IUnknown* pUnkSink,
    DWORD* pdwCookie)
{
     T* pT = static_cast<T*>(this);
    IUnknown* p;
    IID iid;
    GetConnectionInterface(&iid);
    HRESULT hRes = pUnkSink->QueryInterface(iid, (void**)&p);
    if (SUCCEEDED(hRes))
    {
          pT->Lock();
          DWORD myCookie;
          gp_GIT->RegisterInterfaceInGlobal(p, IID_IDispatch, &myCookie);
          //это std::map<DWORD, DWORD> для хранения всех Cookie
          m_GitPointers[*pdwCookie] = myCookie;

          pT->Unlock();
    }
    return hRes;
}

template <class T>
STDMETHODIMP TEvents_UpTask<T>::Unadvise(DWORD dwCookie)
{
...
        //Arkady Add
        gp_GIT->RevokeInterfaceFromGlobal(m_GitPointers[dwCookie]);
...
}

//метод, который должен вызываться при старте потока, генерирующего данные (такого же, как у Вас).
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();
}


Так вот, сервер попадает в Event->OnListenStart(); и выполняет этот метод, но при этом клиентский обработчик об этом почему-то не знает.
Когда то же самое событие вызывается в основном потоке сервера, клиентская реализация интерфейса отрабатывает. А тут — нет.
Не знаете, почему?
С уважением, Аркадий.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.