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

发布于 2024-08-10 11:56:23 字数 500 浏览 5 评论 0原文

据我了解,在 COM 中实现编组有三种方法:

  • typelib 编组
  • 代理/存根编组
  • 通过对象实现 IMarshal

现在组件消费者(用户)如何选择使用哪一种?它是自行决定并使用首选方式,还是调用某些内置函数并为其解决问题?

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

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

As I get it there're three ways to implement marshalling in COM:

  • typelib marshalling
  • proxy/stub marshalling
  • implementing IMarshal by the object

now how does the component consumer (user) choose which one will be used? Does it decide on its own and use the preferred way or does it call some built-in function and it solves the problem for it?

I currently experience the following: my component implements a custom interface ICustomInterface that is also implemented by a component from another company. My component doesn't have a typelib and doesn't implement IMarshal. The system registry contains the HKCR\Interface{uuidof(ICustomInterface)}\ProxyStubClsid32 key with a GUID of the proxy/stub that can be traced to a library provided by that other company.

Now when my component consumer initializes my component it calls QueryInterface() requesting IMarshal from my component and when returned E_NOINTERFACE it just does nothing. Why is this - why doesn't proxy/stub library from the other company kick in?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜空下最亮的亮点 2024-08-17 11:56:23

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

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

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

希望这有帮助。

The COM runtime will use typelib (oleautomation) marshalling if you mark your interface as using the standard marshaler by adding its CLSID {00020424-0000-0000-C000-000000000046} under HKCR\Interfaces\{iid}\ProxyStubClsid (where {iid} is the GUID of your interface). You'll need to have a typelibrary registered too, in order for the runtime to extract the parameter information, and you can only use a certain subset of types. There's some more (old) information here and here.

If you want to use a custom proxy/stub, as generated by the MIDL compiler from your IDL, then you'll need to change the interface registry entry to be the CLSID of that proxy object instead. This enables you to use a wider range of types, e.g. "raw" arrays.

If you support IMarshal then that's what'll be used in preference to either of these mechanisms. This means you can change your object to aggregate the free-threaded marshaler (using its implementation of IMarshal) without having to change anything in the registry. This will avoid any proxies being created.

Hope this helps.

北音执念 2024-08-17 11:56:23

我对此有点生疏,但是你的项目中有一个名为blindquery的函数吗? (如果您创建了 C++ ATL 项目,则通常由向导声明)。函数内的断点。由于代码错误,由向导生成的函数经常会出现 queryinterface 返回 E_NOINTERFACE 的问题。

从我的旧项目中编辑(找到示例代码) _盲目查询

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);
}

I am a bit rusty at this, but do you have a function named blindquery in your project ? (its usually declared by the wizard if you created a C++ ATL project). Breakpoint inside the function. The function is generated by the wizard often has problems with queryinterface returning E_NOINTERFACE due to buggy code.

edit (found sample code) from my old project _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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文