3DX Development Chronicles

#vba #3dx

We have created objects and propagated the changes to the database.

Now is the time to see how to open them in the Catia editor.

In Catia V5, we simply had to select the Open method and enter the location of the document.

Dim PartDoc As Document
Set PartDoc = CATIA.Documents.Open(FullDocPath & "\Document-name.CATPart")

In the 3DEXPERIENCE platform, we must search for an object in the database before opening it. In this post, we will use the 'Easy Search' option.

These are the steps we followed:

  1. Create search criteria: create a dictionary with the key attributes to be used for the search. We use a dictionary because the attributes can differ each time and we want to reuse the function.

  2. Search for entities: together with the criteria dictionary and the base type — the type of object to be searched for; in this example, a 'VPMReference' — this function performs the actual search in the database and returns a list of results as 'PLMEntities'.

  3. Process search results: the results of the search are handled, and if only one object is found, it will be loaded in a new editor.

Option Explicit

Sub CatMain()
    Dim SearchCriteria As Object
    Set SearchCriteria = CreateObject("Scripting.Dictionary")
    Call SearchCriteria.Add("PLM_ExternalID", "prd-xxxxxxxx-00000001")
    Call SearchCriteria.Add("revision", "A")

    Dim Entities As PLMEntities
    Set Entities = EasySearchDbObject("VPMReference", SearchCriteria)

    Call ProcessAndOpenSearchResult(Entities)
End Sub

' Searches the database for PLM entities matching the given criteria
Public Function EasySearchDbObject(ByVal BaseType As String, ByVal Criteria As Object) As PLMEntities

    On Error GoTo ErrorHandler
    Dim SearchService As SearchService
    Set SearchService = CATIA.GetSessionService("Search")

    Dim DbSearch As DatabaseSearch
    Set DbSearch = SearchService.DatabaseSearch

    DbSearch.Mode = SearchMode_Easy
    DbSearch.BaseType = BaseType

    Call AddCriteriaToDbSearch(DbSearch, Criteria)

    Call SearchService.Search

    Set EasySearchDbObject = DbSearch.Results

    Exit Function

ErrorHandler:
    Set EasySearchDbObject = Nothing
End Function

' Helper method to add criteria to DbSearch
Private Sub AddCriteriaToDbSearch(ByVal DbSearch As DatabaseSearch, ByVal Criteria As Object)

    Dim Key As Variant
    For Each Key In Criteria.Keys()
        ' If a key is not valid, just jump to the next one
        ' Valid keys are searchable attributes of the PLM entity
        On Error Resume Next
        Call DbSearch.AddEasyCriteria(CStr(Key), Criteria(Key))
        On Error GoTo 0
    Next
End Sub

' Handles the result of a PLM entity search and opens it if found
Private Sub ProcessAndOpenSearchResult(ByVal Entities As PLMEntities)

    If (Entities Is Nothing) Or (Entities.Count = 0) Then
        Call MsgBox("Object not found in the database", vbCritical, "Object not found.")
    ElseIf Entities.Count = 1 Then
        Dim NewEditor As Editor
        Set NewEditor = OpenPlmEntity(Entities.Item(1))
        If NewEditor Is Nothing Then
            Call MsgBox("Failed to open the PLM entity.", vbCritical, "Open Error")
        End If
    Else
        Call MsgBox("More than one object has been found with those criteria. Refine the search to find just one object", _
                      vbCritical, "Multiple object found.")
    End If
End Sub

' Opens a PLM entity and returns the editor
Public Function OpenPlmEntity(ByVal Entity As PLMEntity) As Editor

    On Error GoTo ErrorHandler

    Dim OpenService As PLMOpenService
    Set OpenService = CATIA.GetSessionService("PLMOpenService")

    Dim NewEditor As Editor
    Call OpenService.PLMOpen(Entity, NewEditor)

    Dim ErrorCode As Long
    Dim ErrorMessage As String
    Call OpenService.getLastError(ErrorMessage, ErrorCode)

    If ErrorCode <> 0 Then
        Call MsgBox(ErrorMessage, vbCritical, "Open Error.")
    End If

