The code is object-oriented, so I'd be posting parts of several classes, or else 70 pages of code.
I have been able to refine my understanding of what's happening some. First off, I had to use Save2(False) and then Close(True). Anything else crashed.
Second, I could NOT save the form the rule was in. That also crashed. The crashes occurred not when the saves were being run, but when the rule finished. They were an "unhandled exception" error, but because of where they occurred I couldn't catch them in a try block.
Finally, my class destructor (in the one class I have one) is not running reliably. I tried putting the Close in the destructor, because the class records whether the file was already open or it had to open it, so the destructor can be set up to only close it if it wasn't open before. Also my class is instance counted so it can close the file only when the last instance is destroyed. And of course, using the destructor means the part closes automatically when the object goes out of scope. But I never know if the destructor is going to fire or not.
So, basically, Inventor is full of bugs and it's taken me a day to figure out workarounds for these four. The one I'm still not satisfied with is the destructor.
The beginning portion of my Part class:
SyntaxEditor Code Snippet
'===============================================================================
' Part
'
' Base class, in the OOP sense, for all Inventor parts. That is, it is
' intended to supply low-level control of Inventor parts to other classes.
' Those Inventor parts can be "derived" parts, "base" parts, or neither. This
' class is where Inventor API access happens. Each specific Inventor part
' class object contains an instance of the Part class which it uses to do the
' "real" work.
'===============================================================================
Public Class Part
'---------------------------------------------------------------------------
Private Shared InstanceCount_ As New Dictionary(Of String, Integer)
Private Shared WasFileOpen_ As New Dictionary(Of String, Boolean)
'---------------------------------------------------------------------------
Private App_ As Application
Private Dim DisplayName_ As String
Private Doc_ As PartDocument
'---------------------------------------------------------------------------
' Constructor
'
' Loads document into memory if necessary, and saves a reference to it.
' Increments instance count, and, for first instance, stores whether the
' file was in memory already.
'---------------------------------------------------------------------------
Public Sub New(ByRef App As Application, ByRef DisplayName As String)
App_ = App
DisplayName_ = DisplayName
' Add to instance count
Dim n As Integer
With InstanceCount_
.TryGetValue(DisplayName_, n)
.Item(DisplayName_) = n + 1
End With
' Get reference to part document if it's in memory already
For Each d As Document In App_.Documents
If d.DisplayName() = DisplayName_ Then
Doc_ = d
If n = 0 Then
WasFileOpen_.Item(DisplayName_) = True
End If
Exit Sub
End If
Next
' Document was not in memory. Load it.
If n = 0 Then WasFileOpen_.Item(DisplayName_) = False
Doc_ = OpenDoc()
End Sub ' New
'---------------------------------------------------------------------------
' Destructor
'
' Decrements the instance count and, for last instance, saves the file,
' then closes it if it had to be opened on construction of first instance.
'---------------------------------------------------------------------------
Protected Overrides Sub Finalize()
' Reduce instance count
Dim n As Integer
With InstanceCount_
.TryGetValue(DisplayName_, n)
If n > 0 Then .Item(DisplayName_) = n - 1
End With
If n > 1 Then Exit Sub
If Doc_ Is Nothing Then Exit Sub
' Save document if possible
' Save()
' Close document if it had to be opened and this is the last instance
Dim WasFileOpen As Boolean
WasFileOpen_.TryGetValue(DisplayName_, WasFileOpen)
If Not WasFileOpen Then Close()
End Sub ' Finalize
'---------------------------------------------------------------------------
' OpenFile
'
' Attempts to open the part file, suppressing errors.
' Returns Document reference, or Nothing for failure.
'---------------------------------------------------------------------------
Private Function OpenFile(ByRef dirSpec As String) As Document
Dim filespec As String = dirSpec & "\" & DisplayName_ & ".ipt"
App_.SilentOperation = True
Try
OpenFile = App_.Documents.Open(filespec)
Catch ex As Exception
OpenFile = Nothing
End Try
App_.SilentOperation = False
End Function ' OpenFile
'---------------------------------------------------------------------------
' OpenDoc
'
' Finds and opens the document file.
' Returns Document reference, or Nothing for failure.
'---------------------------------------------------------------------------
Private Function OpenDoc() As Document
' Get Workspace path
Dim dpm As DesignProjectManager
Dim dp As DesignProject
dpm = App_.DesignProjectManager
dp = dpm.ActiveDesignProject
' Try to open document there
Dim doc As Document = OpenFile(dp.WorkspacePath)
If Not doc Is Nothing Then
OpenDoc = doc
Exit Function
End If
' Try to open file in each, testing for not found error
For Each p As ProjectPath In dp.WorkgroupPaths
doc = OpenFile(p.Path())
If Not doc Is Nothing Then
OpenDoc = doc
Exit Function
End If
Next
OpenDoc = Nothing
End Function ' OpenDoc
'---------------------------------------------------------------------------
' Save
'
' Saves the file to disk.
'---------------------------------------------------------------------------
Public Sub Save()
Doc_.Save2(False)
End Sub ' Save
'---------------------------------------------------------------------------
Public Sub Close()
Doc_.Close(True)
End Sub