main
Drew Owens 0.9.26 source 11bf910 9d ago

Launch, sign-in and readiness — swx

Read this before starting SOLIDWORKS, while waiting through a launch or a 3DEXPERIENCE sign-in, or when deciding whether it is ready. Part of the solidworks-bridge skill — SKILL.md beside this folder has the rules that never bend. Trust each verb's own reply (_hint, errorCode) over anything written here.

Install, launch, sign-in

  • This edition cannot be launched by COM, so do not try. The install here is SOLIDWORKS Connected / Makers (3DEXPERIENCE), and swx_status reports canLaunchProgrammatically:false. COM can ATTACH to a session that is already running; it cannot create one. That is a property of the edition, not a limitation of the bridge, so there is no argument or retry that changes it.

  • The launch that works is the Platform's own shortcut. swx_start invokes the 3DEXPERIENCE Platform .lnk, which starts CATSTART.exe, which starts SWXDesktopLauncher.exe, which starts sldworks.exe. The launcher chain then exits — once sldworks.exe is up there is no launcher process left to poll or to reap.

  • The shellExecute route hands back a real handle, proven live 2026-09-11. It invokes through ShellExecuteExW with SEE_MASK_NOCLOSEPROCESS; the live run got a process handle back (CATSTART pid 131272, creation time 1789148101) and that chain reached the launcher's Run Begin. This matters because the bridge's law is no handle, no kill: it may only clean up a chain the invoke itself handed back. On this machine that world is confirmed.

  • stage:"helperSignIn" means a human has to type a password — you cannot. A cold launch can stop at the 3DEXPERIENCE ID window: a NATIVE WebView2 window, class DSYSysLoginPanelWebView2Class, title "Login | 3DEXPERIENCE ID | Dassault Systemes", owned by SWXDesktopLauncher.exe in the bridge's own chain. UIA sees NO controls inside it, so nothing can read or fill it — this bridge included. As of 0.6.0 the bridge recognises the window, reports helperSignIn, PAUSES every launch deadline while it is on screen (a waiting human is not a stall), never kills or escalates the chain, and toasts the user that sign-in is needed. Your move is to keep polling and, if the user asks what to do, tell them to sign in and to tick Remember me once so later launches do not stop here. The bridge never asks for, stores or transmits a password.

  • How long helperSignIn lasts depends on the user answering the window, not on any timer the bridge owns. Do not convert it into a failure.

  • Read launch.stage and act on it, from swx_status or from swx_start:

    stage What to do
    invoked The route was just invoked. Poll swx_status.
    launcherStarted Chain running, Run Begin not reached. This is the stage that stalls; the bridge cleans up and tries the next route itself. Do not invoke the shortcut any other way.
    runBegin The chain is really building. Keep polling; sldworks.exe appears within seconds.
    helperSignIn Only the user can clear it. Poll; tell them to look at their screen.
    sldworksUp The application exists, COM does not answer yet. Keep polling.
    attaching Polling for the COM server. Keep polling; do not launch again.
    attached COM is usable. This is the only success — carry on.
    stalled That route stalled and its chain was cleaned up. The bridge is trying the next route. Nothing for you to retry.
    exhausted Every route was tried and none attached. ASK THE USER to start SOLIDWORKS from the Start Menu or the Platform.

    The three milestones that matter operationally are runBegin (the chain is really building), sldworksUp (the application exists) and attached (COM is usable, and the only success).

  • stillLaunching:true means a launch this bridge started is still in flight. Calling swx_start again does NOT start a second chain — it attaches to the one in flight. That is deliberate: four launcher chains once ended up on a user's desktop because a caller retried. Polling with swx_start is therefore safe, and a second invocation by any other route is not.

  • swx_stop quits ONLY a session with zero documents open, and force does not waive that (force waives the UNSAVED question only). If documents are open, close them first, or drain leaked conversion temporaries with swx_close_import_temps.

  • Treat a quit as close to a one-way door. On this edition relaunching after a quit takes 1-3 minutes and can stop at the sign-in window again, which only the user can answer. Do not quit to tidy up.

