What's new

Can't get suppressed sub-sub-assemblies.

I can't make sense of what's happening here. When an assembly has a 1st-level subassembly that's suppressed, then I can find it in the collection returned by:

IADAssemblySession.RootOccurrence.Occurrences()

and it has .IsSuppressed = True as expected.

But if there's a 2nd-level subassembly that's suppressed, it doesn't appear in .Occurrences() at all. However, it does appear in IADDesignSession.ConstituentPaths().

The problem this causes is I'm using IADDesignSession.ConstituentPaths() to look for missing files, since they don't appear in Occurrences(), but when there's a suppressed sub-sub-assembly, I can't distinguish it from a missing file.

subassemblies.png
 

stepalibre

Alibre Super User
The problem this causes is I'm using IADDesignSession.ConstituentPaths() to look for missing files, since they don't appear in Occurrences(), but when there's a suppressed sub-sub-assembly, I can't distinguish it from a missing file.
There's not a one to one relationship to occurrences and constituents. You can have 100 occurrences of a single part or assembly. They can be suppressed or have different configurations set in a parent assembly. At the root (1st) level without any nested sub assemblies you'll see a one to one relationship to constituents of unique parts and assemblies where a single occurrence is only present.

ConstituentPaths only show which files are required (referenced) in the assembly or session. This is separate from the occurrence functionality, which is an instance of a part, assembly, or constituent.

Without double checking this I think a missing constituent will prevent the assembly file from loading, and trigger the missing constituent dialog. In your screenshots even for suppressed occurrences you should be able to access subassemblies at any level in code. Can you explain what you're trying to do? Are you building a program to detect missing files to fix? Or are you trying to replace occurrences that are missing?
 

stepalibre

Alibre Super User
I get the constituents and open/close them, like this:
Code:
    For Each Session As IADSession In Root.Sessions
        Console.WriteLine(Session.Name)
        For Each FilePath As String In Session.ConstituentFilePaths
            Console.WriteLine(FilePath)
            Root.OpenFile(filePath)
        Next
    Next
Then, in GUI or headless mode I do work on assemblies, parts, etc.
 
Yea, I realize multiple occurences of the same part only appear once in ConstituentPaths(). But the problem here is that there's a file in ConstituentPaths() (two blocks's AD_ASM file) which doesn't exist in any of the occurrences at any level in the tree.

I'm trying to detect if an assembly has changed without calling the API. I'm doing that by storing hashes of all the files (obtained from the occurrences) and comparing them to the current versions of the files. This works OK except that if a file was missing from an assembly when it was hashed, my application won't know about it and thus can't tell if it gets re-instated. To get avoid that, I'm having it refuse to operate on an assembly with any files missing. I detect missing files by making sure every file in ConstituentPaths() exists in an occurrence.

Now that I wrote all that out, it's clear that it's a giant mess and there's probably a better way. Maybe using ConstituentPaths() as the authoritative source of what files are in an assembly. Except the paths returned by that aren't always the same locations as the actual files and I'm not sure how to reliably "correct" them.

A missing constituent file doesn't prevent it from loading through the API. I wish it would, but it just silently omits that part/subassembly and acts as if everything's fine.
 
I get the constituents and open/close them, like this:
Code:
    For Each Session As IADSession In Root.Sessions
        Console.WriteLine(Session.Name)
        For Each FilePath As String In Session.ConstituentFilePaths
            Console.WriteLine(FilePath)
            Root.OpenFile(filePath)
        Next
    Next
Then, in GUI or headless mode I do work on assemblies, parts, etc.
I don't think that'll work safely because sometimes the paths in ConstituentFilePaths aren't the actual locations of the files. Maybe they're where the files used to be when the assembly was saved or something.
 

stepalibre

Alibre Super User
I don't think that'll work safely because sometimes the paths in ConstituentFilePaths aren't the actual locations of the files. Maybe they're where the files used to be when the assembly was saved or something.
I use ConstituentFilePaths to get a list of referenced files. I then use .NET and/or Everything search app to check if the file exist. If it does not exist at the location specified by ConstituentFilePaths, I search my file system using the missing constituent file name.