ErrorHandler:
    Set OpenPlmEntity = NewEditor
End Function

#vba #3dx

In this post , we learned how to create an object in the database. However, this process has some limitations.

Now, we will see how to save an open object.

First, we are not actually saving anything; in 3DEXPERIENCE jargon, we are propagating the changes. To do so, we must use the PLMPropagateService. Once the service is retrieved, the process is quite simple: PLMPropagate will do the job.

Note: PLMPropagate only propagates changes of the “Active Editor.”

If the propagate action is not carried out correctly for any reason, the reason can be retrieved using the method getLastError. This method provides the error number and description.

Option Explicit

Sub CatMain()
    Call PropagateChanges
End Sub

' Save the changes to the database of the current editor only
Public Function PropagateChanges()

    On Error GoTo ErrorHandler

    Dim PropagateService As PLMPropagateService
    Set PropagateService = CATIA.GetSessionService("PLMPropagateService")

    Call PropagateService.PLMPropagate

    Dim ErrorCode As Long
    Dim ErrorMessage As String
    Call PropagateService.getLastError(ErrorMessage, ErrorCode)

    If ErrorCode <> 0 Then
        Call MsgBox(ErrorMessage, vbCritical, "Propagation Error.")
    End If

    Exit Function

ErrorHandler:
    Call MsgBox("Error while propagating changes.", vbCritical, "Propagation Error")

End Function

#vba #v5 #3dx

If you have experience programming in V5 and 3dx, you are likely aware that the selection object is accessed through the Document or the Editor, respectively.

In this post, we have explored how to share code between both applications. One potential solution could be:

Dim ActiveSelection As Selection

If CATIA.System.Configuration.Version = 5 Then
    Set ActiveSelection = CATIA.ActiveDocument.Selection
    
ElseIf CATIA.System.Configuration.Version = 6 Then
    Set ActiveSelection = CATIA.ActiveEditor.Selection
    
End If

This solution is designed for the active document or editor. To enhance its reusability and allow selection from other documents or editors without needing to activate them, a more generic function can be created:

Dim ActiveSelection As Selection
Set ActiveSelection = GetSelection(CATIA.ActiveDocument)  ' or CATIA.ActiveEditor

' The following function can be created in a separated Module or Class
Public Function GetSelection(ByVal WorkingContext As Variant) As Selection
    On Error GoTo ErrorHandler
    Set GetSelection = WorkingContext.Selection
    ExitFunction
    
ErrorHandler:
    On Error GoTo 0
    Debug.Print "Selection error " & Err.Description
    ExitFunction
End Function

#vba #3dx

In the 3DEXPERIENCE Platform, documents are replaced by objects or PLM entity. Everything is now stored in the database. Parts, Drawings, Products, Publications...

In Catia V5, creating a new part was quite simple. You could use a method like this to create a part (error handling and other checks omitted):

Function CreateNewPartDocument() As PartDocument
    
    Dim Docs As Documents
    Set Docs = CATIA.Documents

    Dim PartDoc As PartDocument
    Set PartDoc = Docs.Add("Part")
    
   Set CreateNewPartDocument = PartDoc 

End Sub

In the new world, to create a new object, you need to use the application's session services (and not the editor's).

Remember that after creating the new object, it will be loaded in a new editor. This means that the CATIA.ActiveEditor is now the newly created object.

Option Explicit

Sub CatMain()
    Dim NewEditor As Editor
    Set NewEditor = CreateNewDbObject("3DShape")
End Sub

Public Function CreateNewDbObject(ByVal ObjectType As String) As Editor

    If Len(Trim(ObjectType)) = 0 Then Exit Function

    On Error GoTo ErrorHandler

    Dim NewService As PLMNewService
    Set NewService = CATIA.GetSessionService("PLMNewService")

    Call NewService.PLMCreate(ObjectType, CreateNewDbObject)

    Exit Function

