IsAssignableFrom with COM

别说谁变了你拦得住时间么 提交于 2020-01-25 01:52:15

问题


I'm working with a COM-API, Autodesk Inventor.

This test passes:

[Test]
public void CastTest()
{
    Inventor.Document document = _application.ActiveDocument;
    var assemblyDocument = (Inventor.AssemblyDocument)document;
    Assert.NotNull(assemblyDocument);
}

This test fails:

[Test]
public void IsAssignableFromTest()
{
    Assert.IsTrue(typeof(Inventor.Document).IsAssignableFrom(typeof(Inventor.AssemblyDocument)));
}

I don't know much about COM at all, is there a way to check if one COM type "inherits" another using reflection or some COM voodoo?


回答1:


The COM type system is not compatible to .NET. Instead you are programming against wrappers (so called RCW's). To test if you can convert one COM object into another one, COM provides the QueryInterface-method as a member of IUnknown, which every COM object must implement. However .NET hides those details for you so that you can write COM code that does "feel" like .NET code.

If you take a look at the disassembly of Inventors interop-library, you will recognize, that there is no direct relation between Document and AssemblyDocument. Both are interfaces that do only implement the default interface of their respective coclasses and are attributed with the CoClassAttribute. But in their inheritance tree, they are not directly related to each other. They may both implement the same interface (I guess something like IDocument), but you cannot convert a WinForms button into a picture box either, even though they both implment the Control-interface.

This is what reflection and IsAssignableFrom is testing: The metadata that each CLR-type provides. COM works different here. Each COM object can "decide" on it's own if it can be called from another interface. Therefor it implements QueryInterface. And therefor you have to create an instance of your source type, before you can perform your test (COM does not know static members).

A traditional cast does call QueryInterface, so your test could simply look like:

[Test]
public void IsAssignableFromTest()
{
    Assert.IsNotNull(_application.ActiveDocument as Inventor.AssemblyDocument);
}

Otherwise you could call QueryInterface directly through the Marshal-class.

However, it is not possible to test type metadata through reflection with COM objects.




回答2:


If you want to use the Inventor API, you could check for document type before casting it to another type.

Ex.: (VBA)

Dim oDoc As Document
Dim oAssyDoc As AssemblyDocument

Set oDoc = ThisApplication.ActiveDocument

If oDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
    Set oAssyDoc = oDoc
End If

Best regards,



来源:https://stackoverflow.com/questions/23885002/isassignablefrom-with-com

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!