CATScript - Questions & Answers

CATScript is a scripting language specific to CATIA, a widely used computer-aided design (CAD) software. CATScript allows users to automate repetitive tasks, customize the software, and create custom tools and functionalities.

It is based on Visual Basic for Applications (VBA) and provides access to CATIA’s Automation API, enabling interaction with CATIA’s objects, properties, and methods.

CATScript can be used to enhance productivity, streamline workflows, and extend the capabilities of CATIA through script-based automation.

Is it possible to determine the current macro directory at runtime?

The macro directory is meant to be the directory where the actual macro file is located on disc. In Catia it does not seem to be possible to retrieve this directory at runtime, or at least I was not able to figure it out.

So the only way is to hard-code e.g. a path to a support file which needs to be loaded from within a CATScript macro.

Is it possible to organize code in a separate file and to evaluate/execute it?

Yes, here is a sample code to illustrate the call:

Sample code...

' Option Explicit
Language = "VBSCRIPT"

Const PATH_NAME = "<your path here>"
Const CUSTOM_DLG = "CustomDialogClass.CATScript"
Const DELIM = "@"

Sub CATMain()
	Dim usr As Variant
	Dim params() As Variant
	
	ReDim params(2)
	params(0) = 350
	params(1) = 420
	params(2) = _
		"The quick brown fox" + DELIM + _
		"*jumps over" 		  + DELIM + _
		"the lazy dog."

	usr = CATIA.SystemService.ExecuteScript ( _
			PATH_NAME, catScriptLibraryTypeDirectory, _
			CUSTOM_DLG, "CustomDialogClass_Cmd", params)

	If (Len(usr) = 0) Then
		MsgBox "Nothing selected!"
	Else
		MsgBox "You selected: '" + usr + "'"
	End If
End Sub

How can I read the decimal separator value from registry ?

The following function might be useful to ensure that CDbl works correctly with the decimal separator setting.

Sample code...

' read decimal separator value from registry
'
Function GetInternationalDecimal (ByRef val As String) As Boolean
	Dim wsh As IWshShell3
	GetInternationalDecimal = False

	Err.Clear : On Error Resume Next

	val = ""
	Set wsh = CreateObject("WScript.Shell")
	val = wsh.RegRead("HKCU\Control Panel\International\sDecimal")
	wsh = Nothing

	On Error Goto 0

	If (Err.Number <> 0 Or val = "") Then
		Exit Function
	End If
	GetInternationalDecimal = True
End Function

' // Test Call
' //
Sub CATMain ()
	Dim val,msg As String

	' MsgBox CATIA.SystemConfiguration.OperatingSystem

	If (Not GetInternationalDecimal(val)) Then
		MsgBox "Error: unable to read current decimal setting!"
		Exit Sub
	End If

	Select Case val
		Case ".":  msg = "point"
		Case ",":  msg = "comma"
		Case Else: msg = val
	End Select

	MsgBox "Current international decimal setting: " + msg
End Sub

Can I declare an array with multiple variables per item ?

The solution is to define a class MyCustomData with the data structure as required and in a 2nd step create an array variable as usual.

For each item of the array, the custom class can be given as argument. Note that as the given argument is from type “Class”, the “Set” operator must be used.

Once this is done, the syntax arr(i).str = str can be used as a valid statement to refer each individual custom data item.

Sample code...

Class MyCustomData
	Dim str As String
	Dim val As Variant
End Class

Sub AddItem (_
		ByRef arr() As Variant, _
		ByVal str As String, ByVal val As Variant)
	Dim i As Integer

	ReDim Preserve arr(UBound(arr) + 1)
	i = UBound(arr)

	Set arr(i) = New MyCustomData
	arr(i).str = str
	arr(i).val = val	
End Sub

Sub CATMain ()

	Dim custom_array() As Variant
	ReDim custom_array(0)

	AddItem custom_array, "test", 99
	AddItem custom_array, "width", 100
	AddItem custom_array, "height", 20
	AddItem custom_array, "dummy_value", "not set"

	For i=1 To Ubound(custom_array)
		MsgBox custom_array(i).str + " = " + CStr( custom_array(i).val)
	Next
	
End Sub

Is it possible to get access to the Clipboard?

The clipboard offers a possibility to pass data to and from a separate process without the need of an intermediate transfer file. A use case could be e.g. an external dialog window (implemented as hta application for example) which can be called from within a CATScript main caller program.

