Здравствуйте, Мизантроп, Вы писали:
реализованная Вами схема выглядит весьма туманно, извините.
Внесем ясность.
Вот потоковая функция, которая посылает события (Теперь я из нее убрал все лишнее).
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.