Skip to content

Commit 8c58c33

Browse files
committed
update cOAPI api and wrapper
1 parent fb68d7e commit 8c58c33

5 files changed

Lines changed: 523 additions & 261 deletions

File tree

Lines changed: 91 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
using EtabSharp.Core.Models;
2+
using EtabSharp.Interfaces.System;
3+
using EtabSharp.System;
24
using ETABSv1;
35
using Microsoft.Extensions.Logging;
46
using Microsoft.Extensions.Logging.Abstractions;
57

68
namespace 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

Comments
 (0)