COM+ Events в пользовательском потоке
Как реализовывать события COM сервера, происходящие в основном его потоке, прекрасно разобрано в FAQ этого раздела форума.
Необходимо же, чтобы сервер запускал второй поток, в котором бы срабатывал механизм событий. Однако в другом потоке этот механизм уже не работает (т.е. Fire_Event просто не отрабатывает, клиент, подключающийся к этим событиям о них не узнает, хотя тот же Fire_Event в основном потоке сервера ловится клиентом).
Т.е. вопрос - как заставить сервер реализовывать (или VBA клиент цепляться) не только к событиям основного потока сервера, но и к событиям в дополнительных потоках.
Как правильно реализовать это на сервере?
Очень надеюсь на помощь, заранее спасибо :-)
Единственное решение, которое нашел - инициация событий в контексте основного потока.
Рабочий поток делает PostMessage в основной поток и ждет сигнала, основной поток делает Fire_Event и устанавливает сигнал, рабочий поток продолжает работу.
Единственное решение, которое нашел - инициация событий в контексте основного потока.
Рабочий поток делает PostMessage в основной поток и ждет сигнала, основной поток делает Fire_Event и устанавливает сигнал, рабочий поток продолжает работу.
Да, интернет говорить, что есть 2 варианта решения, через PostMessage и через CoMarshalInterThreadInterfaceInStream.
1) Вариант через CoMarshalInterThreadInterfaceInStream у меня не получается реализовать, потому что Automation Object, автоматически создаваемый Builder-ом на самом деле имеет Pure Function AddRef(), т.е. IUnknown у него состоит из абстрактных методов. И передать указатель на этот класс, соответственно, не удается (на этапе выполнения Windows шлет ошибку "Call pure function". Да и при попытке создать экземпляр себя не компилится, поскольку AddRef() = 0. Т.е. я так понимаю, именно на этой функции CoMarshalInterThreadInterfaceInStream и "запарывается").
2) Вариант через PostMessage, честно говоря, не понимаю, как реализовать, ведь я не управляю основным потоком и не понимаю, как сказать ему ловить сообщения. Всё, что я знаю об основном потоке, это то, что в нем выполняются методы Automation Object, которые я пишу.
(!!) Заставлять его зависать и ждать сообщения от второго потока я не могу, тогда теряется смысл во втором потоке. А вот как реализовать так, чтобы пользователь мог работать с сервером, а через час работы сервера второй поток послал ему PostMessage и сервер его бы сразу поймать - не понимаю.
Если Вы подскажете, как Вы это сделали, Вы мне очень поможете =)
Заранее спасибо =)
Кто-нибудь имеет опыт проделывания этого? :)
[ATTACH]3395[/ATTACH]
Это частное решение подходящее для ActiveX-контролов. Но может оно натолкнет на мысли и по Вашей проблеме :)
[ATTACH]3395[/ATTACH]
Это частное решение подходящее для ActiveX-контролов. Но может оно натолкнет на мысли и по Вашей проблеме :)
Пример интересный, но в нем нехватает файлов. Из того, что я понял - там создается второй поток, который имеет искусственные задержки (5 секунд). Т.е. каждые пять секунд он просто делает проверку.
Но что если сообщения будут сыпаться с частотой бОльшей, чем раз в 5 секунд? Хочется же именно слушающего потока, который бы давал событие.
Ситуация следующая:
Есть Сервер. Exe. Он динамически линкуется к dll. Эта dll содержит интерфейс такого класса:
{
public:
virtual void Init(IMyEvents* Ev) = 0;
virtual void Start() = 0;
virtual void Stop() = 0;
};
class T_showclass : public IShowClass
{
//...
public:
virtual void Init(IMyEvents* Ev);
virtual void Start();
virtual void Stop();
};
Т.е. dll возвращается указатель на интерфейс объекта. После выполнения метода Start() этого интерфейса, там внутри создаются потоки, идет сложная работа, а в некоторые ключевые моменты дергаются методы интерфейса IMyEvent, указатель на который должен быть передан в объект извне.
Т.е. пользователь извне реализует класс, наследник от IMyEvent, где реализует все методы IMyEvent (реакции на все события объекта IShowClass), передает в IShowClass указатель на свой экземпляр, приведенный к типу IMyEvent, потом запускает этот объект и объект в нужных местах вызывает методы интерфейса IMyEvent, а значит код, реализованный пользователем.
Так самодельно реализована модель событий. Такова dll (объяснил, чтобы понимать, в чем дело).
Эту dll использует Automation Object (COM), у которого есть методы и события.
Такие
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<TUpTaskImpl, &CLSID_UpTask>,
public IConnectionPointContainerImpl<TUpTaskImpl>,
public TEvents_UpTask<TUpTaskImpl>,
public IDispatchImpl<IUpTask, &IID_IUpTask, &LIBID_UpiterObj>
{
//...
public:
STDMETHOD(Start());
STDMETHOD(Stop());
};
Соответственно надо, чтобы события этого сервера реагировали на события из DLL. Однако события в DLL - "происходят" не в основном потоке программы, а во внутренних потоках DLL, а потому даже если я туда передаю пользовательскую реализацию IMyEvent, которая оборачивает вызовы событий TUpTaskImpl, эти события не видятся из VBA.
А очень надо, чтобы виделись.
CoMarshalInterThreadInterfaceInStream и обратная - почему-то не отрабатывают.
Может быть кто-то решал такую проблему?
Пример интересный, но в нем нехватает файлов.
Хм. Все файлы на месте. Все должно компилиться и работать.
Из того, что я понял - там создается второй поток, который имеет искусственные задержки (5 секунд). Т.е. каждые пять секунд он просто делает проверку.
Это имитация асинхронного события вставки карты в устройство для чтения карточек. Задержка задается свойством Delay.
5 сек компонент TFakeReader ждет, чтобы слушатель отложенного уведомления забрал из очереди сообщение, т.е. обработал асинхронное событие - это синхронизация источника события и слушателя. Ибо асинхронное событие для моей задачи должно обрабатываться синхронно =)
Но что если сообщения будут сыпаться с частотой бОльшей, чем раз в 5 секунд? Хочется же именно слушающего потока, который бы давал событие.
Что Вас смущает?
Про слушающий поток дающий событие совсем непонятно.
У меня .bpr овского файла не хватает для второго проекта (который, судя по всему, dll).
Но так - пример полезный и понятный, мне помог, спасибо.
У меня .bpr овского файла не хватает для второго проекта (который, судя по всему, dll).
FakeReaderExample_CB6.bpk - это проект для run-time пакета
dclFakeReaderExample_CB6.bpk - это проект для design-time пакета
AXAsyncExample_CB6.bpr - это проект для ActiveX Library