Re[5]: Вызов событий COM из разных потоков
От: silart  
Дата: 09.11.09 09:19
Оценка:
Здравствуйте, Мизантроп, Вы писали:

реализованная Вами схема выглядит весьма туманно, извините.

Внесем ясность.

Вот потоковая функция, которая посылает события (Теперь я из нее убрал все лишнее).


void EventManager::Routine()
{
HRESULT hr = E_FAIL;
tstring name;
vector<ml::com::Variant> args;
com_ptr<IDispatch, IID_IDispatch> pIEvent;
com_ptr<IEnumConnections, IID_IEnumConnections> pEnumConnections;

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

    // Предотвращаем одновременную генерацию событий из разных потоков.
    // (При использовании нескольких экземпляров компоненты в одном процессе)
    ExternalLock ext_lock;

    if ( !ExtractEvent(name, args) )
        return;

    DispParams dp(args);

    hr = pIConnectionPoint->EnumConnections( &pEnumConnections );

    ML_ASSERT( SUCCEEDED(hr) );

    CONNECTDATA cd;

    hr = pEnumConnections->Next(1, &cd, NULL);

    ML_ASSERT( SUCCEEDED(hr) );

    hr = cd.pUnk->QueryInterface(IID_IDispatch, (void**)&pIEvent);

    ML_ASSERT( SUCCEEDED(hr) );

    BStr memberName( TtoW::from(name).c_str() );
    DISPID dispid;

    hr = pITypeInfo->GetIDsOfNames( memberName, 1, &dispid);    // &lpolestrName

    ML_ASSERT( SUCCEEDED(hr) );

    hr = pIEvent->Invoke(dispid, IID_NULL, 
        GetUserDefaultLCID(), DISPATCH_METHOD, 
        dp.get(), NULL, NULL, NULL);

    ML_ASSERT( SUCCEEDED(hr) );

    cd.pUnk->Release();
}


Вот конструктор, основная цель которого — получить pITypeInfo, который будет использоваться другим потоком.

EventManager::EventManager(IID lib_id, IID event_id)
: m_EventId(event_id)
{
    HRESULT hr;
    com_ptr<ITypeLib, IID_ITypeLib> pITypeLib;

    hr = ::LoadRegTypeLib(lib_id, 1, 0, 0x00, &pITypeLib);
    ML_ASSERT( SUCCEEDED(hr) );

    // Get type information for the interface of the object.
    hr = pITypeLib->GetTypeInfoOfGuid(event_id, &pITypeInfo);
    ML_ASSERT( SUCCEEDED(hr) );

    pIConnectionPoint.reset( new ConnectionPoint(this, m_EventId) );
}


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

Событийный поток при старте вызывает CoInitialize()

bool EventManager::InitDone(bool fInitDone)
{
    if (fInitDone)
    {
        CoInitialize(NULL);
        CoEnableCallCancellation(NULL);
        m_ThreadID = GetCurrentThreadId();
    }
    else
    {
        CoUninitialize();
    }

return true;
}


Мизантроп, если речь идет о компоненте без событий, то с STA все понятно. А как задать STA, если речь идет о генерации событий? Как задать STA именно для событийного потока явно?
А могут быть проблемы от "кривости" клиента? Клиент написан на Borland C++ Builder.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.