ErrorHandler:
    Call MsgBox("Object of type '" & ObjectType & "' could not be created.", vbCritical, "Error while creating new database object.")

End Function

The ObjectType parameter can be of several types. For example:

  • 3DShape
  • 3DPartt
  • VPMReference to create a Physical Product
  • Drawing
  • ...

However, only the 3DShape and Drawing options are valid with the basic licences. If you use any other type, you will receive error “Operation not authorized”, as a specific licence is required (E70). If you want to create these objects in the database, take a look at WebServices and EKL.

#ekl #bestpractice #kac

cover document

Note that you will need a registered account to access the file.

#ekl #bestpractice #python

Until now, you could use Python via the COM interface for automation. There are wrappers for Catia V5 pycatia and for 3DEXPERIENCE experience. In the Templates Rules Designer, you can now create Python scripts using the EKL language. You can use external packages from PyPI (make sure to use the correct version), or even create your own packages. If you want to take it further, you can create a package that uses automation and call it from a Python script. Spoiler alert: the selection methods do not work.

Would you like to learn more? Then check out the best practices on Python scripting in 3DEXPERIENCE!

cover document

Note that you will need a registered account to access the file.

#3dx #v5 #ekl

A ternary operation in programming is a concise way to perform conditional evaluations. The ternary operator takes three operands and is typically used as a shorthand for an if-else statement.

Syntax

The general syntax of a ternary operation is:

condition ? expression_if_true ; expression_if_false

Explanation

  • condition: This is the expression that is evaluated. If it evaluates to true, the first expression is executed; if false, the second expression is executed.
  • expression if true: This expression is returned if the condition is true.
  • expression if false: This expression is returned if the condition is false.

Example

Create a Boolean parameter “switch” with value true Create a Point.1 with coordinates (10, 0, 0) Create a Point.2 with coordinates (-10, 0, 0) Create a parameter of type point and in the formula editor type:

switch == true ? Point.1 ; Point.2

You might need to select the points from the tree to be sure the complete path is caught

In this example, the condition checks if switch is true or false. If true, it assigns “Point.1” to the point parameter, otherwise, it assigns “Point.2”

It can be used directly in formulas, making it useful for assignments. For complex conditions, a rule or reaction can still be used.

#vba #v5 #3dx

Maybe you are working with Catia V5 and 3DEXPERIENCE on a daily basis depending on customers needs. Most of the API is common for both aplications but some of the key methods are different. In order to reuse the code for both aplications, you can check the version and depending on it follow a diference code path.

Dim CatiaVersion As Long
CatiaVersion = CATIA.System.Configuration.Version 

If CatiaVersion = 5 Then
    ' Put your V5 code here

ElseIf CatiaVersion = 6 Then
    ' Put your 3dx code here

End If

#vba #v5 #3dx

When files are moved or downloaded, ensuring their integrity is crucial. One popular method for verifying that a file has not been altered is through MD5 hashing.

What is MD5 Hashing?

MD5 (Message Digest Algorithm 5) is a cryptographic hash function that produces a 128-bit (16-byte) hash value, typically represented as a 32-character hexadecimal number. It takes an input (such as a file) and generates a unique hash. Even a tiny change in the file will result in a completely different hash.

Why is MD5 Important?

MD5 is widely used to verify file integrity. When you download a file, the provider often supplies an MD5 hash. After downloading, you can compute the hash of your copy and compare it to the original. If the hashes match, the file is intact; if not, it may be corrupted or tampered with.

How to Use MD5 for File Integrity: 1. Before Transfer: The sender computes the MD5 hash of the file and shares it. 2. After Transfer: The receiver computes the MD5 hash of the received file. 3. Comparison: If both hashes are identical, the file is unchanged.

How to Use MD5 for File Integrity

You can verify file integrity using MD5 in two common ways: with PowerShell or with VBA code.

Using PowerShell

PowerShell provides a simple command to compute the MD5 hash of a file:

Get-FileHash -Algorithm MD5 "C:\path\to\file"

This command outputs the MD5 hash, which you can compare with the expected value.

