COM如何选择如何编组接口?

时间:2009-11-12 08:13:47

标签: windows com interop com-interop

当我得到它时,有三种方法可以在COM中实现编组:

  • typelib marshalling
  • proxy / stub marshalling
  • 通过对象实现IMarshal

现在组件使用者(用户)如何选择将使用哪一个?它是自己决定并使用首选方式还是调用一些内置函数并解决了它的问题?

我目前遇到以下情况:我的组件实现了一个自定义接口ICustomInterface,它也是由另一家公司的组件实现的。我的组件没有typelib,也没有实现IMarshal。系统注册表包含HKCR \ Interface {uuidof(ICustomInterface)} \ ProxyStubClsid32密钥,其中包含可以跟踪到其他公司提供的库的代理/存根的GUID。

现在,当我的组件使用者初始化我的组件时,它调用QueryInterface()从我的组件请求IMarshal,当返回E_NOINTERFACE时,它什么都不做。为什么这样 - 为什么其他公司的代理/存根库没有启动?

2 个答案:

答案 0 :(得分:5)

如果通过在{00020424-0000-0000-C000-000000000046}下添加其CLSID HKCR\Interfaces\{iid}\ProxyStubClsid(其中{iid}是您的接口的GUID)将接口标记为使用标准封送器,则COM运行时将使用typelib(oleautomation)编组。您还需要注册一个类型库,以便运行时提取参数信息,并且您只能使用某个类型的子集。还有一些(旧)信息herehere

如果要使用由IDL从MIDL编译器生成的自定义代理/存根,则需要将接口注册表项更改为该代理对象的CLSID。这使您可以使用更广泛的类型,例如“原始”阵列。

如果你支持IMarshal,那么就会优先使用这些机制。这意味着您可以更改对象以聚合自由线程封送程序(使用其IMarshal的实现),而无需更改注册表中的任何内容。这将避免创建任何代理。

希望这有帮助。

答案 1 :(得分:0)

我对此有点生疏,但你的项目中是否有一个名为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);
}