Generating CC parts thru API - Inventor freezes/crashes

Generating CC parts thru API - Inventor freezes/crashes

fredform
Advocate Advocate
338 Views
10 Replies
Message 1 of 11

Generating CC parts thru API - Inventor freezes/crashes

fredform
Advocate
Advocate

Hi,

 

I am building a configurator for my company that will rely heavily on Content Center parts. I have made several iterations of my code but keep stumbling on what seems to be the same underlying problem - Querying the Content Center before it is fully "initialized" crashes Inventor.

 

For example, if I have been running Inventor for a while and used CC at some point, then the code runs fine (usually) but if I start a fresh session of Inventor and run my code before doing any UI operations it tends to crash (freezing/hanging only happens when debugging thru Visual Studio, otherwise it just crashes Inventor outright).

 

Debugging my DLL, I could determine that Inventor froze on this line:

 Dim treeNode As ContentTreeViewNode = _contentCenter.TreeViewTopNode

 

I thought I had then discovered the solution by "initializing" CC with this code:

Dim command As ControlDefinition = _invApp.CommandManager.ControlDefinitions.Item("CCV2PlaceButton")

command.Execute()

Dim treeNode As ContentTreeViewNode = _contentCenter.TreeViewTopNode

_invApp.CommandManager.StopActiveCommand()

 

As clicking the "Place from Content Center"-button before running my code made it work without freezing...But that only worked until here:

 

Dim childNodes As ContentTreeViewNodesEnumerator = treeNode.ChildNodes
'Dim child As ContentTreeViewNode = treeNode.ChildNodes

 

I then tried generating a member thru the UI before running the code which then made the "ChildNodes"-line pass but only until a different family was requested and the code froze again (edit: actually it was the same family but the next "section" of the path, i.e. "Tube & Pipe" & "|" & "Fittings"...and here it hangs).

 

Is there some other way to load CC to avoid these problems or is there something else I can do? My code gets the full CC path from a configuration file so if there's a way to access the family directly I guess I wouldn't need to loop thru CC to find the path/family object.

 

Here's the function that gets the CC families and is currently not working: 

    Public Function GetFamilyData(ccPath As String, familyName As String) As ContentCenterFamilyLookup
        Dim key As String = ccPath & "|" & familyName

        Dim familyData As ContentCenterFamilyLookup = Nothing
        If _familyCache.TryGetValue(key, familyData) Then Return familyData

        Dim nodeNames() As String = ccPath.Split(":"c)
        Dim treeNode As ContentTreeViewNode = _contentCenter.TreeViewTopNode

        For Each nodeName As String In nodeNames
            Dim foundNode As ContentTreeViewNode = Nothing

            For Each child As ContentTreeViewNode In treeNode.ChildNodes
                If String.Equals(child.DisplayName, nodeName, StringComparison.OrdinalIgnoreCase) Then
                    foundNode = child
                    Exit For
                End If
            Next

            If foundNode Is Nothing Then Throw New Exception("Content Center node not found: " & nodeName)

            treeNode = foundNode
        Next

        For Each family As ContentFamily In treeNode.Families
            If String.Equals(family.DisplayName, familyName, StringComparison.OrdinalIgnoreCase) Then
                familyData = IndexFamilyData(family, ccPath)
                _familyCache(key) = familyData
                Return familyData
            End If
        Next

        Throw New Exception("Content Center family not found: " & ccPath & " | " & familyName)
    End Function

 

We use Inventor 2025/Vault Pro 2025, a single project file setup and a Vaulted Content Center. My DLL is currently setup to run on net8.0

 

I should also mention that running CC locally seems much more stable...

 

Best,

Fredrik

0 Likes
Accepted solutions (1)
339 Views
10 Replies
Replies (10)
Message 2 of 11

ca-d.one
Advisor
Advisor
Accepted solution

Hi @fredform !
Thanks for tracing exactly where the calls hang.

I'd save the family's ContentIdentifier in your configuration after a successful lookup => resolve it later with ContentCenter.GetContentObject and check for Nothing.
This avoids walking the tree; whether it avoids your startup failure still needs testing.

Does the direct lookup also freeze immediately after restarting Inventor ??
LG

 

