iLogic - Resolve missing files in assembly

iLogic - Resolve missing files in assembly

klaas.haesen
Explorer Explorer
1,324 Views
8 Replies
Message 1 of 9

iLogic - Resolve missing files in assembly

klaas.haesen
Explorer
Explorer

Hi

 

I recently started working for a new company.

Recently they migrated from Vault Basic to Vault Pro.

 

There are some large assemblies where all the parts have been renamed, to get unique file names in the Vault. The files have been renamed using prefixes and/or suffixes.

The main assemblies were not update before the migration. So we get a lot of unresolved file errors.

 

I am working on an iLogic rule that finds all unresolved files and searches in the original folder location for a file that contains the same name.

This is working great for part files. But when I come across an assembly file, the rule throws an error:

 

Error message:

Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL))

 

More Info:

System.Runtime.InteropServices.COMException (0x80004005): Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL))
at Microsoft.VisualBasic.CompilerServices.LateBinding.InternalLateCall(Object o, Type objType, String name, Object[] args, String[] paramnames, Boolean[] CopyBack, Boolean IgnoreReturn)
at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateCall(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack, Boolean IgnoreReturn)
at ThisRule.Main() in external rule: VaultFindUnresolved:line 59
at Autodesk.iLogic.Exec.AppDomExec.ExecRuleInAssembly(Assembly assem)
at iLogic.RuleEvalContainer.ExecRuleEval(String execRule)

 

The line in the code that is causing problems is line 54:

Call oCollection.Item(i).Replace(oPossibleFiles.Item(1).FullName, False)

 

Full code below:

Sub Main
	
    Dim oFile As Inventor.File
    oFile = ThisApplication.ActiveDocument.File
    
    Dim oDoc As AssemblyDocument
    oDoc = ThisApplication.ActiveDocument

    Dim oDocDef As AssemblyComponentDefinition
    oDocDef = oDoc.ComponentDefinition
    
	Dim oCollection As ObjectCollection 'Collection of unresolved files in assembly
	oCollection = ThisApplication.TransientObjects.CreateObjectCollection
	
    Call FindUnresolved(oFile, oDoc, oDocDef, oCollection)
	
	Dim oPossibleFiles As Collection
	
	Dim resultTxt As String
	resultTxt = "Resultaat:" & vbCrLf
	
	Dim i As Integer
		
	For i = 1 To oCollection.Count
		Dim oMissingRefFile = oCollection.Item(i)
				
		Call ListAllFilesInFolder(oMissingRefFile, oPossibleFiles)
		
		If oPossibleFiles.Count > 1 Then ' more than 1 file found
			Dim nameLenght As Integer
			nameLength = 100000
			Dim counter As Integer
			
			For Each oRef As System.IO.FileInfo In oPossibleFiles
				If oRef.FullName.Length < nameLength
					nameLength = oRef.FullName.Length
				End If
			Next
			
			'return the part with the shortest name
			For Each oRef As System.IO.FileInfo In oPossibleFiles
				If oRef.FullName.Length = nameLength
						Try
							Call oCollection.Item(i).Replace(oRef.FullName, False)
							resultTxt = resultTxt & vbCrLf & "Vervangen: " & oCollection.Item(i).Name & " with: " & oRef.Name
						Catch
							resultTxt = resultTxt & vbCrLf & "Fout bij vervangen: " & oCollection.Item(i).ReferencedDocumentDescriptor.ReferencedFileDescriptor.FullFileName
						End Try
				End If
			Next
			
		Else If oPossibleFiles.Count = 1 Then ' only one file
'			Try
				Call oCollection.Item(i).Replace(oPossibleFiles.Item(1).FullName, False)
				resultTxt = resultTxt & vbCrLf & "Vervangen: " & oCollection.Item(i).ReferencedDocumentDescriptor.ReferencedFileDescriptor.FullFileName & " with: " & oPossibleFiles.Item(1).Name
'			Catch
'				resultTxt = resultTxt & vbCrLf & "Fout bij vervangen: " & oCollection.Item(i).ReferencedDocumentDescriptor.ReferencedFileDescriptor.FullFileName
'			End Try
			
		Else ' no files were found
			resultTxt = resultTxt & vbCrLf & " Niet gevonden : " & oCollection.Item(i).ReferencedDocumentDescriptor.ReferencedFileDescriptor.FullFileName
		End If
	Next i
	
	ExportText(resultTxt)

