A single VBA module to embed in Excel that attaches to a running CSI SAFE instance and writes one or more SAFE database tables into a worksheet at a tab + top-left coordinate you pass in as function parameters.
It is written against the COM API documented in
CSI_API_SAFE_v1_html/ (SAFEv1.dll, SAFE 20) and its behaviour is informed
by the reference script SAFE maximum moment search 2025-07-14.py (whose
get_table_view / get_table_edit / set_table / apply_table_edit
workflow is replicated here).
| File | Purpose |
|---|---|
SAFE_Export.bas |
The VBA module. Import into Excel (Alt+F11 → File → Import File…). |
README.md |
This document. |
- Start SAFE and open the model you want to read from. Leave SAFE running. (The script attaches — it never starts SAFE, never opens a model, and never closes it.)
- Add the SAFE reference in the VBA IDE (once):
Alt+F11→Tools → References…→ tickSAFEv1(orBrowse…and selectSAFEv1.tlbfrom the SAFE installation folder). The reference is read from this IDE setting — no file path is hardcoded in the module. - Import the module into the Excel workbook:
Alt+F11→File → Import File…→ selectSAFE_Export.bas. - Run the macro
DemoExport(F5), or call the functions yourself (see below).
n = ExportSAFETables(Tables, SheetName, StartCell, StackHorizontally, IncludeHeader)| Parameter | Meaning |
|---|---|
Tables |
One table key (String), a comma-separated String, or an array of keys: Array("…","…") |
SheetName |
Destination worksheet (“tab”) — created if it does not exist |
StartCell |
Top-left coordinate, e.g. "B3" |
StackHorizontally |
False = stack tables downwards (default); True = side by side |
IncludeHeader |
Write the column-header row (default True) |
' Single table, own sheet:
ExportSAFETables "Element Forces - Area Shells", "Forces", "B2"
' Several tables stacked on one sheet:
ExportSAFETables Array("Point Object Connectivity", _
"Area Load Assignments - Uniform"), _
"SAFE Tables", "A1"
' Only include specific load cases in result tables (e.g. just LIVE):
ExportSAFETables "Element Forces - Area Shells", "Forces", "B2", LoadCases:="LIVE"
' ...or a list: LoadCases:=Array("LIVE", "DEAD")ListSAFETables(SheetName, StartCell)— dumps every available table key (exact strings to use inExportSAFETables).WriteSAFETable(TableKey, Data, UnlockModel)— bonus: writes a 2-D array back into SAFE and applies it (edit workflow, see below).SAFEConnect()/SAFEDisconnect()— attach / release the running SAFE.ShowLog()/ClearLog()/GetLog()— diagnostics.DemoExport,DemoExportSingle,DemoListTables— ready-made examples.
Use the exact strings shown in SAFE Display → Show Tables, for example:
Point Object ConnectivityArea Load Assignments - UniformElement Forces - Area Shells(needs analysis results)Joint DisplacementsLoad Combination Definitions
Run DemoListTables to see the exact keys available in your model.
The script deliberately tolerates SAFE’s quirks instead of aborting:
- Nonzero return = “nothing to show”.
GetTableForDisplayArrayreturns a nonzero code when a table is empty / analysis hasn’t been run. This is treated as a warning (logged, a marker is written to the sheet) and the loop continues to the next table. - Empty tables. Headers-only or empty tables never crash the writer.
- Flattened data. SAFE returns data as a one-dimensional array, row by
row. Rows are rebuilt from the number of columns
(
FieldsKeysIncluded), with bounds guards in case the array is shorter than expected. - All columns / all objects. A single blank
FieldKeyListentry requests all columns;GroupName = ""(or"All") returns all objects. - Reference from the VBA IDE. The SAFE type-library reference is added in
the Excel VBA IDE (
Tools → References…); no file path is hardcoded. Only the COM ProgIDs are kept in the Configuration Zone. - Attach ≠ close. When attached, the script never calls
ApplicationExit(that would close the user’s SAFE session). - Edit workflow guards (
WriteSAFETable):GroupNameis inactive in this SAFE release (pass""); the model must be unlocked (SetModelIsLocked(False)); the column count must match or SAFE rejects the write;ApplyEditedTablesmay leave the model corrupted on a fatal error, so the error/fatal counts are checked andCancelTableEditingis called to clear the pending-edit buffer. Save the SAFE model before writing back. - Load-case filter (
LoadCasesparameter): implemented withSetLoadCasesSelectedForDisplay, which only affects result tables. The previous selection is saved and restored afterwards (also on error). Empty parameter = all load cases (SAFE's default). Quirk: a single blank string selects no cases.
All warnings go to the VBA Immediate window (Ctrl+G) and can be shown
with ShowLog().
- Tested assumptions come from the SAFE 20 API docs (
SAFEv1, v1.23.0.0) and the reference Python script; later SAFE versions may rename tables. - The connect step tries
GetObject(, "CSI.SAFE.API.ETABSObject")first, then theCSI.SAFE.API.Helper(viaNew Helper) as a fallback. If neither finds a running instance, make sure SAFE is open with a model and that theSAFEv1reference is ticked inTools → References…. - Reading tables works whether or not the model is locked; only the
write-back (
WriteSAFETable) needs it unlocked.