Here is the console output and Constituents dialog for reference using demo files:

1714812568454.png

The RED file is missing. I search for tangent-edge-fillets, and if found, I copy it to the location to fix the assembly. Over ~10 years and countless PC and SSD upgrades, I've broken assemblies and use this technique to repair them. This is not exclusive to Alibre Design, and I normally keep files under the same root folder, but some slip through the cracks.
A missing constituent file doesn't prevent it from loading through the API. I wish it would, but it just silently omits that part/subassembly and acts as if everything's fine.
You should check if the file exist first, then decide what to do about it.
I'm trying to detect if an assembly has changed without calling the API. I'm doing that by storing hashes of all the files (obtained from the occurrences) and comparing them to the current versions of the files.
What is the hash? Are you including datetime, file modified or file accessed information? Why not write a program that controls Alibre and handles the change tracking?
Now that I wrote all that out, it's clear that it's a giant mess and there's probably a better way. Maybe using ConstituentPaths() as the authoritative source of what files are in an assembly. Except the paths returned by that aren't always the same locations as the actual files and I'm not sure how to reliably "correct" them.
A PDM system would help here.
 
You should check if the file exist first, then decide what to do about it.
I don't know how. If I open an assembly with the API and it has missing subassemblies or parts, the only way I know to detect that is if they're in ConstituentFilePaths but not on disk. However, since the path part of those filenames is unreliable, I might have to do a risky and expensive search like you described. This is even for non-broken assemblies which can have the wrong path but still work fine and somehow Alibre finds the correct files.

What is the hash? Are you including datetime, file modified or file accessed information? Why not write a program that controls Alibre and handles the change tracking?
It's just a hash I make of the file contents. I've been trying not to touch the API to check for changes because I felt it was too slow, but I might have misjudged that.
 

stepalibre

Alibre Super User
I don't know how. If I open an assembly with the API and it has missing subassemblies or parts, the only way I know to detect that is if they're in ConstituentFilePaths but not on disk.
Yes here's an example. If a constituent is not found, you need to find it somehow or take an action.
Code:
Sub Main()
    Dim args As String() = Environment.GetCommandLineArgs()
    Dim Hook As IAutomationHook = New AutomationHook()
    Hook.Initialize(Nothing, Nothing, Nothing, False, 0)
    Dim Root As IADRoot = DirectCast(Hook.Root, IADRoot)
    Console.WriteLine("Provide an assembly file to check if ConstituentFilePath exist")
    Dim InputFile = Console.ReadLine()
    Dim session As IADSession = Root.OpenFile(InputFile)
    For Each item As IADSession In Root.Sessions
        For Each FilePath As String In item.ConstituentFilePaths
            If File.Exists(FilePath)
                DoWork(0, FilePath)
            Else
                DoWork(1, FilePath)
            End If
        Next
    Next
End Sub
Sub DoWork(_Int, _String)
    Select Case _Int
        Case 0
            Console.WriteLine(String.Format("The ConstituentFilePath for [{0}] was found!", _String))
        Case 1
            Console.WriteLine(String.Format("The ConstituentFilePath for [{0}] was not found!", _String))
    End Select
End Sub
However, since the path part of those filenames is unreliable, I might have to do a risky and expensive search like you described.
Yes, you have to find the missing files.
This is even for non-broken assemblies which can have the wrong path but still work fine and somehow Alibre finds the correct files.
This is related to session data not reflecting data on disk. You'll need to ensure assemblies and parts are properly saved and regen/updated before any code is run on those files.
It's just a hash I make of the file contents. I've been trying not to touch the API to check for changes because I felt it was too slow, but I might have misjudged that.
Is this for security or data integrity. The checksum of a file can change even without new geometry or data changes by saving any change. And opening an old file can trigger a change on exit see this thread:
I'm trying to detect if an assembly has changed without calling the API.
I guess this all depends on what "has changed" mean to you. There are a lot of change that can occur in a file that does not affect geometry or topology. Metadata change can be detected but require more work.
 
