Work Around To Get Assemblies In Content Center Using "Flags" and Replace With iLogic

Work Around To Get Assemblies In Content Center Using "Flags" and Replace With iLogic

Aubrey_Campbell
Advocate Advocate
5,364 Views
68 Replies
Message 1 of 69

Work Around To Get Assemblies In Content Center Using "Flags" and Replace With iLogic

Aubrey_Campbell
Advocate
Advocate

Hello, 

 

I am new to writing code in iLogic (in fact this is my first attempt).  As such I apologize in advance for my complete ignorance on the subject. 

 

I have searched the forum and found similar topics on the bits and pieces I need.  Unfortunately, I don't understand the syntax well enough to modify them to suite my needs, hence this post asking for help. 

 

The goal is to create an external rule that will look at all .ipt files in an assembly (don't look at .iam files) and read a custom property ("CC Assy?" is the custom property.  This custom property will serve as my "Flag".).  This property will either be set to "yes" or "no" within the .ipt file iProperties.  

 

Acampbell95BZ4_0-1638394030138.png

 

If the rule reads an .ipt file with "CC Assy?" set to "no", do nothing.  If the rule reads an .ipt file with "CC Assy?" set to "yes", then I need the code to read the "Part Name" from the iProperties

 

Acampbell95BZ4_1-1638394117442.png

 

Now that we have a part number (probably stored as a variable) the code needs to do a Replace component on that .ipt.  The code needs to look in all these (below) folders (they are all sub folders of a single directory) and find the .iam with file name = Part Name read earlier in the code.  Preferably, only look in these folders one level deep (don't look in subfolders of the folders shown below).  

 

Acampbell95BZ4_2-1638394427257.png

 

Once the .iam file is found, do a Replace component and replace the .ipt with the .iam found in one of the folders above. 

 

 

I'm sure you can tell what I'm trying to do at this point (based on the title of the post).  The purpose is to allow me to put commonly used assemblies in the content center so they can be quickly and easily accessed.  Because CC does not allow .iam files, I will simply place a representative .ipt file in the CC and manually trigger the iLogic code I'm trying to write to automatically replace the representative .ipt file with the correct .iam

 

The code will need perform the replace on all instances of the representative .ipt file placed from the CC.  

 

Thank you in advance for any help anyone is able to offer! 

 

 

Accepted solutions (1)
5,365 Views
68 Replies
Replies (68)
Message 61 of 69

Aubrey_Campbell
Advocate
Advocate

Perfect, I will give it a shot.  I like your idea a lot more than what I did: 

 

 

Actually, In anticipation that your response would be "Yes, that is accurate" and you had confirmed it will probably take quite a bit more work to get the code to build the exact directory it will need to look in to find the assembly, I went ahead and pursued another direction for getting this done. 

 

When I publish the representative part to the CC, I will first fill out iProperties and I will also know the exact folder the corresponding assembly will be in.  So, I simply created another custom iProperty called "Assy Folder" and pulled that value the same way we used the "PullNum" function and built my directory that way.  

 

The code is now performing component replaces on flagged parts!! 

 

However, I like the idea of not having to fill out that iProperty and making the code do a broader search for the appropriate assembly.  I feel this would make the code more robust.  Also, if we ever change the way we store our files, I will only have to change the top level directory in the code.  

 

With my method of building the exact directory, I would have to change the "Assy Folder" field in the  iProperties for every CC assembly as well as the directory in the code.  ... Also, it might get a little hinky trying to change iProperties on parts that have already been published to the CC.

 

Here is the code that is working (replacing parts) by building the directory from the new iProperties field "Assy Folder"

 

 

'[ 
Sub Main()

 Dim oAsmDoc As AssemblyDocument
 oAsmDoc = ThisApplication.ActiveDocument
	
'Iterate through all of the occurrences
Dim oOcc As ComponentOccurrence
For Each oOcc In oAsmDoc.ComponentDefinition.Occurrences
	 
	 Dim oOccDoc As Document
	 oOccDoc = oOcc.Definition.Document
	' Verify that the document is a part.
    If oOccDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then    
        Dim oPartDoc As PartDocument = oOccDoc
		
		Dim check As String
		Dim AssyNum As String
		Dim FileLoc As String
               
                'Call the function to check for the flag
		check = CC_AssyCheck(oPartDoc)
		
		If check = "Yes" Then
			
			'PUll the Part Name field 
			AssyNum = PullNum(oPartDoc)
			FoldL = PullFolder(oPartDoc)
			
			Logger.Info("AssyN Main Sub: " & AssyNum)
			Logger.Info("//////Fodler Name: " & FoldL)
			
		
			FileLoc = FindAssyFile(AssyNum, FoldL, oPartDoc)
				Logger.Info("AssyN Main Sub: " & AssyNum)
			'Do something with the occurrence
			'oOcc.Replace("Enter New File Name Here",True)
		End If
		
    End If

Next


End Sub
']

' This function looks for the flag to see if "CC Assy?" is set to yes or no. "CC Assy?" is a custom iProperty. 
Function CC_AssyCheck(oPartDoc) As String

	Try
	' Get the User Defined property set.
	Dim UserDefinedPropSet As PropertySet
	UserDefinedPropSet = oPartDoc.PropertySets.Item("Inventor User Defined Properties")

	' Get the Size property.
	Dim AssyCheck As Inventor.Property
	AssyCheck = UserDefinedPropSet.Item("CC_Assy?")
	Dim Ans As String
	Ans = AssyCheck.Value
	
	If Ans = "Yes" Then
		Logger.Info("Yes: " & oPartDoc.DisplayName)
		
		Return Ans
		 
	ElseIf Ans = "No" Then
		  Logger.Info("No: " & oPartDoc.DisplayName)
	End If
	 
	Catch
	End Try
		
End Function


' This function pulls the part number for the assembly from the "Part Name" field (Title field from Iventor iProp)
Function PullNum(oPartDoc) As String
	Try
    ' Get the active document.
'    Dim oDoc As Document
'        oDoc = ThisApplication.ActiveDocument
	'Dim AssyN As String
	Dim AssyN As String
    ' Get the PropertySets object.
    Dim oPropSets As PropertySets
        oPropSets = oPartDoc.PropertySets

    ' Get the design tracking property set.
    Dim oPropSet As PropertySet
        oPropSet = oPropSets.Item("Inventor Summary Information")

    ' Get the part number iProperty.
    Dim oPartNumiProp As Inventor.Property
        oPartNumiProp = oPropSet.Item("Title")

Logger.Info("Part Number: " & oPartNumiProp.Value)

		AssyN = oPartNumiProp.Value
		
		Logger.Info("----AssyN in Function is: " & AssyN)

Return AssyN
       	
	Catch
	End Try
		
End Function 


'This function pulls the folder name the assembly is located in which is a user input in the iProperties. 
Function PullFolder(oPartDoc) As String
	
	Try
		Dim UserDefinedPropSet2 As PropertySet
		UserDefinedPropSet2 = oPartDoc.PropertySets.Item("Inventor User Defined Properties")
	
	
		Dim FolderN As Inventor.Property
		FolderN = UserDefinedPropSet2.Item("Assy Folder")
		Dim FolderLoc As String
		FolderLoc = FolderN.Value
	 

		Logger.Info("----Folder Name in Function is: " & FolderLoc)

				
		Return FolderLoc
		Catch
	End	Try
			
End Function


'[\
Function FindAssyFile(AssyNum, FolderL, oPartDoc)
	Dim SearchLocation As String = "R:\__RND CUSTOM & PACKAGING\Purchased\" & FolderL & "\"

	Dim FN As String 
	
    	FN = AssyNum & ".iam"
		'Logger.Info("AssyN Value is: " & AssyN)
		Logger.Info("FN Value is: " & FN)
		Logger.Info("Search Directory is: " & SearchLocation)

Logger.Info("----+++++Folder Name in Function is: " & FolderL)

	Try
    	Dim dirs As String ()
    	dirs = System.IO.Directory.GetFiles(SearchLocation, FN)
   		Dim fullPath As String
    	fullPath = dirs.GetValue(0)
	Catch
    	MessageBox.Show("The File " & FN & " cannot be found in Purchased Folder" _
    	& vbNewLine & "" _
    	& vbLf & "Please make sure an assembly file exsists in the Purchased Folder" _
    	& vbNewLine & "" _
    	& vbCrLf & "Assembly file not found", "Cannot Find Assembly",MessageBoxButtons.OK,MessageBoxIcon.Error)

	Return FileLoc

	End Try

Dim strRelativeFileLocation As String = SearchLocation & FN
	Component.Replace(oPartDoc.DisplayName & ":1", strRelativeFileLocation, True)
	'Component.Replace("Part1:1", "OtherPartfilename.ipt", True)

	Logger.Info("Complete path is: " & strRelativeFileLocation)
	
End Function 
	
	']

 

 

I still need to clean it up quite a bit too.  

 

I will now try to implement your method of searching for the assembly. 

 

Thanks again!! 

 

 

 

 

0 Likes
Message 62 of 69

Aubrey_Campbell
Advocate
Advocate

Trying to implement your method of searching the folders.  from this line:

 

oFilenames = System.IO.Directory.GetFiles(SearchDirectory,"*.iam", SearchOption.AllDirectories )

I get an error saying SearchOption is not declared:

 

Acampbell95BZ4_0-1640034328764.png

 

 

Not sure what it should be.  

 

 

Update #1:

 

I think I found the problem.  I believe that line is supposed to be:

oFilenames = System.IO.Directory.GetFiles(SearchDirectory,"*.iam", IO.SearchOption.AllDirectories )

... It was missing the "IO." in front of "SearchOptions.AllDirectories"

 

however, Now I am getting an error on this line:

If oFilename.Contains (AssyFilename) Then 'this may need to change if multiple files are returned

saying Value cannot be null.

 

Acampbell95BZ4_0-1640035645271.png

 

Trying to figure this one out now. 

 

Update #2:

 

This line was not working because I had a different variable name for "AssyFilename"

If oFilename.Contains (AssyNum) Then 'this may need to change if multiple files are returned

With this correction, at a glance, it seems to be working. 

 

 

 

 

0 Likes
Message 63 of 69

Aubrey_Campbell
Advocate
Advocate

a

0 Likes
Message 64 of 69

Aubrey_Campbell
Advocate
Advocate

So, I've been playing around with both versions of the code (the version that looks in all sub folders using 

IO.SearchOption.AllDirectories

 and the second version that uses a second flag for folder name in the iProperties).  Both versions work (although I haven't implemented the replace component part on the version the uses the IO.Search.... line, however, I can see that it is working properly and finding the files.  

 

There are some definite pros and cons to either approach.  for example:

 

For the version that uses IO.SearchOption..... 

Pros:  it can search all sub folders of a directory, so if anything moves, the most you would need to do is change the one line of code that tells the function what directory to look in.

Cons: it is slower in execution because it is looking in ALL those folders. 

 

For the version that uses a second flag for the specific folder name:

Pros: it executes a lot faster because it knows exactly what folder to look in

Cons: if any of your files need to move to another folder, you will have to change the one line of code in the rule that tells the function what directory to look in.  Also, you would have to change the folder name on the flag for each part in the CC that uses that flag.  This would mean republishing each part to the CC. 

 

Both versions are pretty handy.  For my application, I think I will stick with the version that uses the additional flag due to the increased speed of execution and the extreme unlikelihood that we will change the way we store our files.  However, if we ever do change the way we store our files, I will switch to the other version as it will be easier to implement rather than make all the necessary changes to keep the additional flag version running.  

 

Currently, both versions look in this directory:

 

R:\__RND CUSTOM & PACKAGING\Purchased

 

However, it is possible that I may need them to also look in this directory:

 

R:\__RND CUSTOM & PACKAGING\Assembly

 

As you can see, both of these are a part of the R:\__RND CUSTOM & PACKAGING\ directory.

 

So, how do I implement an "OR" situation.  In other words, is there a way I can easily edit this function to get it to look in "Purchasing" folder first and then look in "Assembly" folder if nothing is found in Purchasing folder? 

Or, is it easier to just create a second function for the second directory I want to search?

 

I tried nested Try-Catch-EndTry statements (probably not implemented correctly, if this is possible).  

 

Here is how I tried to nest the Try-Catch-EndTry

 

 

 

 

 

Function FindAssyFile(AssyNum, FolderL, oPartDoc)
	Dim SearchLocation As String = "R:\__RND CUSTOM & PACKAGING\Purchased\" & FolderL & "\"
	Dim SearchLocation2 As String = "R:\__RND CUSTOM & PACKAGING\Assembly" & FolderL & "\"

	Dim FN As String 
	
    	FN = AssyNum & ".iam"
		'Logger.Info("AssyN Value is: " & AssyN)
		Logger.Info("FN Value is: " & FN)
		Logger.Info("Search Directory is: " & SearchLocation)

Logger.Info("----+++++Folder Name in Function is: " & FolderL)

	Try
    	Dim dirs As String ()
    	dirs = System.IO.Directory.GetFiles(SearchLocation, FN) 
   		Dim fullPath As String
    	fullPath = dirs.GetValue(0)
		
		
'		Dim dirs2 As String ()
'    	dirs2 = System.IO.Directory.GetFiles(SearchLocation2, FN)
'   	Dim fullPath2 As String
'    	fullPath2 = dirs2.GetValue(0)
	Catch
    	
		Try
		
			Dim dirs2 As String()
    		dirs2 = System.IO.Directory.GetFiles(SearchLocation2, FN)
   			Dim fullPath2 As String
    		fullPath2 = dirs2.GetValue(0)
		
		Catch
			
		End Try
		
		Catch
		MessageBox.Show("The File " & FN & " cannot be found in Purchased Folder" _
    	& vbNewLine & "" _
    	& vbLf & "Please make sure an assembly file exsists in the Purchased Folder" _
    	& vbNewLine & "" _
    	& vbCrLf & "Assembly file not found", "Cannot Find Assembly",MessageBoxButtons.OK,MessageBoxIcon.Error)

	Return FileLoc

	End Try

Dim strRelativeFileLocation As String = SearchLocation & FN
	Component.Replace(oPartDoc.DisplayName & ":1", strRelativeFileLocation, True)
	'Component.Replace("Part1:1", "OtherPartfilename.ipt", True)

	Logger.Info("Complete path is: " & strRelativeFileLocation)
	
End Function 

 

 

 

 

 

Here is the original function that only looks in "Purchasing" folder

 

 

 

 

 

Function FindAssyFile(AssyNum, FolderL, oPartDoc)
	Dim SearchLocation As String = "R:\__RND CUSTOM & PACKAGING\Purchased\" & FolderL & "\"

	Dim FN As String 
	
    	FN = AssyNum & ".iam"
		'Logger.Info("AssyN Value is: " & AssyN)
		Logger.Info("FN Value is: " & FN)
		Logger.Info("Search Directory is: " & SearchLocation)

Logger.Info("----+++++Folder Name in Function is: " & FolderL)

	Try
    	Dim dirs As String ()
    	dirs = System.IO.Directory.GetFiles(SearchLocation, FN)
   		Dim fullPath As String
    	fullPath = dirs.GetValue(0)
	Catch
    	MessageBox.Show("The File " & FN & " cannot be found in Purchased Folder" _
    	& vbNewLine & "" _
    	& vbLf & "Please make sure an assembly file exsists in the Purchased Folder" _
    	& vbNewLine & "" _
    	& vbCrLf & "Assembly file not found", "Cannot Find Assembly",MessageBoxButtons.OK,MessageBoxIcon.Error)

	Return FileLoc

	End Try

Dim strRelativeFileLocation As String = SearchLocation & FN
	Component.Replace(oPartDoc.DisplayName & ":1", strRelativeFileLocation, True)
	'Component.Replace("Part1:1", "OtherPartfilename.ipt", True)

	Logger.Info("Complete path is: " & strRelativeFileLocation)
	
End Function 
	

 

 

 

 

 

 

0 Likes
Message 65 of 69

A.Acheson
Mentor
Mentor

Maybe try and change the contains statements which might search the entire paths and if the folder numbers are similar might be trying to crunch all of those numbers too. 

If oFilename.Contains(AssyFilename) Then 'this may need to change if multiple files are returned
			

Change to only search the filename which includes the extension.

https://docs.microsoft.com/en-us/dotnet/api/system.io.path.getfilename?view=net-6.0

result = System.IO.Path.GetFileName(oFilename)
	If result = AssyFilename & ".iam" Then
End If

 

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
0 Likes
Message 66 of 69

Aubrey_Campbell
Advocate
Advocate

Is this this what you are suggesting to do?

 

Function FindAssy(SearchDirectory, AssyNum) As String
	
Dim oFilenames  As String()
Dim oFilename As String
Dim result As String
oFilenames = System.IO.Directory.GetFiles(SearchDirectory,"*.iam", IO.SearchOption.AllDirectories )

'Loop through all files found with above criteria"
		For Each oFilename In oFilenames 
	Logger.Info("Files In Folder  " & oFilename)
			
			result = System.IO.Path.GetFileName(oFilename)
			
			If result = AssyFilename & ".iam" Then 'this may need to change if multiple files are returned
			Logger.Info("~~~~Files In Folder : Yes  " & oFilename)
	
			Return oFilename
	
			End If
	
Next
End Function

 

I'm thinking not.  This version of the function seems to return a lot more file names than the previous version. 

0 Likes
Message 67 of 69

Aubrey_Campbell
Advocate
Advocate

This seems to be what is making the code take so long to run:

 

Acampbell95BZ4_0-1640199216421.png

 

The line

For Each oFilename In oFilenames 
	Logger.Info("Files In Folder  " & oFilename)

 

is putting out all .iam files in those directories.  I don't think they are being returned by the function, but the function is taking time to look at them all. 

0 Likes
Message 68 of 69

A.Acheson
Mentor
Mentor

That is correct. The for loop is looping through all .iam files. Checking the filename vs if the filename contains your supplied filename seems to take the same amount of time. All the time is actually going on finding every .iam file in the sub directories. 

 

So if your file is buried in the sub directory and you have alot of .iam files there then it will take some time. 

 

Maybe try also supplying the filename and extension in the search criteria instead of just the extension. Really is trial and error in terms of fastest return speed.

 

So if you can supply the full filename in advance stored in the cc part  and the file should be there method like your doing earlier it will be the quickest method. 

 

Alternatively you filter the sub directories and it might be able to narrower the focus to look in at least the correct number range folder first.

 

If you have time you might be able to find a similar vba/vb.net sample on stackoverflow.

 

 

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
0 Likes
Message 69 of 69

Aubrey_Campbell
Advocate
Advocate
Accepted solution

I have had to step away from this project for a little while to work on other projects.  However, I do plan to return to complete the version @A.Acheson suggests that does not require a second "flag" in the iProperties to help find the folder the actual assembly lives in. 

 

In the meantime, I will post the version I have that is working and explain how to implement it so others can use it, if they desire.  

 

The code is heavily commented for users like me that don't really know what they are doing (creating those comments helped me to understand what the code is doing).  Next there is a section with general notes.  After the general notes is a copy of the code (commented out) that has minimal comments for those that want a cleaner version to work with.  

 

Here is the code:

 

 

 

'[  Heavily commented version with Logger.Info() outputs for debugging. Logger.Info() calls are commented out.
Sub Main()

' Declaring variable "oAsmDoc" and setting its datatype to Assembly Document object.
 Dim oAsmDoc As AssemblyDocument
 ' Setting oAsmDoc equal to the currently opened document.  "This Application" represents Inventor, 
 '"Active Document" represents the document that is currently active in Inventor. 
 oAsmDoc = ThisApplication.ActiveDocument
	
'Iterate through all of the occurrences

' Declaring variable "oOcc" and setting its datatype to be an occurrence of a component. 
Dim oOcc As ComponentOccurrence

' "For Each" will look at all component occurrences ("oOcc") in the currently active assembly document ("oAsmDoc")
For Each oOcc In oAsmDoc.ComponentDefinition.Occurrences

' Declaring a variable "oOccDoc" and setting its datatype to be a document.
	 Dim oOccDoc As Document
' Setting the variable "oOccDoc" equal to the definition of the document so we can check if it is a part or not.	 
	 oOccDoc = oOcc.Definition.Document
' Verify that the document is a part and carry out the task if it is. 
    If oOccDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then   
' Declaring a variable "oPartDoc" and setting its datatype to be a Part Document, then setting the "oPartDoc" variable
' equal to the occurrence "oOccDoc"	
        Dim oPartDoc As PartDocument = oOccDoc
' Declaring variables "check", "AssyNum" and "FileLoc" that will be used to call functions and store their returned 
' values as strings. 		
		Dim check As String
		Dim AssyNum As String
		Dim FileLoc As String
               
'Call the function to check for the flag, passing to the function oPartDoc (the variable that represents a specifc 
' occurrence a part in the active assembly).
		check = CC_AssyCheck(oPartDoc)

' If the returned value from the function ("Ans" which was set eaual to "check" by the function call) is set to Yes 
' do the following ....
		If check = "Yes" Then
			
			'PUll the Part Name field from iProperties.
' Call the function that will pull the part number (which is the file name of the assembly to replace with) from the 
' iProperties.  Pass "oPartDoc" to this function as the work needs to be done on the document (digging through iProp).
			AssyNum = PullNum(oPartDoc)
			'Pull the folder name
' Call the function that will pull the folder name (a [custom] value in the iProperties) just like the PullNum() 
' function.  Pass "oPartDoc" to this function as the work needs to be done on the document (digging through iProp).
			FoldL = PullFolder(oPartDoc)
			
			Logger.Info("AssyN Main Sub: " & AssyNum)
			Logger.Info("//////Fodler Name: " & FoldL)
			'Find the desired assembly file to replace with.
' Call the function that will check a specific directory to try and find the desired assembly to replace with.
' Pass to this function "AssyNum" (the file name of the assembly to replace with found by PullNum() function),
' "FoldL" (the folder name pulled from the iProperties by the PullFolder() function), and "oPartDoc" (the 
' representative part file that will be replaced with the desired assembly.  The returned value from this function 
' is set equal to "FileLoc" which really doesn't matter becasue this variable is not used anywhere. 
			FileLoc = FindAssyFile1(AssyNum, FoldL, oPartDoc)
				Logger.Info("AssyN Main Sub: " & AssyNum)
		End If
' There is nothing for if "check" comes back as "No" or null becasue we don't want the code to do anything in that 
' case.  We only want the code to do something if the CC_AssyCheck() function returns a "Yes" value (check = "Yes")
    End If
' There is nothing for if oOccDoc comes back as a document type other than a part file becuase we only want to look
' at part files, ... skip everything else. 
Next

End Sub


' This function looks for the flag to see if "CC Assy?" is set to Yes or No. "CC Assy?" is a custom iProperty. 
' "Yes" and "No" must have first letter capitalized in iProperties for code to recognize the flag.
Function CC_AssyCheck(oPartDoc) As String  'Function output is defined to be a string.

	Try
	' Get the User Defined property set.
' Decalring variable "UserDefinedPropSet" to be a Property Set object.  
' This is the first step in drilling down to the desired level of the API Object Model which is needed to pull properties.
' Go to this link to see the Inventor API Object Model:
' https://damassets.autodesk.net/content/dam/autodesk/www/pdfs/Inventor2022ObjectModel.pdf
	Dim UserDefinedPropSet As PropertySet
' Setting the "UserDefinedPropSet" equal to the a custom property.  So, basically, looking at the part document (oPartDoc),
' and then the property sets "Inventor User Defined Properties".  "Inventor User Defined Properties" is where you go to 
' access custom iProperties.
	UserDefinedPropSet = oPartDoc.PropertySets.Item("Inventor User Defined Properties")

	' Get the custom property "CC Assy?" value.
' Now that we are at the custom property level, we tell the code to look at the specific custom property "CC Assy?"

' Declaring a new variable "AssyCheck" and setting it to be an Inventor property.
	Dim AssyCheck As Inventor.Property
' Setting "AssyCheck" equal to the value contained in the custom iProperty "CC Ass?".
' UserDefinedPropSet is already at the Custom (or Inventor User Defined Properties) level.  Now we need to tell it which
' custom property to look at.  
	AssyCheck = UserDefinedPropSet.Item("CC_Assy?")
' Now "AssyCheck" is looking at the custom property "CC Assy?"	

' Declare a new variable to hold the value stored under the custom iProperty "CC Assy?"
	Dim Ans As String
' Set the new variable ("Ans") equal to the value stored in iProperties uncer "CC Assy?"
	Ans = AssyCheck.Value
' Now "Ans" holds whatever was typed into the "CC Assy?" field in the iProperties of part.  This should be a "Yes" or "No".

' If value in "CC Assy?" is set to "Yes", then do the following ....
	If Ans = "Yes" Then
		Logger.Info("Yes: " & oPartDoc.DisplayName)
' Function returns "Yes"		
		Return Ans
		 
	ElseIf Ans = "No" Then
' If Value in "CC Assy?" is set to "No", do nothing. 
		  Logger.Info("No: " & oPartDoc.DisplayName)
	End If
	 
	Catch
' We only want the code to act if it finds a "Yes" in the "CC Assy?" field.  So, leave "Catch" blank so the code does
' nothing if if finds anything other than "Yes" in the "CC Assy?" field.
	End Try
		
End Function


' This function pulls the part number for the assembly from the "Part Name" field (this is the title field in
' Iventor iProperties).  
Function PullNum(oPartDoc) As String 'Function output is defined to be a string. 
	Try

' Declare a variable "AssyN" to be a string
	Dim AssyN As String
    ' Get the PropertySets object.

' Declare a variable "oPropSets" to be a PropertySets object.
' This is the first step in drilling down to the desired level of the API Object Model which is needed to pull properties.
' Go to this link to see the Inventor API Object Model:
' https://damassets.autodesk.net/content/dam/autodesk/www/pdfs/Inventor2022ObjectModel.pdf
    Dim oPropSets As PropertySets
' Setting "oPropSets" equal to a property set in the document (oPartDoc)
        oPropSets = oPartDoc.PropertySets

    ' Get the design tracking property set.
' Declare a new variable "oPropSet" and set it to be a Property Set object.
    Dim oPropSet As PropertySet
' Setting oPropSet equal to the Inventor Summary Information (drilling into the API to get to the iProp field we want.
        oPropSet = oPropSets.Item("Inventor Summary Information")

    ' Get the part number iProperty.
' Declaring a new variable "oPartNumiProp" and setting its datatype to be and Inventor property
    Dim oPartNumiProp As Inventor.Property
' The Inventor property "oPartNumiProp" will hold is the "Title" property from the iProperties
        oPartNumiProp = oPropSet.Item("Title")

Logger.Info("Part Number: " & oPartNumiProp.Value)
' Decalring a new variable "AssyN" and setting it equal to the valu stored in the title field of the iProperties.
' This is the value we want from the function
		AssyN = oPartNumiProp.Value
		
		Logger.Info("----AssyN in Function is: " & AssyN)

' Output an error message if there is no assembly number stored in the representative part file.  This means the part file
' did not have its iProperties properly filled out before it was published.  The part will need to be fixed (add in assembly
' part number un the "Title" field of iProperties ("Part Name" field in iPropWiz). 
' The error checking will look for null value.  
			If AssyN = ""
	MessageBox.Show(oPartDoc.DisplayName &" does not contain the part number of the desired assembly", 
	"No Assembly Number Found")
' Error checking:  If there is a space and no characters
			ElseIf AssyN = " " Then
	MessageBox.Show(oPartDoc.DisplayName &" does not contain the part number of the desired assembly", 
	"No Assembly Number Found")
' Error checking:  If there are 2 spaces and no characters
			ElseIf AssyN = "  " Then
	MessageBox.Show(oPartDoc.DisplayName &" does not contain the part number of the desired assembly", 
	"No Assembly Number Found")

			End If

' Return the desired value from the function.  In this case, the value stored in the Title field of the iProperties which 
' will be the part number for the assembly we want.
Return AssyN
       	
	Catch
' If the try fails, do nothing.  There is error checking in the Try statement 

	End Try
		
End Function 

'This function pulls the folder name the assembly is located in, which is a user input in the iProperties. 
' oPartDoc is passed to this function as the work needs to be done on this variable (i.e. we are looking at
' document properties). 
Function PullFolder(oPartDoc) As String
	
	Try
' The next 8 lines (including blank lines) are drilling down the API to get to the Custom iProperty "Assy Folder"
' the same as the CC_AssyCheck() function and PullNum() function above. 
		Dim UserDefinedPropSet2 As PropertySet
		UserDefinedPropSet2 = oPartDoc.PropertySets.Item("Inventor User Defined Properties")
	
		Dim FolderN As Inventor.Property
		FolderN = UserDefinedPropSet2.Item("Assy Folder")
		Dim FolderLoc As String
		FolderLoc = FolderN.Value
	 
		Logger.Info("----Folder Name in Function is: " & FolderLoc)
' Error checking the same as the PullNum() function. 
			If FolderLoc = "" Then
	MessageBox.Show(oPartDoc.DisplayName &" does not contain the folder name the desired assembly resides in", 
	"No Folder Name Found")
			
			ElseIf FolderLoc = " " Then
	MessageBox.Show(oPartDoc.DisplayName &" does not contain the folder name the desired assembly resides in", 
	"No Folder Name Found")
	
			ElseIf FolderLoc = "  " Then
	MessageBox.Show(oPartDoc.DisplayName &" does not contain the folder name the desired assembly resides in", 
	"No Folder Name Found")

			End If
' Return the value that was pulled from the custom iProperty "Assy Folder".
		Return FolderLoc
		Catch
' If the Try fails, do nothing.  There is error checking the Try statement. 
	End	Try
			
End Function

' This function will perform a search in the specified directory to try and located the assembly file.
' Once the search finds the assembly file the replace command will be executed. 
' Pass to this function the variable "AssyNum" (the file name (or part number for the assembly) we want to find),
' the variable "FolderL" (the folder name in which the assembly file resides. We will need this to build the search directory)
' and the variable "oPartDoc" (the part document we want to replace.  Needed for the replace command).
Function FindAssyFile1(AssyNum, FolderL, oPartDoc)
' Declare a variable "SearchLocation" to be equal to the directory (one folder above the folder name stored in the 
' custom iProperty "Assy Folder".  The directory has to be built using the variable "FolderL"
	Dim SearchLocation As String = "R:\__RND CUSTOM & PACKAGING\Purchased\" & FolderL & "\"
' Declare a new variable "FN" and set its datatype to be a string	
	Dim FN As String 
' Build the full assembly file name with extension.	
    	FN = AssyNum & ".iam"
		Logger.Info("FN Value is: " & FN)
		Logger.Info("Search Directory is: " & SearchLocation)
		Logger.Info("----+++++Folder Name in Function is: " & FolderL)
	Try
' Declare a new variable "dirs" and set its datatype to be an array of strings. 
    	Dim dirs As String()
' Find and populate the "dirs" array with all the matching criteria.  If none are found, the Try fails and moves to the Catch
    	dirs = System.IO.Directory.GetFiles(SearchLocation, FN) 
' Declare a new variable "fullPath" and set its datatype to be a string.
   		Dim fullPath As String
' Set "fullPath" equal to the first string in the array of strings stored in "dirs".  This will be the 
		fullPath = dirs.GetValue(0)
		Logger.Info("~~~~~~ Bottom ~~~~~~ FullPath Value is: " & fullPath)
		
	Catch
	
    	FileLoc2 = FindAssyFile2(AssyNum, FolderL, oPartDoc)	

	Return FileLoc

	End Try

Dim strRelativeFileLocation As String = SearchLocation & FN

	Component.Replace(oPartDoc.DisplayName & ":1", strRelativeFileLocation, True)
	
	Logger.Info("Complete path is: " & strRelativeFileLocation)
	
End Function 

Function FindAssyFile2(AssyNum, FolderL, oPartDoc)
	
	Dim SearchLocation2 As String = "R:\__RND CUSTOM & PACKAGING\Assembly\" & FolderL & "\"

	Dim FN As String 
	
    	FN = AssyNum & ".iam"
		Logger.Info("2nd Fnctn FN Value is: " & FN)
		Logger.Info("2nd Fnctn Search Directory is: " & SearchLocation2)

Logger.Info("----2nd Fnctn+++++Folder Name in Function is: " & FolderL)

	Try
		
		Dim dirs2 As String ()
    	dirs2 = System.IO.Directory.GetFiles(SearchLocation2, FN)
   		Dim fullPath2 As String
    	fullPath2 = dirs2.GetValue(0)
	Catch
 ' This is a more complicated error message box.  The Catch puts this message box out if the try fails.  If the Try fails
 ' that means the assembly file could not be found. 
		MessageBox.Show("The File " & FN & " cannot be found in Purchased Folder Or Assembly Folder" _
    	& vbNewLine & "" _
    	& vbLf & "Please make sure an assembly file exsists in the Purchased or Assembly Folder" _
    	& vbNewLine & "" _
    	& vbCrLf & "Assembly file not found", "Cannot Find Assembly in Folders",MessageBoxButtons.OK,MessageBoxIcon.Error)

	Return FileLoc2

	End Try

Dim strRelativeFileLocation2 As String = SearchLocation2 & FN

	Component.Replace(oPartDoc.DisplayName & ":1", strRelativeFileLocation2, True)
	
	Logger.Info("Complete path is: " & strRelativeFileLocation2)
	
End Function   
']

'[ General Notes:
' The flag in the iProperties ("CC Assy?") must be a string value and connot be boolean (Yes/No) because the API 
' will try to write to the iProperties when it reads the boolean values for some reason.  A CC part placed as standard
' cannot be written to as it will be a read-only file.  Due to the naute of the read-only state of standard CC files, 
' Boolean cannot be used for this application. 

' Logger.Info() is for debugging purposes only and outputs data to the "iLogic Log" bowser tree in Inventor. 

' If additional directories need to be searched, simplay add another FindAssyFile#(AssyNum, FolderL, oPartDoc) function and 
' place its call in the Catch of the last FindAssyFile#(AssyNum, FolderL, oPartDoc) function.  Keep the error message in the
' Catch of the last FindAssyFile#(AssyNum, FolderL, oPartDoc) function.

'To see the Autodesk forum post that concerns the creation of this rule, go to this link:
'
'https://forums.autodesk.com/t5/Inventor-ilogic-api-vba-forum/work-around-To-Get-assemblies-In-content-center-Using-quot-flags/td-p/10796274/highlight/False

']

'*******************************************************************************************************************

'[ Clean version of the code with very few comments.  Highlight everything and click "Uncomment the selected lines" button once. 
'Sub Main()
' Dim oAsmDoc As AssemblyDocument
 
' oAsmDoc = ThisApplication.ActiveDocument
	
''Iterate through all of the occurrences
'Dim oOcc As ComponentOccurrence
'For Each oOcc In oAsmDoc.ComponentDefinition.Occurrences

'	 Dim oOccDoc As Document
'	 oOccDoc = oOcc.Definition.Document

'    If oOccDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then   

'        Dim oPartDoc As PartDocument = oOccDoc
'		Dim check As String
'		Dim AssyNum As String
'		Dim FileLoc As String
               
'		' Check the flag.
'		check = CC_AssyCheck(oPartDoc)

'		If check = "Yes" Then
			
'			'PUll the Part Name field from iProperties.
'			AssyNum = PullNum(oPartDoc)
			
'			'Pull the folder name from the iProperties.
'			FoldL = PullFolder(oPartDoc)
			
'			'Find the desired assembly file to replace with.
'			FileLoc = FindAssyFile1(AssyNum, FoldL, oPartDoc)
				
'		End If

'    End If

'Next

'End Sub

'' Check the flag "CC_Assy?" to see if it stores a "Yes" or a "No"
'Function CC_AssyCheck(oPartDoc) As String  

'	Try
'	' Get the User Defined property set.
'	Dim UserDefinedPropSet As PropertySet
'	UserDefinedPropSet = oPartDoc.PropertySets.Item("Inventor User Defined Properties")

'	' Get the custom property "CC Assy?" value.
'	Dim AssyCheck As Inventor.Property
'	AssyCheck = UserDefinedPropSet.Item("CC_Assy?")

'	Dim Ans As String
'	Ans = AssyCheck.Value

'		If Ans = "Yes" Then
		
'			Return Ans
		 
'		ElseIf Ans = "No" Then
'		End If
	 
'	Catch

'	End Try
		
'End Function

'' Get the part number of the assembly 
'Function PullNum(oPartDoc) As String 
'	Try

'	' Declare a variable "AssyN" to be a string
'	Dim AssyN As String
 
' 	' Get the PropertySets object.
'    Dim oPropSets As PropertySets
'        oPropSets = oPartDoc.PropertySets

'    ' Get the design tracking property set.
'    Dim oPropSet As PropertySet
'        oPropSet = oPropSets.Item("Inventor Summary Information")

'    ' Get the part number iProperty.
'    Dim oPartNumiProp As Inventor.Property
'        oPartNumiProp = oPropSet.Item("Title")
'		AssyN = oPartNumiProp.Value
		
'			If AssyN = ""
'	MessageBox.Show(oPartDoc.DisplayName &" does not contain the part number of the desired assembly", 
'	"No Assembly Number Found")

'			ElseIf AssyN = " " Then
'	MessageBox.Show(oPartDoc.DisplayName &" does not contain the part number of the desired assembly", 
'	"No Assembly Number Found")

'			ElseIf AssyN = "  " Then
'	MessageBox.Show(oPartDoc.DisplayName &" does not contain the part number of the desired assembly", 
'	"No Assembly Number Found")

'			End If

'Return AssyN
       	
'	Catch

'	End Try
		
'End Function 

''This function pulls the folder name the assembly is located in, which is a user input in the iProperties. 
'Function PullFolder(oPartDoc) As String
	
'	Try
'		Dim UserDefinedPropSet2 As PropertySet
'		UserDefinedPropSet2 = oPartDoc.PropertySets.Item("Inventor User Defined Properties")
	
'		Dim FolderN As Inventor.Property
'		FolderN = UserDefinedPropSet2.Item("Assy Folder")
'		Dim FolderLoc As String
'		FolderLoc = FolderN.Value
	 
'			If FolderLoc = "" Then
'	MessageBox.Show(oPartDoc.DisplayName &" does not contain the folder name the desired assembly resides in", 
'	"No Folder Name Found")
			
'			ElseIf FolderLoc = " " Then
'	MessageBox.Show(oPartDoc.DisplayName &" does not contain the folder name the desired assembly resides in", 
'	"No Folder Name Found")
	
'			ElseIf FolderLoc = "  " Then
'	MessageBox.Show(oPartDoc.DisplayName &" does not contain the folder name the desired assembly resides in", 
'	"No Folder Name Found")

'			End If

'		Return FolderLoc
		
'	Catch

'	End	Try
			
'End Function

'Function FindAssyFile1(AssyNum, FolderL, oPartDoc)
	
'	Dim SearchLocation As String = "R:\__RND CUSTOM & PACKAGING\Purchased\" & FolderL & "\"
	
'	Dim FN As String 
	
'    	FN = AssyNum & ".iam"
'		Logger.Info("FN Value is: " & FN)
'		Logger.Info("Search Directory is: " & SearchLocation)

'Logger.Info("----+++++Folder Name in Function is: " & FolderL)

'	Try
		
'    	Dim dirs As String ()
'    	dirs = System.IO.Directory.GetFiles(SearchLocation, FN) 
'   		Dim fullPath As String
'    	fullPath = dirs.GetValue(0)
		
'	Catch
	
'    	FileLoc2 = FindAssyFile2(AssyNum, FolderL, oPartDoc)	

'	Return FileLoc

'	End Try

'Dim strRelativeFileLocation As String = SearchLocation & FN

'	Component.Replace(oPartDoc.DisplayName & ":1", strRelativeFileLocation, True)
		
'End Function 

'Function FindAssyFile2(AssyNum, FolderL, oPartDoc)
	
'	Dim SearchLocation2 As String = "R:\__RND CUSTOM & PACKAGING\Assembly\" & FolderL & "\"

'	Dim FN As String 
	
'    	FN = AssyNum & ".iam"
'		Logger.Info("2nd Fnctn FN Value is: " & FN)
'		Logger.Info("2nd Fnctn Search Directory is: " & SearchLocation2)

'	Try
		
'		Dim dirs2 As String ()
'    	dirs2 = System.IO.Directory.GetFiles(SearchLocation2, FN)
'   		Dim fullPath2 As String
'    	fullPath2 = dirs2.GetValue(0)
	
'	Catch
    	
'		MessageBox.Show("The File " & FN & " cannot be found in Purchased Folder Or Assembly Folder" _
'    	& vbNewLine & "" _
'    	& vbLf & "Please make sure an assembly file exsists in the Purchased or Assembly Folder" _
'    	& vbNewLine & "" _
'    	& vbCrLf & "Assembly file not found", "Cannot Find Assembly in Folders",MessageBoxButtons.OK,MessageBoxIcon.Error)

'	Return FileLoc2

'	End Try

'Dim strRelativeFileLocation2 As String = SearchLocation2 & FN

'	Component.Replace(oPartDoc.DisplayName & ":1", strRelativeFileLocation2, True)	

'End Function   
']

 

 

 

 

Here is the idea and how it works:

 

First, create two custom iProperties.  The first custom iProperty will be called "CC_Assy?" and it takes a string of text input ("Yes" or "No").  As @A.Acheson pointed out in an earlier post, there was a problem using boolean for the Yes and No, so Use a sting.  The second custom iProperty will be called "Assy Folder" and it holds a string of text.  This string will be the folder name the actual assembly live in. 

 

Here is an example:

Aubrey_Campbell_0-1643745145740.png

 

Now that you have created the new custom iProperties, you need to create a representative part (a simple .ipt that will go into the CC and represent the assembly you want). 

 

Here is a good way to create one of those parts:

Create a simple .ipt (thin extruded rectangle, for example) and place a screen shot of the assembly this .ipt will represent in a sketch on the front face of the part.  ... Maybe create another sketch that has the text "RUN CONTENT CENTER ASSEMBLY RULE" to remind users what they need to do. 

Here is an example of one I made to represent an electrical box.  

 

Aubrey_Campbell_1-1643745415317.png

 

Now that we have a representative part, we need to fill out the iProperties so the code will find what it needs to carry out the replace. 

 

Let's say the assembly you want to put in the Vault has filename "A10001003.iam" and it lives in a folder called "A10001000-10001999"

 

Aubrey_Campbell_2-1643746832866.png

 

The part of the directory in the yellow box is hard coded into the rule.  You will have to find that line of code and replace it with your actual directory. 

 

Go back to your representative part and fill in the iProperties:

Put the filename (without the extension) In the "Title" field under the "Summary" tab

 

Aubrey_Campbell_3-1643747089473.png

 

Now click over to the "Custom" tab and fill in the two custom iPropeties you created.  

"CC_Assy?" gets a "Yes" value and in the "Assy Folder" field, input the folder name.

 

Aubrey_Campbell_4-1643747222073.png

 

 

Now, publish the representative part to the content center.  

 

Now you are ready to use it and "pull" and assembly from the CC. 

 

Place your representative part from the CC into an assembly and run the rule.  

 

Your part will be automatically replaced with the assembly you assigned to the representative part.  

 

I hope this makes sense and is useful to someone!!

 

As I mentioned earlier in this post, I do plan to return to this project at some point to finish the other version that searches all folders and sub folders so you don't need to create an iProperty for the folder name.  Right now, that code works, but is very slow as it searches EVERYTHING.  I cannot use that version as it is due to the time it takes to run and find the correct files; my team will complain!! ... It just needs to be tuned up a little to work quicker.  Once I finish that, or make any adjustments, I will post it to this thread.  

 

..... Before I finish the next version, I will probably need to work on getting this version to work with Vault.  

 

Updates to come (probably not very soon, though).   

 

Extra special thanks to @A.Acheson for all the help!!!! 

Also, thanks to @theo.bot for helpful information and resources!!!! 

 

 

 

 

 

 

 

 

0 Likes