У меня есть пользовательский интерфейс, определенный в библиотеке типов и реализованный в моем коде. Я не создал свой собственный прокси / заглушку. Я успешно маршалировал указатель интерфейса из моего основного потока (STA) в фоновый поток (STA), в моем случае используя IGlobalInterfaceTable.
Из этого фонового потока я хочу сделать асинхронный вызов объекта в потоке пользовательского интерфейса. Я не реализовал ICallFactory в моем объекте. Я вижу, что стандартный прокси действительно реализует ICallFactory (т.е. я могу успешно QI в фоновом потоке для ICallFactory). Но CreateCall для моего пользовательского интерфейса происходит сбой с HRESULT 0x80040150 (не удалось прочитать ключ из реестра).
Нужно ли создавать свой собственный прокси, который явно реализует ICallFactory чтобы сделать это?
Вот мой IDL:
[
object,
uuid(92303FE7-A79D-47DD-923F-62062105C00E),
async_uuid(2880C40C-9965-4544-AE39-DF08056E8CB6),
nonextensible,
pointer_default(unique),
oleautomation
]
interface IFoo: IUnknown
{
HRESULT Foo([in] long a, [in] long b);
}
[
uuid(D58B0A31-A2D5-4BFB-8702-3B710320493B)
]
coclass Foo
{
[default] interface IFoo;
};
А вот фоновый поток proc в моем модульном тесте:
static DWORD WINAPI threadproc(LPVOID lpParameter)
{
// get arguments
DWORD cookie = *(DWORD*)lpParameter;
// initialize COM
Assert::AreEqual(S_OK, CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
{
// get global interface table
IGlobalInterfaceTablePtr globalInterfaceTable;
Assert::AreEqual(S_OK, globalInterfaceTable.CreateInstance(CLSID_StdGlobalInterfaceTable));
// get object
MyLib::IFooPtr object;
Assert::AreEqual(S_OK, globalInterfaceTable->GetInterfaceFromGlobal(cookie, MyLib::IID_IFoo, (LPVOID*)&object));
// get async call factory
ICallFactoryPtr callFactory;
Assert::AreEqual(S_OK, object->QueryInterface(&callFactory));
//
// Everything is fine up until the CreateCall call below,
// which fails with HRESULT 0x80040150
//
// create async call object
IUnknownPtr callObject;
Assert::AreEqual(S_OK, callFactory->CreateCall(MyLib::IID_AsyncIFoo, NULL, IID_IUnknown, &callObject));
}
// uninitialize COM
CoUninitialize();
// success
return 0;
}
Насколько я знаю, универсальный маршаллер не работает с Async COM. Вам необходимо создать (сгенерированный MIDL) прокси (хотя, IIRC, вы можете объединить заглушки, если вы создаете DLL).
Вам также необходимо зарегистрировать прокси-библиотеку DLL (и собрать ее с помощью определения -DREGISTER_PROXY_DLL). Для работы Async COM требуется больше ключей реестра.