Here are 2 functions which serve this purpose:

Sample code...

Function GetClipboardText() As String
	Dim str As String
	Dim html As HtmlDocument
	Set html = CreateObject("htmlfile")
	str = html.ParentWindow.ClipboardData.GetData("text")
	Set html = Nothing
	
	If (TypeName(str) = "Null") Then
		GetClipboardText = ""
	Else
		GetClipboardText = str
	End If
End Function

Sub CopyToClipboard(ByVal str As String) As String
	Dim html As HtmlDocument
	Set html = CreateObject("htmlfile")
	html.ParentWindow.ClipboardData.SetData "text", str
	Set html = Nothing
End Sub

A practical example of how to use excel from inside a CATScript macro

The following code example illustrates the possibility to call excel directly from CATScript. Excel will be launched and some sample information will then be written to it.

Hint: In this scenario it is important that the current excel file has a unique file name otherwise excel will possibly raise an error.

The code could be handy if e.g. during macro execution some kind of (process-) information needs to be written and kept as evidence/reference for the user.

Sample code...

Class CustomExcelFactory

	' type declaration omitted, will be declared at runtime...
	Private obj_excel, obj_sheet
	Private keep_excel_on_screen As Boolean

	' do something when the class is initialized
	Private Sub Class_Initialize ()
        keep_excel_on_screen = True
    End Sub

    Public Property Let KeepExcelOnScreen (ByVal excel_on_screen As Boolean)
        keep_excel_on_screen = excel_on_screen
    End Property
	
   ' define the public properties
    Public Property Get objSheet ()
        Set objSheet = obj_sheet
    End Property
	
	' // open Excel Application for writing
	' //
	Public Function OpenExcelAppForWriting () As Boolean
		OpenExcelAppForWriting = False
		
		Err.Clear : On Error Resume Next
		Set obj_excel = CreateObject ("EXCEL.Application") 
		
		If Err.Number <> 0 Then
			MsgBox "Warning: Excel application not found.", vbCritical
			Err.Clear : On Error Goto 0
			Exit Function
		End If

		If ( keep_excel_on_screen = True ) Then
			obj_excel.Application.Visible = True
		End If
		
		' create a new workbook
		Err.Clear : On Error Resume Next
		set workbook  = obj_excel.WorkBooks.Add()

		' - disabled- non critical error message !
		' If Err.Number <> 0 Then 
		'     MsgBox "Error when trying to set the current workbook in Excel!"
		' End If
		
		Err.Clear : On Error Goto 0
	   
		Set obj_sheet = obj_excel.ActiveSheet
		obj_sheet.Select
		' obj_sheet.Name = "My Sheet Name"
		
		OpenExcelAppForWriting = True
	End Function

	' // SaveAs... the spreadsheet.
	' //
	Public Sub SaveAsExcelApplication (ByVal fileName As String)
		Dim fs As FileSystem
		Set fs = CATIA.FileSystem

		' ActiveWorkbook.SaveAs:
		'   if the file already exists, the user gets a dialog,
		'   to specify whether to overwrite the file or not...
		' as a workaround, we delete the file prior to the save operation!

		Err.Clear : On Error Resume Next

		If ( fs.FileExists(fileName) ) Then
			fs.DeleteFile fileName
			If Err.Number <> 0 Then
				MsgBox _
					"Error when trying to delete excel file: " + fileName + vBNewLine _
				+	"--> Please close Excel Application and try again!"

				Err.Clear : On Error Goto 0
				Exit Sub
			End If
		End If

		' ??? problem on some workstations / excel versions:
		Err.Clear : On Error Resume Next
		
		obj_excel.ActiveWorkbook.SaveAs fileName

		If Err.Number <> 0 Then
			MsgBox _
				"Error in excel -  operation went wrong for: " + fileName + vBNewLine _
			+	"--> Please save your Excel sheet manually!"
	
			Err.Clear : On Error Goto 0
		End If
		
		Err.Clear : On Error Goto 0
	End Sub

	' // save the spreadsheet and close the workbook if required
	' //
	Public Sub CloseExcelApplication ()
		obj_excel.ActiveWorkbook.Save

		If ( keep_excel_on_screen = False) Then
			obj_excel.ActiveWorkbook.Close
			obj_excel.Application.Quit
		End If

	End Sub

End Class

