11using EtabSharp . Core . Models ;
2+ using EtabSharp . Interfaces . System ;
3+ using EtabSharp . System ;
24using ETABSv1 ;
35using Microsoft . Extensions . Logging ;
46using Microsoft . Extensions . Logging . Abstractions ;
57
68namespace EtabSharp . Core ;
79
810/// <summary>
9- /// ETABS application wrapper for v22 and newer
10- /// Provides strongly-typed access to ETABS API using ETABSv1.DLL (.NET Standard 2.0)
11+ /// ETABS application wrapper for v22 and newer.
12+ /// Entry point returned by ETABSWrapper.Connect() and ETABSWrapper.CreateNew().
13+ ///
14+ /// Two access paths:
15+ /// app.Application — lifecycle, visibility, ROT (wraps cOAPI via IApplication)
16+ /// app.Model — all model operations (geometry, loads, analysis, results)
1117/// </summary>
12- public class ETABSApplication : IDisposable
18+ public sealed class ETABSApplication : IDisposable
1319{
1420 private readonly cOAPI _api ;
1521 private readonly cSapModel _sapModel ;
@@ -20,52 +26,58 @@ public class ETABSApplication : IDisposable
2026
2127 private readonly ILogger < ETABSApplication > _logger ;
2228
23- // NEW: Add the model wrapper
29+ private readonly Lazy < IApplication > _application ;
2430 private readonly Lazy < ETABSModel > _model ;
2531
2632 /// <summary>
27- /// Gets the ETABS model instance, providing access to the building analysis and design data.
33+ /// Application-level control: lifecycle (start/exit), visibility (hide/unhide),
34+ /// version info, and ROT registration.
35+ /// Wraps cOAPI.
36+ /// </summary>
37+ public IApplication Application => _application . Value ;
38+
39+ /// <summary>
40+ /// Model operations: geometry, properties, loads, analysis, results, design.
41+ /// Wraps cSapModel.
2842 /// </summary>
2943 public ETABSModel Model => _model . Value ;
3044
3145 /// <summary>
32- /// Gets the ETABS major version (e.g., 22 for v22.7.0)
46+ /// ETABS major version number (e.g., 22 for v22.7.0).
3347 /// </summary>
3448 public int MajorVersion => _majorVersion ;
3549
3650 /// <summary>
37- /// Gets the full ETABS version (e.g., "22.7.0")
51+ /// Full ETABS version string (e.g., "22.7.0").
3852 /// </summary>
3953 public string FullVersion => _fullVersion ;
4054
4155 /// <summary>
42- /// Gets the API version number
56+ /// OAPI version number reported by the running ETABS instance.
4357 /// </summary>
4458 public double ApiVersion => _apiVersion ;
4559
4660 /// <summary>
47- /// Gets the DLL name being used
61+ /// Always "ETABSv1. DLL" for v22+.
4862 /// </summary>
4963 public string DllName => "ETABSv1.DLL" ;
5064
5165 /// <summary>
52- /// Always true for v22+ (.NET Standard 2.0)
66+ /// Always true for v22+ (.NET Standard 2.0 API).
5367 /// </summary>
5468 public bool IsNetStandard => true ;
5569
5670 /// <summary>
57- /// Gets strongly-typed cOAPI object for ETABS v22+
58- /// Use this for application-level operations (file, program control, etc.)
59- /// </summary>
60- public ETABSv1 . cOAPI API => _api ;
61-
62- /// <summary>
63- /// Gets strongly-typed cSapModel object for ETABS v22+
64- /// Use this for model operations (geometry, loads, analysis, results, etc.)
71+ /// Direct access to the underlying cSapModel for advanced usage.
72+ /// Prefer Model.* properties over this wherever possible.
6573 /// </summary>
66- public ETABSv1 . cSapModel SapModel => _sapModel ;
74+ public cSapModel SapModel => _sapModel ;
6775
68- internal ETABSApplication ( ETABSv1 . cOAPI api , int majorVersion , double apiVersion , string fullVersion ,
76+ internal ETABSApplication (
77+ cOAPI api ,
78+ int majorVersion ,
79+ double apiVersion ,
80+ string fullVersion ,
6981 ILogger < ETABSApplication > ? logger = null )
7082 {
7183 _api = api ?? throw new ArgumentNullException ( nameof ( api ) ) ;
@@ -75,8 +87,11 @@ internal ETABSApplication(ETABSv1.cOAPI api, int majorVersion, double apiVersion
7587 _fullVersion = fullVersion ;
7688 _logger = logger ?? NullLogger < ETABSApplication > . Instance ;
7789
78- // Initialize the model wrapper with lazy loading
79- _model = new Lazy < ETABSModel > ( ( ) => new ETABSModel ( _sapModel , _logger ) ) ;
90+ _application = new Lazy < IApplication > (
91+ ( ) => new ETABSApplicationManager ( _api , _logger ) ) ;
92+
93+ _model = new Lazy < ETABSModel > (
94+ ( ) => new ETABSModel ( _sapModel , _logger ) ) ;
8095
8196 _logger . LogInformation (
8297 "Connected to ETABS v{Version}, API v{ApiVersion}" ,
@@ -85,93 +100,82 @@ internal ETABSApplication(ETABSv1.cOAPI api, int majorVersion, double apiVersion
85100 }
86101
87102 /// <summary>
88- /// Gets API information
103+ /// Returns a summary of API connection info.
89104 /// </summary>
90- public ETABSApiInfo GetApiInfo ( )
105+ public ETABSApiInfo GetApiInfo ( ) => new ETABSApiInfo
91106 {
92- return new ETABSApiInfo
93- {
94- MajorVersion = MajorVersion ,
95- FullVersion = FullVersion ,
96- ApiVersion = ApiVersion ,
97- DllName = DllName ,
98- IsNetStandard = IsNetStandard
99- } ;
100- }
107+ MajorVersion = MajorVersion ,
108+ FullVersion = FullVersion ,
109+ ApiVersion = ApiVersion ,
110+ DllName = DllName ,
111+ IsNetStandard = IsNetStandard
112+ } ;
101113
102114 /// <summary>
103- /// Safely executes an API function with error handling
104- /// ETABS v22+ throws catchable exceptions for unsupported functions
115+ /// Safely executes an API call with error handling and logging.
116+ /// ETABS v22+ throws catchable exceptions for unsupported functions.
105117 /// </summary>
106- /// <typeparam name="T">Return type</typeparam>
107- /// <param name="apiCall">The API function to execute</param>
108- /// <param name="functionName">Optional name for better error messages</param>
109- /// <returns>Result of the API call</returns>
110- public T ExecuteSafely < T > ( Func < T > apiCall , string functionName = null )
118+ public T ExecuteSafely < T > ( Func < T > apiCall , string ? functionName = null )
111119 {
112120 try
113121 {
114122 return apiCall ( ) ;
115123 }
116124 catch ( Exception ex )
117125 {
118- var funcName = functionName ?? "API function" ;
119- _logger . LogError ( ex , "Error calling {FunctionName}: {Message}. This function may not be supported in your version of ETABS." , funcName , ex . Message ) ;
126+ _logger . LogError ( ex ,
127+ "Error calling {FunctionName}: {Message}. This function may not be supported in your version of ETABS." ,
128+ functionName ?? "API function" , ex . Message ) ;
120129 throw ;
121130 }
122131 }
123132
124133 /// <summary>
125- /// Safely executes an API action with error handling (void return)
126- /// ETABS v22+ throws catchable exceptions for unsupported functions
134+ /// Safely executes a void API call with error handling and logging.
127135 /// </summary>
128- /// <param name="apiCall">The API action to execute</param>
129- /// <param name="functionName">Optional name for better error messages</param>
130- public void ExecuteSafely ( Action apiCall , string functionName = null )
136+ public void ExecuteSafely ( Action apiCall , string ? functionName = null )
131137 {
132138 try
133139 {
134140 apiCall ( ) ;
135141 }
136142 catch ( Exception ex )
137143 {
138- var funcName = functionName ?? "API function" ;
139- _logger . LogError ( ex , "Error calling {FunctionName}: {Message}. This function may not be supported in your version of ETABS." , funcName , ex . Message ) ;
144+ _logger . LogError ( ex ,
145+ "Error calling {FunctionName}: {Message}. This function may not be supported in your version of ETABS." ,
146+ functionName ?? "API function" , ex . Message ) ;
140147 throw ;
141148 }
142149 }
143150
144151 /// <summary>
145- /// Gets the underlying cOAPI object (for advanced usage)
146- /// </summary>
147- public cOAPI GetRawAPI ( ) => _api ;
148-
149- /// <summary>
150- /// Gets the underlying cSapModel object (for advanced usage)
151- /// </summary>
152- public cSapModel GetRawModel ( ) => _sapModel ;
153-
154- /// <summary>
155- /// Closes the ETABS application
152+ /// Exits the ETABS application.
153+ /// Prefer using Application.ApplicationExit() for explicit control.
154+ /// This method exists for IDisposable and convenience.
156155 /// </summary>
156+ /// <param name="savePrompt">
157+ /// If true, ETABS prompts to save unsaved changes.
158+ /// If false (default), exits immediately — correct for Mode B hidden instances.
159+ /// </param>
157160 public void Close ( bool savePrompt = false )
158161 {
159- if ( ! _disposed )
162+ if ( _disposed ) return ;
163+
164+ try
160165 {
161- try
162- {
163- _api . ApplicationExit ( savePrompt ) ;
164- _logger . LogInformation ( "ETABS application closed" ) ;
165- }
166- catch ( Exception ex )
167- {
168- _logger . LogWarning ( ex , "Error closing ETABS: {Message}" , ex . Message ) ;
169- }
166+ _application . Value . ApplicationExit ( savePrompt ) ;
167+ _logger . LogInformation ( "ETABS application closed" ) ;
168+ }
169+ catch ( Exception ex )
170+ {
171+ _logger . LogWarning ( ex , "Error during Close: {Message}" , ex . Message ) ;
170172 }
171173 }
172174
173175 /// <summary>
174- /// Implements IDisposable to close ETABS when disposed
176+ /// Disposes this wrapper. Calls ApplicationExit(false) — does NOT save.
177+ /// For Mode A (attach) flows, do NOT dispose — release COM manually via ComCleanup.
178+ /// For Mode B (hidden) flows, disposing is correct and will exit the hidden instance.
175179 /// </summary>
176180 public void Dispose ( )
177181 {
@@ -183,4 +187,20 @@ public void Dispose()
183187
184188 GC . SuppressFinalize ( this ) ;
185189 }
190+
191+ #region Advanced / Raw Access
192+
193+ /// <summary>
194+ /// Gets the raw cOAPI object.
195+ /// Use only when IApplication does not cover what you need.
196+ /// </summary>
197+ internal cOAPI GetRawAPI ( ) => _api ;
198+
199+ /// <summary>
200+ /// Gets the raw cSapModel object.
201+ /// Use only when Model.* does not cover what you need.
202+ /// </summary>
203+ internal cSapModel GetRawModel ( ) => _sapModel ;
204+
205+ #endregion
186206}
0 commit comments