Using VBA Code

If you prefer to automate the process within Microsoft Office or other VBA-enabled environments, you can use a VBA module to compute the MD5 hash. For example, you might have a module like ComputeMD5.bas with a function to calculate the hash of a file:

On Error Resume Next

Dim Hash As String
Hash = ComputeMd5("C:\path\to\file")

If Err.Number <> 0 Then
        MsgBox "Error: " & Err.Description
Else
        MsgBox "MD5: " & Hash
End If

This approach is useful for integrating file integrity checks into your own automation workflows.

Limitations

While MD5 is fast and easy to use, it is not collision-resistant. For highly sensitive applications, stronger algorithms like SHA-256 are recommended. However, for basic file integrity checks, MD5 remains a practical choice.

Conclusion

MD5 hashing is a simple yet effective way to ensure files remain unchanged during transfers. By comparing hash values before and after moving or downloading files, users can quickly verify file integrity and prevent issues caused by corruption or tampering.

You can also check external files (settings, XML, TXT, etc.) of your application for unwanted modifications before using the app. This check will not prevent users from modifying the files, but if they do so, you will be able to log the issue and inform them to use an unmodified file.😉

ComputeMd5.bas

The original code has been extracted from this source and then refactored to make it more module-friendly and easier to understand.

' Checks if the specified file exists.
Private Function FileExists(FilePath As String) As Boolean
    On Error GoTo ErrorHandler
    FileExists = (Len(Dir(FilePath)) <> 0)
    Exit Function
ErrorHandler:
    FileExists = False
End Function

' Allocates a buffer for reading file data, rounding up to the nearest KB if needed.
Private Function AllocateBuffer(HFile As Integer, BlockSize As Long) As Byte()
    Const KB As Long = 1024
    ' Adjust block size to next multiple of 1024 if file is smaller than requested block size
    If LOF(HFile) < BlockSize Then
        BlockSize = ((LOF(HFile) + KB - 1) \ KB) * KB
    End If
    Dim Buffer() As Byte
    ReDim Buffer(0 To BlockSize - 1)
    AllocateBuffer = Buffer
End Function

' Computes the MD5 hash of a file stream using block-wise reading.
Private Function ComputeFileHash(HFile As Integer, BlockSize As Long) As Byte()
    Dim Md5Provider As Object
    Set Md5Provider = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")

    Dim FileLen As Long
    FileLen = LOF(HFile)

    Dim NumBlocks As Long
    NumBlocks = FileLen \ BlockSize

    Dim RemainderSize As Long
    RemainderSize = FileLen Mod BlockSize

    Dim Buffer() As Byte
    ReDim Buffer(0 To BlockSize - 1)

    Dim i As Long
    ' Read and process each block
    For i = 1 To NumBlocks
        Get HFile, , Buffer
        Md5Provider.TransformBlock Buffer, 0, BlockSize, Buffer, 0
    Next i

    ' Process the final block
    If RemainderSize > 0 Then
        Get HFile, , Buffer
        Md5Provider.TransformFinalBlock Buffer, 0, RemainderSize
    Else
        Md5Provider.TransformFinalBlock Buffer, 0, 0
    End If

    ComputeFileHash = Md5Provider.Hash
    Md5Provider.Clear
    Set Md5Provider = Nothing
End Function

' Converts a byte array to a hexadecimal string.
Private Function BytesToHex(Buffer() As Byte) As String
    ' Converts a byte array to a hexadecimal string
    Dim HexStr As String: HexStr = ""
    Dim i As Long
    For i = LBound(Buffer) To UBound(Buffer)
        HexStr = HexStr & Right("0" & Hex(Buffer(i)), 2)
    Next i
    BytesToHex = HexStr
End Function