End Sub

Sub FindUnresolved(ByVal oFile As Inventor.File, oDoc As AssemblyDocument, oDocDef As ComponentDefinition, ByRef collection As ObjectCollection)
	
    Dim oFileDescriptor As FileDescriptor
    For Each oFileDescriptor In oFile.ReferencedFileDescriptors
        If Not oFileDescriptor.ReferenceMissing Then 'If file is not missing
            If Not oFileDescriptor.ReferencedFileType = FileTypeEnum.kForeignFileType Then 'If it is an Inventor file, search for missing files in its children
                Call FindUnresolved(oFileDescriptor.ReferencedFile, oDoc, oDocDef,collection)
            End If
        Else 'If file is missing
	        Dim oOccurrence As ComponentOccurrence
	        For Each oOccurrence In oDocDef.Occurrences
		        If oOccurrence.ReferencedDocumentDescriptor.ReferencedFileDescriptor.FullFileName _
					 = oFileDescriptor.FullFileName Then
		       		collection.Add(oOccurrence)
		        End If
			Next oOccurrence
			For Each oOccurrence In oDocDef.Occurrences.AllLeafOccurrences
		        If oOccurrence.ReferencedDocumentDescriptor.ReferencedFileDescriptor.FullFileName _
					 = oFileDescriptor.FullFileName Then
		       		collection.Add(oOccurrence)
		        End If
	        Next oOccurrence
			
        End If                   
    Next
	
End Sub