Edit: AI-assisted content (Cad.one AI team, AI assistants); cross-checked by AI before posting; Dirk Prante takes responsibility.

_____________________________________________________________
Ihr fandet einen Beitrag hilfreich? Dann vergebt dafür doch Likes!
Eure Frage wurde erfolgreich gelöst? Dann einfach auf den 'Als Lösung akzeptieren'-Button klicken!

Autodesk Expert Elite Member

Dirk Prante

0 Likes
Message 3 of 11

JBerns
Advisor
Advisor

@fredform,

 

I too recall issues (crashes) placing CC parts, but I was using iLogic functions.

Does the API have anything equivalent to:

System.GC.Collect()

 

I was trying to place a washer, bolt, and nut. Regardless of order, Inventor crashed or errored on the third component.

I was trying to find my original post, but I recall someone from the community suggested the 'garbage collector' (GC) function. 

 

	' Add/Replace the hardware components
	' Left side of paddle
	Dim componentWL = Components.AddContentCenterPart("Washer_01L", WasherCCCategory, WasherCCFamily, 
													  {"PartNumber", Washer_String }, 
													  position := Nothing, grounded := False, 
													  visible := True, appearance := Nothing)

	Dim componentBL = Components.AddContentCenterPart("Bolt_01L", BoltCCCategory, BoltCCFamily, 
													  {"PartNumber", Bolt_String }, 
													  position := Nothing, grounded := False, 
													  visible := True, appearance := Nothing)
												 
	Try
		System.GC.Collect()
		Dim componentNL = Components.AddContentCenterPart("Nut_01L", NutCCCategory, NutCCFamily, 
													  	 {"PartNumber", Nut_String }, 
													  	 position := Nothing, grounded := False, 
													  	 visible := True, appearance := Nothing)
	Catch
		MessageBox.Show("A problem occurred placing the fastener nut." & vbCrLf & vbCrLf & "Contact the CAD Administrator." , "WARNING", MessageBoxButtons.OK, MessageBoxIcon.Warning)
	End Try

 

This resolved the placement issue and has worked well. 

I hope this may be helpful.

 

Regards,

Jerry

-----------------------------------------------------------------------------------------
CAD Administrator
Using AutoCAD & Inventor 2025
Autodesk Certified Instructor
Autodesk Inventor Certified Professional
Autodesk AutoCAD Certified Professional
0 Likes
Message 4 of 11

fredform
Advocate
Advocate

Hi @ca-d.one  

 

Yeah I came to the same conclusion pondering this late last night!

 

I also ran this little test in an ilogic rule, writing out the names of every CC family, of every standard of every accessible CC library!

 

Sub Main()
	Dim cc As Inventor.ContentCenter = ThisApplication.ContentCenter
	Dim topNode As Inventor.ContentTreeViewNode = cc.TreeViewTopNode
	
	LogFamilyPaths(topNode, "")
End Sub

Sub LogFamilyPaths(node As Inventor.ContentTreeViewNode, currentPath As String)

    Dim nodePath As String = currentPath

    If nodePath <> "" Then
        nodePath &= ":"
    End If

    nodePath &= node.DisplayName

    For Each family As Inventor.ContentFamily In node.Families
        Logger.Info(nodePath & " | " & family.DisplayName)
    Next

    For Each child As Inventor.ContentTreeViewNode In node.ChildNodes
        LogFamilyPaths(child, nodePath)
    Next

End Sub

 

Since that worked I guess my limitations may be part Visual Studio debugger and part overload to process that many families at once, repeatedly. Surprisingly, researching this I have yet to find a good way to loop only a given CC library (e.g. my own and skip the standard ones)? Seems like that would be a pretty useful filtering.

 

Either way, like you pointed out, putting the InternalName or ContentIdentifier in the configuration file and accessing the family directly seems like a much better approach overall.

 

I'll give it a try and report back in a few days.

 

Thanks!

0 Likes
Message 5 of 11

fredform
Advocate
Advocate

Hi @JBerns 

 

That's an interesting suggestion! I guess System.GC.Collect is just standard .NET so definitely available thru API or the like.

 

I'll test that out as well and see if there's any improvement to stability.

 