' Main function to compute the MD5 hash of a file and return it as a hex string.
Public Function ComputeMd5(FilePath As String) As String
    Const DEFAULT_BLOCK_SIZE As Long = 2 ^ 16

    If Not FileExists(FilePath) Then
        Err.Raise 53, , "File not found." & vbCr & FilePath
    End If

    Dim HFile As Integer
    HFile = VBA.FreeFile
    On Error GoTo ErrorHandler
    Open FilePath For Binary Access Read As HFile

    Dim HashBuffer() As Byte
    HashBuffer = ComputeFileHash(HFile, DEFAULT_BLOCK_SIZE)
    ComputeMd5 = BytesToHex(HashBuffer)

    If HFile <> 0 Then Close HFile
    Exit Function

ErrorHandler:
    On Error Resume Next
    If HFile <> 0 Then Close HFile
    Err.Raise 5, , "File could not be processed." & vbCr & FilePath
End Function

#vba #3dx

Information extracted from the User Assistance

In a collaborative space, managing access and permissions is essential. In the 3DEXPERIENCE platform, credentials comprise a collaborative space, a role and an organization, and define the content a user can access and the actions they can perform.

What are credentials?

When users log in, they select a collaborative space, role, and organization. This combination is called credentials. Credentials determine the user's access rights and the scope of content available to them.

Users may be authorized for multiple collaborative spaces but are only connected to one set of credentials at a time. While users can be assigned multiple roles within a collaborative space, this is generally discouraged due to the hierarchical nature of role access.

How roles work

Roles dictate what content users can access and what operations they can perform, such as searching, viewing, creating, or deleting content. Roles inherit the permissions of lower ones.

Example role hierarchy:

  • Reader: Can view content and create personal management items (Favorites, Personal Folders).
  • Contributor: Inherits Reader rights and can create evaluation content (Reviews, Simulations).
  • Author: Inherits Contributor rights and can create definition content (Requirements, CAD, EBOM Part, etc.).
  • Leader: Inherits Author rights and can create design resources (Libraries, Project Templates).

Restricted roles (e.g., Reader Restricted, Contributor Restricted) limit read access to content owned by the collaborative space and organization but otherwise function like their regular counterparts.

Administrative roles

Administrative roles provide broader access and management capabilities: – Owner: Can read all content in a collaborative space, create administrative resources, manage resources, and modify properties for repair or exception tasks. – Administrator: Inherits all Owner rights across all collaborative spaces, manages company resources, and can modify any property in the 3DEXPERIENCE 3D Space service. – Owner Restricted: Restricts read access to content owned by the collaborative space and organization, with the same capabilities as a regular Owner.

Use case

It makes sense to check the user's credentials before they use an application that modifies or adds geometry. The idea is to inform the user that, with the current credentials, it is not possible to save data. This avoids the situation where a user has been working for some time, only to find that they cannot save to the database. 🙁

Function to check if the active user write rights

Const VALID_WRITE_ROLES As String = "VPLMCreator,3DSRestrictedAuthor,VPLMProjectLeader,3DSRestrictedLeader"


' Checks if the currently connected user has write rights based on their role.
' Returns True if the user's role is in the list of valid write roles.
Function HasUserWriteRights() As Boolean

    On Error GoTo ErrorHandler

    Dim PnoService As PnoService
    Set PnoService = CATIA.GetSessionService("PnOService")

    Dim ConnectedPerson As Person
    Set ConnectedPerson = PnoService.Person

    Dim ActiveRole As String
    ActiveRole = ConnectedPerson.RoleID

    HasUserWriteRights = ValueInList(ActiveRole, Split(VALID_WRITE_ROLES, ","))

ErrorHandler:
    Exit Function

End Function


' Checks if a given value exists in the provided list (array).
' Returns True if found, otherwise False.
Private Function ValueInList(Value As String, List As Variant) As Boolean

    If Not IsArray(List) Then Exit Function

    If Len(Trim(Value)) = 0 Then Exit Function

    Dim i As Integer
    For i = LBound(List) To UBound(List)
        If StrComp(List(i), Value, vbBinaryCompare) = 0 Then
            ValueInList = True
            Exit For
        End If
    Next i

End Function


Sub CATMain()
    MsgBox HasUserWriteRights
End Sub

In a future post, we will learn how to check whether files are locked and who locked them.