Реализация реентерабельности для апартаментов STA более сложна. Поскольку STA-объекты обладают привязкой к потоку, то когда поток делает межапартаментный вызов из STA, СОМ не может разрешить потоку сделать блокирующий вызов, который предотвратил бы обработку входящих ORPC-запросов. Когда поток вызывающего объекта входит в метод канала
Фильтры сообщений являются уникальными для STA. Фильтр сообщений – это объект СОМ для каждого STA, который используется для решения вопроса, организовать диспетчеризацию поступающих ORPC-запросов или нет. Кроме того, фильтры сообщений используются для размещения задержанных сообщений пользовательского интерфейса, пока поток STA ожидает ORPC-ответа внутри канала. Фильтры сообщений выставляют интерфейс
[ uuid(00000016-0000-0000-C000-000000000046),local, object ]
interface IMessageFilter : IUnknown {
typedef struct tagINTERFACEINFO {
IUnknown *pUnk;
// which object?
// чей объект?
IID iid;
// which interface?
// чей интерфейс?
WORD wMethod;
// which method?
// чей метод?
} INTERFACEINFO;
// called when an incoming ORPC request arrives in an STA
// вызывается, когда входящий ORPC-запрос поступает в STA
DWORD HandleInComingCall(
[in] DWORD dwCallType,
[in] HTA5K dwThreadIdCaller,
[in] DWORD dwTickCount,
[in] INTERFACEINFO *pInterfaceInfo
);
// called when another STA rejects or postpones an ORPC request
// вызывается, когда другой STA отклоняет или откладывает ORPC-запрос
DWORD RetryRejectedCall(
[in] HTASK dwThreadIdCallee,
[in] DWORD dwTickCount,
[in] DWORD dwRejectType
);
// called when a non-COM MSG arrives while the thread is
// awaiting an ORPC response
// вызывается, когда поступает не СОМ'овское MSG, пока
// поток ожидает ORPC-ответа
DWORD MessagePending(
[in] HTASK dwThreadIdCallee,
[in] DWORD dwTickCount,
[in] DWORD dwPendingType
); }
Для установки специального фильтра сообщений в СОМ существует API-функция
HRESULT CoRegisterMessageFilter([in] IMessageFilter *pmfNew, [out] IMessageFilter **ppmfOld);
Когда бы входящий ORPC-запрос ни пришел в STA-поток, вызывается метод фильтра сообщений
typedef enum tagCALLTYPE {
CALLTYPE_TOPLEVEL,
// STA not in outbound call
// STA не в исходящем вызове
CALLTYPE_NESTED,
// callback on behalf of outbound call
// обратный вызов от имени исходящего вызова
CALLTYPE_ASYNC,
// asynchronous call
// асинхронный вызов
CALLTYPE_TOPLEVEL_CALLPENDING,
// new call while waiting
// новый вызов во время ожидания
CALLTYPE_ASYNC_CALLPENDING
// async call while waiting
// асинхронный вызов во время ожидания
} CALLTYPE;
Вложенный (реентерабельный) вызов и незаконченный (нереентерабельный) вызов верхнего уровня происходят, пока поток ожидает ORPC-ответа в канале. Вызовы верхнего уровня происходят в тех случаях, когда в апартаменте нет активных вызовом.
В СОМ определено перечисление, которое должна возвратить реализация
typedef enum tagSERVERCALL {
SERVERCALL_ISHANDLED,
// accept call and forward to stub
// принимаем вызов и направляем его заглушке
SERVERCALL_REJECTED,
// tell caller that call is rejected
// сообщаем вызывающему объекту, что вызов отклонен
SERVERCALL RETRYLATER
// tell caller that call is postponed
// сообщаем вызывающему объекту, что вызов отложен
} SERVERCALL;