首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >对于COM可调用的包装器,ComDefaultInterface有什么用途吗?

对于COM可调用的包装器,ComDefaultInterface有什么用途吗?
EN

Stack Overflow用户
提问于 2013-10-14 00:18:55
回答 1查看 3K关注 0票数 5

ComDefaultInterfaceAttribute属性的用途是什么,如果ClassInterfaceType.None 编组作为IUnknownIDispatch的托管对象是什么?

考虑下面的C#类AuthenticateHelper,它实现了COM IAuthenticate

代码语言:javascript
运行
复制
[ComImport]
[Guid("79eac9d0-baf9-11ce-8c82-00aa004ba90b")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAuthenticate
{
    [PreserveSig]
    int Authenticate(
        [In, Out] ref IntPtr phwnd,
        [In, Out, MarshalAs(UnmanagedType.LPWStr)] ref string pszUsername,
        [In, Out, MarshalAs(UnmanagedType.LPWStr)] ref string pszPassword);
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(IAuthenticate))]
public class AuthenticateHelper: IAuthenticate
{
    public int Authenticate(ref IntPtr phwnd, ref string pszUsername, ref string pszPassword)
    {
        phwnd = IntPtr.Zero;
        pszUsername = String.Empty;
        pszPassword = String.Empty;
        return 0;
    }
}    

我刚刚了解到,.NET互操作运行库将IUnknown的实现与此类类的IAuthenticate分离开来:

代码语言:javascript
运行
复制
AuthenticateHelper ah = new AuthenticateHelper();
IntPtr unk1 = Marshal.GetComInterfaceForObject(ah, typeof(IAuthenticate));
IntPtr unk2 = Marshal.GetIUnknownForObject(ah);
Debug.Assert(unk1 == unk2); // will assert!

我已经了解到,在实现IServiceProvder时,由于(以下所示)的没有工作,它在从QueryService返回时会在客户端代码中崩溃

代码语言:javascript
运行
复制
[ComImport]
[Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
    [PreserveSig]
    int QueryService(
        [In] ref Guid guidService,
        [In] ref Guid riid,
        [Out, MarshalAs(UnmanagedType.Interface, IidParameterIndex=1)] out object ppvObject    
}

// ...

public readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");

AuthenticateHelper ah = new AuthenticateHelper();

int IServiceProvider.QueryService(ref Guid guidService, ref Guid riid, out object ppvObject)
{
    if (guidService == typeof(IAuthenticate).GUID && (riid == IID_IUnknown || riid == guidService))
    {
        ppvObject = this.ah; // same as ppvObject = (IAuthenticate)this.ah
        return S_OK;
    }
    ppvObject = null;
    return E_NOINTERFACE;
}

我天真地期望AuthenticateHelper的实例将被封送为IAuthenticate,因为该类声明了[ComDefaultInterface(typeof(IAuthenticate))],因此该类实现的惟一默认COM接口是AuthenticateHelper。但是,这没有起作用,显然是因为对象仍然被封送为IUnknown

的工作原理是,但它更改了QueryService的签名,使其不太适合使用(而不是提供)对象:

代码语言:javascript
运行
复制
[ComImport]
[Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
    [PreserveSig]
    int QueryService(
        [In] ref Guid guidService,
        [In] ref Guid riid,
        [Out] out IntPtr ppvObject);
}

// ...

int IServiceProvider.QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
{
    if (guidService == typeof(IAuthenticate).GUID && (riid == IID_IUnknown || riid == guidService))
    {
        ppvObject = Marshal.GetComInterfaceForObject(this.ah, typeof(IAuthenticate));
        return S_OK;
    }
    ppvObject = IntPtr.Zero;
    return E_NOINTERFACE;
}

那么,如果ComDefaultInterface不影响封送处理,为什么要指定它呢?我看到的唯一其他用途是类型库生成。

调用我的IServiceProvider::QueryService托管实现的非托管客户端COM代码。有没有办法使QueryService在我的例子中工作,而不求助于低级别的东西,如GetComInterfaceForObject

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-10-14 00:32:35

只有在单个对象上实现了多个接口时,ComDefaultInterface属性才真正有用。在某些情况下,对象公开的“第一个”接口可能很重要,但顺序实际上不是由语言指定的。该属性强制首先发出您指定的接口,其他任何接口都以非指定的顺序出现。

它也适用于从托管代码导出到COM的类,以便以CoCreateObject以外的其他方式将类返回给它们的客户端获得正确的“默认”接口(例如,如果您的类被标记为[ClassInterface(ClassInterfaceType.None)])。

对于通过托管代码使用的导入类,或者只实现单个接口的类,该属性是无害的,但本质上是无用的。

此外,就您的上一个问题而言,在完全托管代码中使用COM对象时,很少需要使用低级接口查询。如果使用普通的C#和is类型强制关键字,则as编译器将自动处理as调用。在您的示例中,AuthenticationHelper是作为托管AuthenticationHelper类创建的,因为这是您所要求的;如果您知道您想要的接口,并且知道它已经实现,请请求:

代码语言:javascript
运行
复制
AuthenticateHelper ah = new AuthenticateHelper();
IAuthenticate ia = ah as IAuthenticate;
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19351840

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档