Is it ready?

  • attached is not ready. MEASURED 2026-10-01: document commands sent 8 s after COM attach crashed SOLIDWORKS while its 3DEXPERIENCE add-in was still initialising. swx_start now reports stage:"starting" (stillStarting:true) until SOLIDWORKS has finished starting, then stage:"ready"; swx_status says solidworks.ready and what it is based on (readiness.basedOn, readiness.performanceLog.verdict and why, and the rule). EVERY verb that reaches SOLIDWORKS waits — the gate is the default since 0.9.5, and only a short list of verbs that never reach COM (status, start, describe, the disk and window verbs, kill) is exempt. They refuse host_app_starting with retryAfterSeconds until then — wait that long and call again; never try to get around it. readinessTimedOut:true means it has been over five minutes: look at the user's screen (a dialog, a sign-in) rather than forcing anything.

  • How ready is decided. The performance log only speaks for THIS session (written since the process started); a log from an earlier session is notThisSession, never complete. COM's StartupProcessCompleted is true before the start finishes (measured), so it is never enough alone on a machine whose log writes 3DEXPERIENCE markers. An add-in loaded on demand after the start (a quiet log, an add-in other than 3DEXPERIENCE, COM true) does not make a started session "starting" again. A session that never loads the platform add-in (it can be disabled) is ready once its log is quiet and COM agrees; a log still being written holds the start. A session older than ten minutes whose COM says the start completed is never held by the log unless add-in loads are still appearing (longRunningSession), and a session seen ready stays ready across a bridge update.

  • state:"unverifiable" — nothing can verify the start. After the grace (readsAllowed:true) READ verbs run; anything that creates, opens, saves, closes or changes a document refuses with startingUnverifiable:true ("cannot verify startup completed"). The clock never authorises a document command.

  • Quitting during startup: under userAuthorized:true, swx_stop with maxRung:"c" or "d" runs with the COM rungs skipped — the window-message rungs need neither COM nor a finished start.

  • bridge_readiness (ab-level, never spawns anything) answers "is SOLIDWORKS installed / is the bridge warm" — use it for what-do-I-have questions.

  • swx_readiness is the bridge's own read-only probe; swx_status is the everyday state check (detection + COM attach + open docs); swx_get_app_state is the one to POLL while something long runs.

  • If SOLIDWORKS is not installed verbs return errorCode:"host_app_not_installed". Dassault publishes NO silent installer — desktop trial serials come from a reseller, the Makers edition from the 3DEXPERIENCE Platform store. Don't tell the user to go download it; surface the returned _hint.

  • If SOLIDWORKS is not running, swx_start starts it — including the Connected editions. Pass a reason (it is written for the person whose desktop this is, and it is the only thing this verb needs — starting an application creates nothing and destroys nothing).

    • On classic desktop installs it attaches over COM.
    • On 3DEXPERIENCE / Connected editions (including Design Professional for Makers) it invokes the shortcut the Platform installed, which runs CATSTART.exe -run SWXDesktopLauncher.exe with that user's tenant and registry. That is the launch Dassault sanctions.
    • A cold Connected start runs 1-3 minutes and may stop at a 3DEXPERIENCE sign-in only the user can answer. swx_start returns started:true, stillLaunching:true while it is coming up — that is not a failure. Poll swx_status until running:true, or call swx_start again, which ATTACHES to what is already coming up. waitSeconds:<n> (up to 240) blocks instead of polling. Never invoke the launcher any other way meanwhile — two launches means two sign-in windows on somebody's desktop.
    • Calling swx_start during a launch launches NOTHING (v0.4.0). It answers stillLaunching:true, launchedNow:false with the live stage (launcherStarted / runBegin / helperSignIn / sldworksUp / attaching), its age, and what to do — and it needs no reason while an attempt is in flight, so polling with it is always safe. swx_status carries the same launch block.
    • A stalled launcher recovers itself. The launcher chain sometimes starts and then stops at SecurityContext: without ever logging Run Begin — it then sits idle forever and SOLIDWORKS never appears. A supervisor inside the bridge watches the launcher's OWN log, and on a stall it ends only the CATSTART/SWXDesktopLauncher chain it started itself and tries the next launch route, remembering whichever one works. There is nothing for you to retry, and nothing for you to clean up.
    • NO HANDLE, NO KILL — and the same rule for evidence. A launcher log is read as this bridge's own only when the launcher's own writing-thread id resolves to a process in our chain, or it is the sole candidate with no other launch running; otherwise unattributedLog:true and it is not used. On a route that cannot say what it started, no log is attributed at all. One consequence worth knowing: if SOLIDWORKS comes up on explorer or cmdStart, the launch SUCCEEDS and the route is never remembered — attached proves SOLIDWORKS is usable, not that our route did it.
    • NO HANDLE, NO KILL. A process is only ever ended when the INVOKE ITSELF handed back its root (ShellExecuteExW's process handle, or Start-Process -PassThru's pid) and it descends from that root. The explorer and cmdStart routes cannot say what they started, so a stall on either reports cleanup:"notAttributable" and terminates nothing — the response says a launcher chain may remain that the bridge cannot identify, which the user can end from Task Manager. If a route leaves something the bridge cannot account for, the machine STOPS rather than starting another chain beside it.
    • If SOLIDWORKS is running but unreachable, swx_start will not start a second one. It answers host_app_hung (Windows says the window is not responding AND a COM call exceeded its budget — only the user can end it), host_app_exhausted (NewDocument came back with no document — the one signal that proves it; close the bridge's own documents, then ASK THE USER to restart, and do not retry in a loop), or host_app_com_unreachable (usually a sign-in window: ask the user to look at their screen). swx_status.solidworks.memoryAdvisory reports a very large session as an OBSERVATION — a 13 GB SOLIDWORKS can be perfectly healthy, and this bridge no longer calls one out of room on a threshold.
    • "Not responding" is not "dead". swx_status.solidworks.verdict is busy / dead / unknown, from the CPU and memory DELTA across two reads (cpuActiveSeconds, memoryDeltaMB). A session at 17.9 GB was not-responding with a COM timeout for five minutes while burning 70% of a core — and it recovered. busy means tell the user to wait; only dead (no CPU over ≥15s, memory flat, no dialog) means only they can end it. One reading never says dead — poll again.
    • After a failed attempt the bridge waits (host_app_launch_backoff, growing with each consecutive failure) and then tries ONE route rather than re-sweeping the plan. Retrying in a loop is how four launcher chains ended up on somebody's desktop; the honest move while it waits is to ASK THE USER to start SOLIDWORKS from their Start Menu.
    • Crash-reporter recovery ships OFF (launch.crashRecovery:"off"). When armed it clicks the crash reporter's "Restart SOLIDWORKS Design" button once — but only on a window OWNED by the SOLIDWORKS being launched, and only when ab structurally confirms the button exists. It is disabled by default because the reply shape it reads has never been seen on a real desktop.
  • NEVER kill the 3DEXPERIENCE launcher daemons. 3DEXPERIENCELauncher.exe, 3DEXPERIENCELauncherSysTray.exe and 3DEXPERIENCELauncherService.exe are the Platform's own background services and carry the user's Platform session. They are not required for a launch (a successful launch on 2026-09-04 ran with no Backbone at all), so killing one buys nothing and breaks something that is not yours — and a real user launch rebuilds them, which is the fix if they are genuinely broken. The bridge's own kill allowlist is exactly two images, CATSTART.exe and SWXDesktopLauncher.exe, and only instances it created itself, terminated by pid. Do not reach for taskkill / process_kill against any of this yourself; sldworks.exe included (that is swx_kill, and it is gated behind the user's explicit opt-in).

    • errorCode:"host_app_launch_blocked" now means only one thing: the bridge could not FIND a shortcut, not that the edition cannot be launched. swx_status reports solidworks.shortcut and solidworks.launchRoute so you can see what it found; if the user has a shortcut elsewhere, SWX_SOLIDWORKS_SHORTCUT=<path to the .lnk> points the bridge at it. Do not run sldworks.exe yourself via shell_execute or launch_process — launching it DIRECTLY, bypassing the launcher chain, is what produces the "SOLIDWORKS Design must be launched from the 3DEXPERIENCE Platform" modal.
  • waitingOn:"userSignIn" on swx_start / swx_status means a 3DEXPERIENCE ID login is up and the launch is waiting for the user to sign in. signInWindow is {hwnd, title, ownerImage, host, recognizedBy}; it was a bare title before 0.9.23. Any login window on the machine counts, found by class or title OR by content (an Edit "Email or username" or "Password" in it). Measured 2026-10-12: the platform updater SWXDesktopUpdate.exe showed a login titled just "3DEXPERIENCE" (host:"desktopUpdate") and the Visualize start was parked behind it. swx_start {app:"visualize"} now says stage:"waitingOn" with visualize.parkedBehind instead of stage:"launching". Only the user can answer it; tell them, and poll swx_status.

  • ab's policy keeps the password with the user (measured 2026-10-12). pup_credential_reveal refuses a bridge: "requires a VERIFIED local transport … this request arrived with origin "bridge"". Since 0.9.25 swx_sign_in PREPARES the page before it asks for the password: it fills the user name from the vault's host list (no secret, no toast) and presses Continue. A refused reveal then answers sign_in_vault_policy with abSaid, pagePrepared {page, userNameFilled} and waysOut. The user types the password in the window that is left on page 2; nothing is retried or worked around. ab issue #237 asks for a fill verb that keeps the secret inside ab. Other vault refusals (consent pending or denied) carry pagePrepared too.

  • Page 2, read right (0.9.26, measured 2026-10-12). A page that holds the password box is page 2, even though it also shows the user-name box. That box is prefilled and READ-ONLY, so the bridge leaves it alone (a read-only refusal means "prefilled") and goes on to ask for the password once. cookieBanner is true only for accept/reject BUTTONS; a "Manage cookies" link is not a banner. A failed set is never blamed on a banner, and no cookie toast goes out unless a banner is there. "Remember me" is toggled in the background and reported from its read-back state. The updater's tree is cold (14 nodes, the frame only) until probed, then stays awake (~37 nodes).

  • Signing in for the user — swx_sign_in {reason} (0.9.13). Only for a launch this bridge started whose own launcher is showing the 3DEXPERIENCE ID window. It reads the window's inventory (control types, names, IsPassword — never values; also in swx_status.signInInventory every time the window appears), takes the login from the user's pup vault ON THEIR LAPTOP through ab (pup_credential_reveal — the user clicks a consent toast "Sign in to SOLIDWORKS with your saved 3DEXPERIENCE login" EVERY time; an unanswered toast is sign_in_consent_pending, and calling again re-attaches to it), types it through UI Automation, ticks "Remember me" if there is one, presses the sign-in button and checks the window actually closed. The password never appears in its reply, the log or the ledger. It fails closed: sign_in_credential_missing (the reply carries the import command for the user), sign_in_window_unrecognized (with the inventory), sign_in_needs_user (a code / second step: the user is notified), sign_in_rejected — never retried; later calls refuse sign_in_rejected_before until the user says the saved password changed (userConfirmedNewPassword:true, on their word only). swx_start {signIn:"auto"} lets the bridge do it once by itself; the default is to wait for the user.

  • The measured login flow (two pages, a lazy tree, a cookie banner, real keystrokes only while the user is idle) is in the solidworks-sign-in skill, which ships with this one.

  • Any login window, on the user's say-so: swx_sign_in {reason, userAuthorized:true} also answers a 3DEXPERIENCE ID login window the bridge's launch did not raise — SOLIDWORKS Visualize's, or the platform updater's. Add window:"visualize" / "solidworks" / "desktopUpdate" / an hwnd when several are open; the reply's window names the owning process. A named hwnd is checked by its CONTENT and never refused because a census missed it; with neither field in it the reply is sign_in_window_not_a_login, with found (every control looked for and what came back).

  • When the tree shows only the frame (the updater's login, measured: 14 nodes), swx_sign_in finds each control with desktop_find_control. It looks up by automation id first, then role and exact name, then role and name-contains, and never by a role alone. It clears each field and then sets it by automation id. The user name cannot be read back on that host (readBack: "unreadable"), and "Remember me" is a label whose state cannot be read (rememberTicked: null). pages[].located says how each page was read.