Best,

Fredrik

0 Likes
Message 6 of 11

ca-d.one
Advisor
Advisor

Hallo Jerry, hallo fredform,

System.GC.Collect() ist kein Inventor-Befehl, sondern kommt direkt aus .NET. Deshalb steht er in iLogic genauso zur Verfügung wie in jedem Add-In oder jeder externen Anwendung in VB.NET oder C#. Eine eigene Funktion dafür braucht die Inventor-API also nicht.

Bei COM-Objekten wie denen von Inventor hilft oft die „doppelte“ Variante besser, weil erst die Finalizer die COM-Verweise freigeben:

System.GC.Collect()
System.GC.WaitForPendingFinalizers()
System.GC.Collect()
 

Ausnahme VBA: Dort gibt es keinen Garbage Collector. Da hilft nur, nicht mehr benötigte Objekte konsequent mit Set obj = Nothing freizugeben.

Dass es gerade beim dritten Content-Center-Teil kracht, passt übrigens ins Bild. Jeder Aufruf erzeugt im Hintergrund COM-Objekte (Familie, Member, Datei), die sich ohne Aufräumen ansammeln.

Grüße
Dirk

KI-unterstützt erstellt (Cad.one KI-Team, KI-Assistenzsystem); verantwortet von Dirk Prante.

_____________________________________________________________
Ihr fandet einen Beitrag hilfreich? Dann vergebt dafür doch Likes!
Eure Frage wurde erfolgreich gelöst? Dann einfach auf den 'Als Lösung akzeptieren'-Button klicken!

Autodesk Expert Elite Member

Dirk Prante

0 Likes
Message 7 of 11

ca-d.one
Advisor
Advisor

Hi Jerry, hi fredform,

Your question got me curious, so I tried it out myself. Here's what I did and what came out of it.

Short answer first

You don't need anything special in the API. System.GC.Collect() isn't an Inventor command, it's plain .NET. So it works the same in iLogic, in an add-in or in a standalone app (VB.NET or C#).

Most people use the "double" version, because it also gives pending finalizers a chance to run:

(In VBA there's no garbage collector at all. There you can only let go of your own references with Set obj = Nothing.)

What I tested

I wanted to see whether you can place Content Center parts through the API directly, instead of using AddContentCenterPart. This way you have more control, and you can clean up after each part. Here's how I went about it:

Looked at the Content Center tree. First I ran a small read-only rule that walks through the tree and lists the families and their columns. That's how I found where washer, bolt and nut live in my (German) library, e.g. Verbindungselemente > Schrauben > Sechskantkopf > ISO 4017.
Checked the exact values. The size column is called "Bezeichnung" in German and SIZE internally. The values are written without spaces: 8, M8x30, M8. With M8 x 30 the row isn't found.
Wrote the rule. It walks the tree, finds the family, column and row, creates the part file with CreateMember and places it with Occurrences.Add. After each part it runs the garbage collector.
Had the code reviewed. Before running it, I had the code double-checked. The main change: I took out Marshal.ReleaseComObject. Releasing single COM objects by hand isn't a proper cleanup and can even break wrappers that are shared.
Ran it in Inventor 2026. New assembly, rule added, rule started: washer ISO 7089, bolt ISO 4017 M8x30 and nut ISO 4032 M8, one after the other.
Result

All three parts were placed without a crash. I ran it twice in a row, which gave six parts, still no problem (see screenshot).

One thing got in the way, though: I wasn't logged in to Vault. When CreateMember created the file, the Vault add-in popped up a login dialog, and the rule just sat there waiting. After clicking "No", everything ran through. So if your rule ever seems to "hang", check for a dialog hiding somewhere.

The rule

Good to know

 

 

Sub Main()
Dim asmDoc As Inventor.AssemblyDocument =
TryCast(ThisApplication.ActiveDocument, Inventor.AssemblyDocument)
If asmDoc Is Nothing Then
Throw New System.InvalidOperationException("An assembly document is required.")
End If

Dim occ As Inventor.ComponentOccurrence

occ = PlaceCCPart(ThisApplication, asmDoc,
New String() {"Verbindungselemente", "Unterlegscheiben", "Einfach"},
"ISO 7089", "Bezeichnung", "8")
occ = Nothing
ForceGc()

occ = PlaceCCPart(ThisApplication, asmDoc,
New String() {"Verbindungselemente", "Schrauben", "Sechskantkopf"},
"ISO 4017", "Bezeichnung", "M8x30")
occ = Nothing
ForceGc()

occ = PlaceCCPart(ThisApplication, asmDoc,
New String() {"Verbindungselemente", "Muttern", "Sechskant"},
"ISO 4032", "Bezeichnung", "M8")
occ = Nothing
ForceGc()
End Sub

Function PlaceCCPart(app As Inventor.Application,
asmDoc As Inventor.AssemblyDocument,
path As String(),
familyName As String,
colName As String,
value As String) As Inventor.ComponentOccurrence

' Walk the Content Center tree
Dim node As Inventor.ContentTreeViewNode = app.ContentCenter.TreeViewTopNode
For Each p As String In path
node = node.ChildNodes.Item(p)
Next

' Find the family
Dim fam As Inventor.ContentFamily = Nothing
For Each f As Inventor.ContentFamily In node.Families
If f.DisplayName = familyName OrElse f.InternalName = familyName Then
fam = f
Exit For
End If
Next
If fam Is Nothing Then Throw New System.InvalidOperationException("Family not found.")

' Find the column
Dim col As Inventor.ContentTableColumn = Nothing
For Each c As Inventor.ContentTableColumn In fam.TableColumns
If c.DisplayHeading = colName OrElse c.InternalName = colName Then
col = c
Exit For
End If
Next
If col Is Nothing Then Throw New System.InvalidOperationException("Column not found.")

' Find the row
Dim row As Inventor.ContentTableRow = Nothing
For Each r As Inventor.ContentTableRow In fam.TableRows
If r.GetCellValue(col) = value Then
row = r
Exit For
End If
Next
If row Is Nothing Then Throw New System.InvalidOperationException("Row not found.")

' Create (or reuse) the member file
Dim errCode As Object = Nothing
Dim errMsg As String = ""
Dim fileName As String = fam.CreateMember(row, errCode, errMsg)
If String.IsNullOrEmpty(fileName) Then
Throw New System.InvalidOperationException("CreateMember failed: " & errMsg)
End If

' Place it
Dim mat As Inventor.Matrix = app.TransientGeometry.CreateMatrix()
Return asmDoc.ComponentDefinition.Occurrences.Add(fileName, mat)
End Function

Sub ForceGc()
System.GC.Collect()
System.GC.WaitForPendingFinalizers()
System.GC.Collect()
End Sub

 

 

The tree names, family names and column headings above come from a German Content Center. In other languages they're different. If the rule should work everywhere, use the InternalName. The code already accepts both.
Why the GC helped in your case, I honestly can't say for sure. It could be COM references piling up, but my test doesn't prove that. It only shows that this way works without trouble.
Hope this helps!

Cheers,
Dirk

AI-assisted content (Cad.one AI team, AI assistants); cross-checked by AI before posting; Dirk Prante takes responsibility.

 

 

cadone_0-1790239922506.png

 

 

_____________________________________________________________
Ihr fandet einen Beitrag hilfreich? Dann vergebt dafür doch Likes!
Eure Frage wurde erfolgreich gelöst? Dann einfach auf den 'Als Lösung akzeptieren'-Button klicken!

Autodesk Expert Elite Member

Dirk Prante

Message 8 of 11

JBerns
Advisor
Advisor

@fredform,

 

A while back I was testing our custom content center library. I wanted to ensure I could place all components.

Attached is a rule that will place all non-suppressed rows of our library.

Be sure to edit all "NMC" references in the code, especially Line 53, so that the name matches your custom libraries.

If family.DisplayName.StartsWith("NMC ") AndAlso family.DisplayName.EndsWith(" - Inch") Then

Hope it is helpful.

 

Regards,

Jerry

-----------------------------------------------------------------------------------------
CAD Administrator
Using AutoCAD & Inventor 2025
Autodesk Certified Instructor
Autodesk Inventor Certified Professional
Autodesk AutoCAD Certified Professional
Message 9 of 11

lauri_barnhart
Autodesk
Autodesk

Greetings, @fredform.

 

Thank you for posting your question! Following up to see if any of the replies by ca-d.one or JBerns helped you resolve your question. Please consider clicking on the 'Accept Solution' button on any post that provided the clarity.

 

Best,


Lauri | Community Manager
0 Likes
Message 10 of 11

fredform
Advocate
Advocate

Hi @JBerns,

Thank you for sharing that code! No doubt it is useful for me and others. I played around with it a bit and will probably come back to it in the future for doing admin tasks/updates for our CC but as for solving my problem today it is far too slow a process. We currently have all the standard CC libraries present in our Vault, as well as our own custom library and with that many libraries to search thru it becomes infeasible. I just wish there was a simple way to ONLY query a specific library as that would reduce this processing significantly...

 

 

@lauri_barnhart 

I've been traveling and short of time to devote to this project but I'll try to post back later this week with a version of the code I will end up using, in the meantime I will mark @ca-d.one's first suggestion as the accepted solution as I think that is the way forward for me (incorporating the InternalName into the configuration file and void traversing the CC tree altogether).

 

 

Best,

Fredrik

 

Message 11 of 11

JBerns
Advisor
Advisor

@fredform, 

 

The code I created earlier was intended to test whether all of our custom Content Center parts could be placed from an iLogic rule without crashes or freezes.
That is not necessarily the workflow you would want for placing specific parts from a DLL.

 

I tested another approach in Inventor 2025 using the iLogic managed API from a VB.NET Inventor add-in.

The add-in does not need to explicitly traverse TreeViewTopNode, ChildNodes, Families, or ContentRows.

The key is to create an IStandardObjectProvider for the active document using StandardObjectFactory.Create(doc), then access provider.ThisAssembly.Components, which exposes IManagedComponents.AddContentCenterPart.

 

Imports Inventor
Imports Autodesk.iLogic.Interfaces

Private Function AddContentCenterPart(
    doc As Inventor.Document,
    occurrenceName As String,
    ccPath As String,
    familyName As String,
    searchCriteria As Object(),
    x As Double,
    y As Double,
    z As Double
) As Boolean

    If doc Is Nothing Then Return False

    If doc.DocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
        Return False
    End If

    Using provider As IStandardObjectProvider =
        StandardObjectFactory.Create(doc)

        Dim components As IManagedComponents =
            provider.ThisAssembly.Components

        ' Important for Content Center lookup.
        components.ContentCenterLanguage = "en-US"

        Dim position =
            provider.ThisAssembly.Geometry.Point(x, y, z)

        Dim ccPart = components.AddContentCenterPart(
            occurrenceName,
            ccPath,
            familyName,
            searchCriteria,
            position)

        Return ccPart IsNot Nothing

    End Using

End Function

 

Example call from an Inventor add-in:

Dim doc As Inventor.Document =
    g_inventorApplication.ActiveDocument

Dim result As Boolean = AddContentCenterPart(
    doc,
    "DLL_Nut_01",
    "Fasteners:Nuts:Hex",
    "NMC Hex Nut - Inch",
    New Object() {"StockNumber", "031-0345"},
    -16,
    0,
    0)

System.Diagnostics.Debug.WriteLine(
    "AddContentCenterPart result = " & result.ToString())

 

I verified this from a true Inventor add-in DLL, with no iLogic rule involved. I successfully placed members from multiple Content Center families using Stock Number lookup.

One detail that mattered in my testing was explicitly setting:

components.ContentCenterLanguage = "en-US"

 

The searchCriteria argument can be any valid Content Center column/value pair, for example:

New Object() {"StockNumber", "031-0345"}

or a compound search such as:

New Object() {"SIZE", "1/2", "NLG", "2"}

 

I hope this is helpful. Let us know.

 

Regards,

Jerry

 

* Code created with assistance of ChatGPT

-----------------------------------------------------------------------------------------
CAD Administrator
Using AutoCAD & Inventor 2025
Autodesk Certified Instructor
Autodesk Inventor Certified Professional
Autodesk AutoCAD Certified Professional
0 Likes