The following procedure shows how to bring the CustomExcelFactory class to live.

  • After the Dim XLS As CustomExcelFactory initialization statement, the class object is instantiated with the Set XLS = New CustomExcelFactory command.

  • Once the class is available , the 1st command is XLS.OpenExcelAppForWriting which attempts to open or launch excel.

  • With XLS.SaveAsExcelApplication a new spreadsheet file is created.

    Note that it is not required to expose the obj_excel to public, the only object which is required as public is XLS.objSheet which in fact refers to excel’s sheet object itself and thus knows all the sub-commands which can be used on CATScript level to define the spreadsheet properties.

  • Within the For loop some arbitrary data is written as an example and with the XLS.CloseExcelApplication procedure the excel sheet is finally saved to file. Depending on weather the XLS.KeepExcelOnScreen property is true or false Excel stays on screen or is closed again.

Hint: The created excel sheet is saved on the disk and the user has to take care to manage it afterwards.

Sample code...

' -----------------------------------------------------------------------------
' ---  CustomExcelFactory.CATScript
' -----------------------------------------------------------------------------
' (c) 2023, Johann Oberdorfer - Engineering Support | CAD | Software
'     johann.oberdorfer [at] gmail.com
'     www.johann-oberdorfer.eu
' -----------------------------------------------------------------------------
' This source file is distributed under the BSD license.
'   This program is distributed in the hope that it will be useful,
'   but WITHOUT ANY WARRANTY; without even the implied warranty of
'   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
'   See the BSD License for more details.
' -----------------------------------------------------------------------------
' Option Explicit
Language = "VBSCRIPT"

' --- copy the CustomExcelFactory code to here ---
' --- BEGIN ---
' Class CustomExcelFactory
' ...
' End Class
' --- EOF ---

Sub CustomExcelFactory_test ()
	Dim i,j, col_index, rowcnt As Integer
	Dim temp_dir, time_stamp, _
		spread_sheet_file, _
		spread_sheet_path As String
	Dim fs As FileSystem
	Dim str As Folder
	Dim XLS As CustomExcelFactory

	Set XLS = New CustomExcelFactory
	XLS.KeepExcelOnScreen = True

	i = 1
	j = 10
	col_index = 1
	rowcnt = 2

	' get the user's temporary directory ...
	Set fs = CATIA.FileSystem
	Set str = fs.TemporaryDirectory
	temp_dir = CATIA.SystemService.Environ(str.Name)
	time_stamp = Replace (Time, ":", "", 1, -1, vbTextCompare)

	spread_sheet_file = "Excel_Test_" + time_stamp + ".xls"
	spread_sheet_path = fs.ConcatenatePaths(temp_dir, spread_sheet_file)

	If (XLS.OpenExcelAppForWriting() <> True ) Then
		Exit Sub
	End If
	
	' create new file...
	XLS.SaveAsExcelApplication spread_sheet_path

	XLS.objSheet.Name = "Result-List"
	XLS.objSheet.Range("A1:C1").Font.Bold = True
	XLS.objSheet.Range("A1:C1").Interior.ColorIndex = 15 ' COLOR_LIGHTGREY

	' "A" / "B" / "C"
	XLS.objSheet.Cells(1, col_index).Value     = "Count:"     : XLS.objSheet.Columns(col_index).ColumnWidth = 10
	XLS.objSheet.Cells(1, col_index + 1).Value = "Item Name:" : XLS.objSheet.Columns(col_index + 1).ColumnWidth = 40
	XLS.objSheet.Cells(1, col_index + 2).Value = "Value:"     : XLS.objSheet.Columns(col_index + 2).ColumnWidth = 40

	For i = 1 To j
		rowcnt = rowcnt + 1
		XLS.objSheet.Cells(rowcnt, 1).Value = CStr(i) + " of " + CStr(j)
		XLS.objSheet.Cells(rowcnt, 2).Value = "Test " + CStr(i)
		XLS.objSheet.Cells(rowcnt, 3).Value = "dummy " + CStr(i)
		' scroll to current row...
		XLS.objSheet.Cells(rowcnt, 1).Select
	Next

	' once finished, jump to the beginning of the sheet
	XLS.objSheet.Cells(1, 1).Select
	XLS.CloseExcelApplication
	Set XLS = Nothing

	MsgBox _
		"Excel write test finished!", _
	+ 	vbInformation + vbOKOnly, "User Information:"
End Sub

' execution starts here ...
Sub CATMain ()
	Call CustomExcelFactory_test ()
End Sub