找出可以查询COM对象的接口?

时间:2010-12-02 18:56:57

标签: c# com

我正在使用ESRI的ArcObjects COM库,我正在努力弄清楚“选择”应该是什么类型:

IMxDocument doc = m_application.Document as IMxDocument;
object selected = doc.SelectedItem;

SelectedItem返回一个comobject(非空),通常表示当前选择的数据类型。但是我没有最微弱的想法,我应该把它投入到什么类型。当我调试它时,我真的没有看到任何有用的东西:

http://imgur.com/Yfo6G

(在设置值后观察调试)

ESRI的ArcObjects库非常庞大,文档记录很差,我根本无法理解。我甚至竟然手动检查了大约50个我认为应该是的接口。

有没有人有任何想法如何解决这个问题?

编辑澄清他们的文档绝对没有帮助,他们的论坛也没有。

7 个答案:

答案 0 :(得分:8)

我不熟悉那个图书馆,但我可以提出一些建议。一旦从COM的角度看问题,你就会发现没有简单的答案。

(请记住,在COM中所有对象都只是对象,并且唯一的要求是它必须支持IUNKNOWN(可能还有其他接口)。所以问题的答案是“它是什么类型的对象”通常可以有不止一个答案。)

要记住的重要一点是,在COM中,对象的接口列表没有像在.NET中那样在任何类型的元数据中定义(除了库通常提供可选的类型库作为开发工具的一种文档形式 - 一分钟内更多内容。

接口列表仅由调用IUNKNOWN的QueryInterface()方法的结果正式定义 - 也就是说,它完全由执行代码的结果定义。

有时列表可能是硬编码的。通常情况下,列表可能直到运行时才知道,甚至可能不知道,直到有人问。唯一的规则是接口列表需要稳定,我称之为 sensible :列表不能随着时间的推移而改变给定的对象实例;它必须支持IUNKNOWN,有时人们会忘记;如果它支持派生接口,它必须支持它的基础;还有几个我确定我忘记了。

最后一点对您的问题至关重要:COM不知道先验任何对象支持哪些接口。 .NET运行时也不知道 - 无论如何都不是来自COM。 .NET知道的唯一方法是,对象的类型库是否返回的对象是特定接口。缺少这一点,你只需要一个IUNKNOWN指针,你必须通过代码询问特定的接口,看看你是否得到了除NULL以外的答案。

由于SelectedItem属性的类型是对象,这意味着类型库只是说“返回类型是IUNKNOWN类型的接口指针”(它可能是IDISPATCH,但原理是站立的)。确切的类型显然取决于运行时的情况 - “现在正在选择什么”。

(在.NET中,返回类型实际上是System.__ComObject,因为你没有得到一个裸接口指针,而是一个COM可调用包装器,它是基于.NET的代理对象)

你受库的(穷人?)文档的支配,以获得返回对象可能支持的接口类型的线索。缺乏这一点,像Chibacity这样的代码也可能会让你得到一个部分列表(我没有审查过那段代码)。最终,您可能希望使用该代码在调试期间获取候选接口列表。

一旦你知道了一些你感兴趣的可能性,你可以通过使用C#as运算符(这会导致COM可调用包装器针对本机对象发出相应的COM法术)来节省一些打字麻烦。

答案 1 :(得分:6)

在阅读了你的问题,答案和评论之后,你可能不得不写一个实用工具来蛮力地找到答案。

使用反射从互操作程序集中删除接口列表,然后只需循环遍历此列表,并查看对象是否依次支持每个接口。

<强>更新

一些示例代码:

    object unknown = //your com object...

    Type someComObjectType = typeof(ExampleTypeInInteropAssembly);

    Assembly interopAssembly = someComObjectType.Assembly;

    Func<Type, bool> implementsInterface = iface =>
    {
        try
        {
            Marshal.GetComInterfaceForObject(unknown, iface);
            return true;
        }
        catch (InvalidCastException)
        {
            return false;
        }
    };

    List<Type> supportedInterfaces = interopAssembly.
        GetTypes().
        Where(t => t.IsInterface).
        Where(implementsInterface).
        ToList();

    if (supportedInterfaces.Count > 0)
    {
        supportedInterfaces.ForEach(Console.WriteLine);
    }
    else
    {
        Console.WriteLine("No supported interfaces found :(");
    }

答案 2 :(得分:1)

我认为文档在某些地方缺乏,但帮助在您的情况下非常具体:

  

<强>说明

     

此属性返回对当前所选项目的引用   目录。返回是 IUnknown ,因为那里   是所选项目可以使用的几个可能对象。

     

在“展示位置”标签中工作时,参考可以是地图   对象,如果您选择了数据框,则为图层对象之一   (FeatureLayer,FDOGraphicsLayer等),如果您选择了图层,或   如果您选择了唯一值或标题,则 LegendGroup

     

在“源”选项卡中,引用可以是上述任何对象   加上 FeatureDataset 工作区

     

如果选择了多个项目,则参考是   设置对象。

http://help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/index.html#/SelectedItem_Property/000v00000124000000/

答案 3 :(得分:0)

尝试选择.GetType()。ToString();

它应该给出它的对象类型。

答案 4 :(得分:0)

尝试阅读文档。如果SDK没有帮助,请尝试阅读Windows Resource Kit和Visual C ++附带的OLEView实用程序中的类型库。

答案 5 :(得分:0)

我很害怕没有办法列出com对象实现的接口。但是,您仍然可以通过查询您感兴趣的界面列表来强制它。

修改

一些可能有用的代码:

foreach(Type comInterfacType in comInterfaceTypesIAmInterestedIn) {
  IntPtr comInterface = Marshal.GetComInterfaceForObject(o, comInterfaceType);
  if(comInterface != IntPtr.Zero) {
    Console.WriteLine("o implements " + comInterfaceType);
    Marshal.ReleaseComObject(o);
  }
}

答案 6 :(得分:0)

(会添加这个作为评论,但我是一个菜鸟,我的代表不够)

自从我使用ArcObjects以来已经有一段时间了,但是我确实记得对象模型非常庞大且文档记录不清。也就是说,IMxDocument.SelectedItem不是指在TOC / layers控件中选择的项目吗?如果是这样,它不会返回IMap或ILayer的实例吗?