Why
EtabExtension.CLI Closed Alpha remediation has reached a real lifecycle boundary that EtabSharp 0.3.5-beta cannot express safely.
Live evidence in tadoEng/EtabExtension.CLI#15 showed the managed path Process.Start(ETABS.exe) -> ETABSWrapper.ConnectToProcess(pid) could return an object whose SapModel existed but was not API-ready: cSapModel.InitializeNewModel threw and ApplicationExit(false) returned -1 on the same freshly attached object. Cardex ETABS 23.3 evidence confirms cHelper.CreateObject(path) starts the target program, cOAPI.ApplicationStart() is the explicit startup call, and InitializeNewModel is for a properly created API object.
The CLI therefore needs to own the raw CSI lifecycle (cHelper / cOAPI) and exact OS-process identity, then hand the same already-created, already-started cOAPI to EtabSharp for model/domain abstractions. EtabSharp 0.3.5-beta has no public way to do that: ETABSApplication(cOAPI, ...) is internal.
Do not solve this by using CreateNew(startApplication:true): current CreateNew logs but does not propagate nonzero ApplicationStart, and the CLI needs the raw return code as part of its safety contract. Do not use ConnectToProcess: its GetObjectProcess path can fall back to ROT GetObject, which is incompatible with exact-PID ownership.
Required API
Add one deliberately low-level public factory, conceptually:
public static ETABSApplication WrapExisting(
cOAPI api,
int majorVersion,
double apiVersion,
string fullVersion,
ILogger<ETABSApplication>? logger = null)
Exact naming may differ, but the semantics must not.
Contract
This method is pure wrapping. It must:
- validate
api and supplied metadata;
- construct the existing
ETABSApplication around that exact cOAPI;
- use the existing
api.SapModel path;
- preserve the exact object identity supplied by the caller.
It must not:
- call
cHelper.CreateObject*;
- call
ApplicationStart;
- call
GetObject, GetObjectProcess, or any ROT attach;
- enumerate or select ETABS processes;
- call
Hide / Unhide;
- call
ApplicationExit;
- silently create or attach to another ETABS instance.
Keep the ETABSApplication constructor internal; the public entry point should communicate the non-owning/raw-interop intent clearly.
Ownership / disposal
The caller owns application lifecycle. Wrapping an existing cOAPI must not imply that EtabSharp owns process startup or shutdown. Current ETABSApplication.Dispose() only releases COM references; preserve that non-exiting behavior.
Document that callers must perform lifecycle calls themselves when using this factory.
Verification
- API is additive; existing
Connect / ConnectToProcess / CreateNew behavior remains unchanged in this issue.
- Add focused tests/documentation proving the new factory does not bootstrap or attach another application.
- Build/test both supported targets.
- No live ETABS mutation is needed merely to prove the factory surface.
- Use Cardex for any CSI API fact referenced during implementation; do not commit proprietary/generated Cardex content.
Downstream
This is a blocking dependency for EtabExtension.CLI TAD-19 / PR #15. After this change is reviewed, release it as the next beta package version (expected 0.3.6-beta, unless repository release policy dictates otherwise), then the CLI can implement raw CSI startup + exact OS ownership + InitializeNewModel before wrapping the proven-ready handle.
Why
EtabExtension.CLI Closed Alpha remediation has reached a real lifecycle boundary that EtabSharp 0.3.5-beta cannot express safely.
Live evidence in
tadoEng/EtabExtension.CLI#15showed the managed pathProcess.Start(ETABS.exe) -> ETABSWrapper.ConnectToProcess(pid)could return an object whoseSapModelexisted but was not API-ready:cSapModel.InitializeNewModelthrew andApplicationExit(false)returned-1on the same freshly attached object. Cardex ETABS 23.3 evidence confirmscHelper.CreateObject(path)starts the target program,cOAPI.ApplicationStart()is the explicit startup call, andInitializeNewModelis for a properly created API object.The CLI therefore needs to own the raw CSI lifecycle (
cHelper/cOAPI) and exact OS-process identity, then hand the same already-created, already-started cOAPI to EtabSharp for model/domain abstractions. EtabSharp 0.3.5-beta has no public way to do that:ETABSApplication(cOAPI, ...)is internal.Do not solve this by using
CreateNew(startApplication:true): currentCreateNewlogs but does not propagate nonzeroApplicationStart, and the CLI needs the raw return code as part of its safety contract. Do not useConnectToProcess: itsGetObjectProcesspath can fall back to ROTGetObject, which is incompatible with exact-PID ownership.Required API
Add one deliberately low-level public factory, conceptually:
Exact naming may differ, but the semantics must not.
Contract
This method is pure wrapping. It must:
apiand supplied metadata;ETABSApplicationaround that exactcOAPI;api.SapModelpath;It must not:
cHelper.CreateObject*;ApplicationStart;GetObject,GetObjectProcess, or any ROT attach;Hide/Unhide;ApplicationExit;Keep the
ETABSApplicationconstructor internal; the public entry point should communicate the non-owning/raw-interop intent clearly.Ownership / disposal
The caller owns application lifecycle. Wrapping an existing
cOAPImust not imply that EtabSharp owns process startup or shutdown. CurrentETABSApplication.Dispose()only releases COM references; preserve that non-exiting behavior.Document that callers must perform lifecycle calls themselves when using this factory.
Verification
Connect/ConnectToProcess/CreateNewbehavior remains unchanged in this issue.Downstream
This is a blocking dependency for EtabExtension.CLI TAD-19 / PR #15. After this change is reviewed, release it as the next beta package version (expected
0.3.6-beta, unless repository release policy dictates otherwise), then the CLI can implement raw CSI startup + exact OS ownership +InitializeNewModelbefore wrapping the proven-ready handle.