> This is related to session data not reflecting data on disk. You'll need to ensure assemblies and parts are properly saved and regen/updated before any code is run on those files.

Ah, so I have to save it before using ConstituentFilePaths. I'd rather not because I don't want my application altering the Alibre files at all. Didn't know it does that silently for old files. Since this is all getting too messy, I'll give up on detecting when missing files have been reinstated and just let users sort it out.
 

stepalibre

Alibre Super User
Ah, so I have to save it before using ConstituentFilePaths.
No, only if changes have been made in-between your code being run. If users are accessing files this can cause problems when your code accesses the same files. This type of work is best done off-hours when no one is working. Or you could restrict file/project access while your application is in use.
 
No, only if changes have been made in-between your code being run. If users are accessing files this can cause problems when your code accesses the same files. This type of work is best done off-hours when no one is working. Or you could restrict file/project access while your application is in use.

The specific case that I found was this assembly https://s3-us-west-1.amazonaws.com/alibre-usa/SampleModels/0_Alibre_Wankel_Airplane_Engine.AD_PKG If you extract it then open it with the API, the constituentfilepaths are wrong and look like they're from the computer that previously saved it. So it looks like if somebody moves their files to another location, then tries to use them through my application, my application will have to re-save them before trying to check for missing files.
 

stepalibre

Alibre Super User
The specific case that I found was this assembly https://s3-us-west-1.amazonaws.com/alibre-usa/SampleModels/0_Alibre_Wankel_Airplane_Engine.AD_PKG If you extract it then open it with the API, the constituentfilepaths are wrong and look like they're from the computer that previously saved it. So it looks like if somebody moves their files to another location, then tries to use them through my application, my application will have to re-save them before trying to check for missing files.
Yes. I noticed references/ConstituentFilePaths don't match until you save/regen/deep regen/update the files locally from packages. This is likely a bug in packages and/or the API.
 

stepalibre

Alibre Super User
You have to save the files again to fix the ConstituentFilePaths:
Package with wrong ConstituentFilePaths:
1715034473164.png
Package with right ConstituentFilePaths after save as:
1715034527653.png
 

stepalibre

Alibre Super User
The packager saves assemblies and parts to a temp folder @ AppData\Local\Temp\PackageTempFolder0 then creates the zip/Alibre Package and copies it to your folder. The ConstituentFilePaths don't update until the files are saved to disk.
 

stepalibre

Alibre Super User
So it looks like if somebody moves their files to another location, then tries to use them through my application, my application will have to re-save them before trying to check for missing files.
Yes, or don't use packages. If users are on the same network this is not a problem. If you rely on packages then, you'll need to save the files to update the ConstituentFilePaths. But again this all depend on your application and goals. When using a package all the files will be included in the package and will work properly when extracted. I don't understand your requirements and how detecting changes relate.
 
Oh that's good news. I don't think the API can open packages anyway, at least as I remember it, so nobody would probably be using those with my application.

Nonetheless, I've already abandoned the idea of checking for missing files. It's a fairly unlikely event anyway and I think people will just accept that they lost them themselves.
 

stepalibre

Alibre Super User
I'd rather not because I don't want my application altering the Alibre files at all.
Oh that's good news. I don't think the API can open packages anyway, at least as I remember it, so nobody would probably be using those with my application.

Nonetheless, I've already abandoned the idea of checking for missing files. It's a fairly unlikely event anyway and I think people will just accept that they lost them themselves.
You can read from Alibre files and save to a file or database any data you want to detect a change. This is more work but you can read and write anything. Here is my project for writing sketch data to plain text files:

This could be any data accessible through AlibreX or Alibre Script. You would then perform a diff on the data to detect the change. This is more reliable than using only checksums or hashes.
 
Na, I was just looking for a catch-all for any possible change even if it had some false positives. Checking the files themselves would be the safest way since nothing can change if the files aren't changed.
 

stepalibre

Alibre Super User
The DesignProperties APIs are also useful and worth considering. I make use of CustomProperties in my tools as a way to check versions and revisions.
 
Top