我正在使用ESRI的ArcObjects COM库,我正在努力弄清楚“选择”应该是什么类型:
IMxDocument doc = m_application.Document as IMxDocument;
object selected = doc.SelectedItem;
SelectedItem返回一个comobject(非空),通常表示当前选择的数据类型。但是我没有最微弱的想法,我应该把它投入到什么类型。当我调试它时,我真的没有看到任何有用的东西:
(在设置值后观察调试)
ESRI的ArcObjects库非常庞大,文档记录很差,我根本无法理解。我甚至竟然手动检查了大约50个我认为应该是的接口。
有没有人有任何想法如何解决这个问题?
编辑澄清他们的文档绝对没有帮助,他们的论坛也没有。
答案 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 或工作区。
如果选择了多个项目,则参考是 设置对象。
答案 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的实例吗?