Sub ListAllFilesInFolder(ByRef oRefFile As Object, ByRef fPossibleFiles As Collection)
		
	Dim oPath As String
	oPath = oRefFile.ReferencedDocumentDescriptor.ReferencedFileDescriptor.FullFileName
	oPath = Left(oPath, InStrRev(oPath, "\") -1)
	oPath = oPath.Replace("LocalWorkspace", "Workspace\Vault\Documents")
	
	Dim partOfName As String = oRefFile.ReferencedDocumentDescriptor.ReferencedFileDescriptor.FullFileName
	partOfName = Right(partOfName, partOfName.Length - InStrRev(partOfName, "\"))
	partOfName = Left(partOfName, InStrRev(partOfName, ".") - 1)
	
	Dim fileExtension As String
	fileExtension = Right(oRefFile.ReferencedDocumentDescriptor.ReferencedFileDescriptor.FullFileName, 3)
	
	fPossibleFiles = New Collection
	
	Dim FileLocation As System.IO.DirectoryInfo = New System.IO.DirectoryInfo(oPath)
	
	Dim fi As System.IO.FileInfo()
	Try
		fi = FileLocation.GetFiles("*" & partOfName & "*" & fileExtension)
	Catch		
		Exit Sub
	End Try
	
	Dim oMsg As String = "Files containing " & partOfName & ":"
	
	For Each oFile As System.IO.FileInfo In fi
		oMsg = oMsg & vbCrLf & oFile.FullName
		fPossibleFiles.Add(oFile)
	Next
	
End Sub

Sub ExportText (txt As String)
	Dim oPath As String = "D:\temp\"
	Dim oFile As String = oPath & "ReplaceUnresolved.txt"
	Dim oContents As String
	If Not System.IO.File.Exists(oFile) Then
		MsgBox("The specified text file:" & vbCrLf & _
		oFile & vbCrLf & _
		"was not found.  Exiting.", vbOKOnly, " ")
		Exit Sub
	Else
		'get all text in the text file to a String variable
		oContents = System.IO.File.ReadAllText(oFile)
		'clear all text in the text file (overwrites all text with empty string)
		System.IO.File.WriteAllText(oFile, "")
		'delete the text file
		System.IO.File.Delete(oFile)
	End If
	'now create a new text file
	Dim oWriter As New System.IO.StreamWriter(oPath & "ReplaceUnresolved.txt")
	'write contents from old text file into the new one
	oWriter.Write(txt)
	'write more text below that
	oWriter.Flush 'clears buffers & makes sure it's written to the text file
	oWriter.Close 'closes the text file
	oWriter.Dispose 'releases resources/references to the writer & file
End Sub

 

0 Likes
Accepted solutions (1)
1,325 Views
8 Replies
Replies (8)
Message 2 of 9

Michael.Navara
Advisor
Advisor

Perhaps it is off-topic, but you can try different approach. instead of replacing references on active document, try to handle FileAccessEvents.OnFileResolution Event. It is better to solve this task in add-in instead of iLogic, but it may solve your issue.

This event is fired when Inventor looks for file on local disk. If you can construct new file name from the old one, you can pass this new file name to the opening process instead of the old one.

0 Likes
Message 3 of 9

klaas.haesen
Explorer
Explorer

Michael

 

Thanks for the reply. It is an interesting idea.

 

I am not sure if I know how to catch the event with an add-in, but I will look into that.

0 Likes
Message 4 of 9

JMGunnar
Collaborator
Collaborator

Error ""

Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL))

 

if there is resolve link in the subassembly 

you can not replace 

 

Call oCollection.Item(i).Replace(oPossibleFiles.Item(1).FullName, False)

 

 

 

johangunnar_0-1667996387285.png

 

0 Likes
Message 5 of 9

Michael.Navara
Advisor
Advisor
Accepted solution

This is a minimalistic sample, how to handle this event using iLogic and its SharedVariable. It may helps you to understand, how it may works.

This sample just display the most important arguments.

Implementation in add-in is better, because you have a control of the event handler lifetime and you don't need to rely the SharedVariable functionality.

 

 

 

 

Sub Main
	Dim sharedVariableName = "OnFileResolutionEventHandler"

	'Stop existing handler
	If SharedVariable.Exists(sharedVariableName) Then
		SharedVariable(sharedVariableName).StopHandling()
	End If

	If MsgBox("Start 'OnFileResolutionEventHandler'?", MsgBoxStyle.Question + MsgBoxStyle.YesNo) = MsgBoxResult.No Then Return
	Dim eventHandler = New OnFileResolutionEventHandler(ThisApplication)
	SharedVariable(sharedVariableName) = eventHandler
	eventHandler.StartHandling()
End Sub

Class OnFileResolutionEventHandler
	'Inherits MyEventHandlerBase

	Private ThisApplication As Application
	Private _fileAccessEvents As FileAccessEvents
	Private _running As Boolean

	Public Sub New(Inventor As Application)
		Me.ThisApplication = inventor
	End Sub

	Private Sub FileAccessEvents_OnFileResolution(
		relativeFileName As String,
		libraryName As String,
		ByRef customLogicalName As Byte(),
		beforeOrAfter As EventTimingEnum,
		context As NameValueMap,
		ByRef fullFileName As String,
		ByRef handlingCode As HandlingCodeEnum)

		Dim msg As String = ""
		msg += "relativeFileName: " & relativeFileName & vbCrLf
		msg += "libraryName: " & libraryName & vbCrLf
		msg += vbCrLf & "Cntinue?"

		If MsgBox(msg, MsgBoxStyle.YesNo) = MsgBoxResult.No Then
			StopHandling()
		End If

	End Sub

	Public Sub StartHandling()
		If _running Then Return
		_fileAccessEvents = ThisApplication.FileAccessEvents
		AddHandler _fileAccessEvents.OnFileResolution, AddressOf FileAccessEvents_OnFileResolution
		_running = True
	End Sub

	Public Sub StopHandling()
		If Not _running Then Return
		RemoveHandler _fileAccessEvents.OnFileResolution, AddressOf FileAccessEvents_OnFileResolution
		_fileAccessEvents = Nothing
		_running = False
	End Sub
End Class

 

 

 

 

 

0 Likes
Message 6 of 9

Michael.Navara
Advisor
Advisor
I add small improvement to the code snippet
0 Likes
Message 7 of 9

klaas.haesen
Explorer
Explorer

Johan, thanks for clarifying what is causing the error.

 

So the error occurs because the subassemly has unresolved links.

The solution to try to replace the subassembly when the main assembly is open is not possible.

 

The only way forward is the FileAccessEvents.OnFileResolution event.

Because here we do not need to replace ...

 

0 Likes
Message 8 of 9

klaas.haesen
Explorer
Explorer

Thanks for the sample.

 

I will try to wrap my head around what is happening in the code.

It looks like it is a step in the right direction.

0 Likes
Message 9 of 9

klaas.haesen
Explorer
Explorer

@Michael.Navara

With the sample you provide I managed to get all the unresolved sub-assemblies to load.

Thanks again!

I will look into how creating add-ins. But for now your solution works like a charm.

0 Likes