I have a STA COM object that implements a native interface. My user interface has a custom proxy server, which was created from code generated by the MIDL compiler. I would like to be able to make interface calls from other apartments asynchronously. I found that the synchronous interface respects the OLE message filter in the calling thread, but asynchronous interface calls do not. This means that COM-asynchronous calls cannot be used in fire and swell mode if the calling apartment has a message filter that suggests repeating the call later.
Is this expected? Is there a way around this otherwise than not using a message filter without using the fire and swell operations, or have a separate homegrown component just to control the fire-and-forget operations?
In the code below, MessageFilter is a simple in-module implementation of IMessageFilter that routes lambda calls. If I do not use message filters, synchronous and asynchronous calls work fine. If I use the message filters shown below, the synchronous call works (after the main STA message filter stops returning SERVERCALL_RETRYLATER), but the asynchronous call ends immediately with an error and never retries.
The main STA has a message filter that is delayed for a period of time.
chrono::time_point<chrono::system_clock> defer_until = ...;
auto message_filter = new MessageFilter;
message_filter->AddRef();
message_filter->handle_incoming_call
= [defer_until](DWORD, HTASK, DWORD, LPINTERFACEINFO)
{
return chrono::high_resolution_clock::now() >= defer_until
? SERVERCALL_ISHANDLED
: SERVERCALL_RETRYLATER;
};
CoRegisterMessageFilter(message_filter, nullptr);
STA , COM .
auto message_filter = new MessageFilter;
message_filter->AddRef();
message_filter->retry_rejected_call
= [](HTASK, DWORD, DWORD)
{
return 0;
};
CoRegisterMessageFilter(message_filter, nullptr);
STA STA.
IGlobalInterfaceTablePtr global_interface_table;
global_interface_table.CreateInstance(CLSID_StdGlobalInterfaceTable);
IMyInterfacePtr object_interface;
global_interface_table->GetInterfaceFromGlobal(cookie, __uuidof(IMyInterface), reinterpret_cast<LPVOID*>(&object_interface)));
:
HRESULT hr = object_interface->SomeMethod();
:
ICallFactoryPtr call_factory;
object_interface->QueryInterface(&call_factory);
AsyncIMyInterfacePtr async_call;
call_factory->CreateCall(__uuidof(AsyncIMyInterface), nullptr, __uuidof(AsyncIMyInterface), reinterpret_cast<LPUNKNOWN*>(&async_call)));
async_call->Begin_SomeMethod();
HRESULT hr = async_call->Finish_SomeMethod();