据我了解,在 COM 中实现编组有三种方法:
现在组件consumer(用户)如何选择使用哪一个?它是自行决定并使用首选方式,还是调用某些内置函数并解决问题?
我目前遇到以下情况:我的组件实现了一个自定义接口
ICustomInterface
,该接口也由另一家公司的组件实现。我的组件没有类型库并且没有实现 IMarshal。系统注册表包含 HKCR\Interface{uuidof(ICustomInterface)}\ProxyStubClsid32 项,其中包含代理/存根的 GUID,可以追溯到该其他公司提供的库。
现在,当我的组件使用者初始化我的组件时,它会调用 QueryInterface() 向我的组件请求 IMarshal,当返回 E_NOINTERFACE 时,它什么也不做。这是为什么 - 为什么其他公司的代理/存根库没有启动?
如果您通过在
{00020424-0000-0000-C000-000000000046}
下添加其 CLSID HKCR\Interfaces\{iid}\ProxyStubClsid
(其中 {iid} 是接口的 GUID)将接口标记为使用标准封送拆收器,则 COM 运行时将使用 typelib(oleautomation)封送处理。您还需要注册一个类型库,以便运行时提取参数信息,并且您只能使用特定类型的子集。还有更多(旧)信息这里和这里。
如果您想使用由 MIDL 编译器从 IDL 生成的自定义代理/存根,那么您需要将接口注册表项更改为该代理对象的 CLSID。这使您能够使用更广泛的类型,例如“原始”数组。
如果您支持
IMarshal
,那么将优先使用这两种机制。这意味着您可以更改对象以聚合自由线程封送拆收器(使用其 IMarshal
的实现),而无需更改注册表中的任何内容。这将避免创建任何代理。
希望这有帮助。
我对此有点生疏,但是你的项目中有一个名为blindquery的函数吗? (如果您创建了 C++ ATL 项目,则通常由向导声明)。函数内的断点。由于代码错误,由向导生成的函数经常会出现查询接口返回 E_NOINTERFACE 的问题。
从我的旧项目中编辑(找到示例代码)_blindquery
class ATL_NO_VTABLE CChildEvents :
public CComObjectRootEx <CComSingleThreadModel>,
public CComCoClass<CChildEvents, &CLSID_ChildEvents>,
public IDispatchImpl<IChildEvents, &IID_IChildEvents, &LIBID_XXX>
{
public:
CChildEvents(void) :
m_pItfMgr(0)
{
}
/* called from internalQI to tear off a new blind interface */
static HRESULT WINAPI _BlindQuery(void *pvThis, REFIID riid, void **ppv, DWORD dw);
DECLARE_REGISTRY_RESOURCEID(IDR_CHILDEVENTS)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CChildEvents)
COM_INTERFACE_ENTRY(IChildEvents)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY_FUNC_BLIND(0, _BlindQuery)
END_COM_MAP()
};
HRESULT WINAPI CChildEvents::_BlindQuery(void *pvThis, REFIID riid, void **ppv, DWORD /* dw */ )
{
HRESULT hr = E_NOINTERFACE;
USES_CONVERSION;
try
{
if(pvThis == NULL)
{
ATLASSERT(FALSE);
}
else
{
/*
* cast the pvThis pointer to the actual class £
* so we can use it here £
* reinterpret_cast should be safe since we're calling ourself
*/
CChildEvents *pThis = reinterpret_cast < CChildEvents * > (pvThis);
if(pThis == NULL)
{
ATLASSERT(FALSE);
}
else
{
/* check to see if it matches on of our children's DIID */
if(memcmp(&riid,&l_someotherguid,sizeof(GUID)) == 0) {
/* if so cast to a IDispatch -- the standard for event interfaces */
*ppv = reinterpret_cast < IDispatch * > (pvThis);
/* addref */
pThis->AddRef();
/* reply */
hr = S_OK;
}
}
}
}
catch(...)
{
ATLASSERT(FALSE);
}
/* must not be in our map - tell them to GO FISH */
return(hr);
}