【发布时间】:2015-05-13 13:52:36
【问题描述】:
我有一个在类型库中定义并在我的代码中实现的自定义接口。我还没有创建自己的代理/存根。我已经成功地将接口指针从我的主线程 (STA) 编组到后台线程 (STA),在我的例子中使用 IGlobalInterfaceTable。
从那个后台线程,我想对 UI 线程上的对象进行异步调用。我没有在我的对象中实现ICallFactory。我看到标准代理确实实现了ICallFactory(即,我可以在ICallFactory 的后台线程上成功QI)。但是我的自定义界面的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;
};
这是我的单元测试中的后台线程过程:
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;
}
【问题讨论】:
-
显示您如何称呼
CreateCall。它失败的错误是什么?另外,您的界面是双界面(源自IDispatch)吗?来自this piece of documentation:“注意异步支持不适用于IDispatch或继承IDispatch的接口。” -
我确实看到了该文档并采取了相应的行动。但是,我认为我违反了规则。根据上述文档,异步内容不适用于 IDispatch。所以我的接口只继承自 IUnknown。但是,当接口未标记为 [dual] 时,全局接口表的 GetInterfaceFromGlobal 方法失败并显示 E_FAIL,据我所知,它必须从 IDispatch 继承。在这一点上,我已经离开 [dual] 以进行编组工作,但将 IDispatch 取出以希望使异步调用工作。
-
另外:添加了错误详情
-
似乎 [oleautomation] 同样解决了编组问题(并且我的界面与 OLE 自动化兼容,给定定义 here)。并且标记为 [oleautomation] 的接口不必从 IDispatch 继承。现在测试 ICallFactory...
-
尝试在 IDL 的
coclass子句中提及AsyncIFoo。我敢打赌,类型库没有描述它。0x80040150是REGDB_E_READREGDB“无法从注册表中读取密钥” - 我的猜测是,这是通用编组器试图读取HKCR\Interface\{AsyncIFoo IID}以弄清楚如何编组它。如果这不起作用,那么我怀疑您毕竟必须构建代理/存根 DLL - TLB 驱动的编组不会削减它。
标签: c++ winapi com ole-automation