iLogic: ActiveDocument.ComponentDefinition throws exception for specific document

By Xiaodong Liang

Recently, we got a strange issue. With a specific dataset, we opened all files in cascade views, then activated each document and ran an external rule. The rule is quite simple. It just gets the document ComponentDefinition and access parameters.

Dim compDef = ThisApplication.ActiveDocument.ComponentDefinition

For most documents, it works well. but for specific assembly document, it throws an exception that says: Member not found.

We doubted ComponentDefinition / Parameters have been broken when activating the document at his side, so we tested with a VBA code. But the code tells the ComponentDefinition / Parameters are always valid. While the issue seems not always reproducible.

Finally, our expert of iLogic Mike Deck shared the insights:

It is caused by internal .NET behavior to do with COM interop. Here’s a simplified rule that will reproduce it:

  • Create a new part

  • Run the rule in the part

  • Create a new assembly

  • Run the rule in the assembly

The order matters: it won’t break if you run it in the assembly first.

Here’s what’s happening: ActiveDocument returns a Document object. There is no ComponentDefinition property on the Document object. So VB.NET tries to do late binding. When you run the rule on a Document that is also a PartDocument, it will find a ComponentDefinition property with a DispId on that object. Then later you run the rule on a Document that is also an AssemblyDocument. It also has a ComponentDefinition property, but with another DispId.

For some reason, VB.NET will fail to find that property. it might probably cache the first DispId (from PartDocument), and associates it with the Document interface. Then it thinks that it can always use that DispId to access ComponentDefinition on a Document. But that DispId will fail if the object is an AssemblyDocument.

It seems like an issue of Microsoft .NET. So in such case, there is a workaround. In VB.NET code, never try to access the ComponentDefinition on a Document object. Instead, always cast it to a PartDocument or AssemblyDocument first. Here’s sample code to get the UserParameters:

Dim doc = ThisApplication.ActiveDocument

Dim params As Parameters = Nothing

If doc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then

  Dim assemDoc As AssemblyDocument = doc

  params = assemDoc.ComponentDefinition.Parameters

ElseIf doc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then

  Dim partDoc As PartDocument = doc

  params = partDoc.ComponentDefinition.Parameters

End If

 

Dim userparams As UserParameters = params.UserParameters

It requires a lot more than a single line of code, but it avoids the problem.


Comments

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading