Commit c37e5c5
v0.10.2: fix run-script .csx hang on OpenDoc6 (Roslyn await was bouncing script body across ThreadPool workers)
Closes FR_runscript_opendoc6_hangs_nonpumping_apartment.md — bug
reported by SWFormat 2026-07-16, reproduced live against SW 2026
rev 34.2.1.
Bug: a .csx calling swApp.OpenDoc6(diskPath, ...) via run-script
hung indefinitely. Doc opened on SW's side, but call never returned.
Same OpenDoc6 from typed plugin commands (list-configs) worked
fine.
Root cause: Program.cs's Main has no [STAThread] — combridge is MTA
default. ScriptHost.RunAsync had:
var state = await script.RunAsync(globals);
Roslyn's Script<T>.RunAsync returns a Task whose continuations use
TaskScheduler.Default (ThreadPool) when no SynchronizationContext
is set. So the script body could execute on any ThreadPool worker —
NOT the thread that constructed the SolidWorks RCW earlier in
plugin.CreateGlobals(comRoot). OpenDoc6 is thread-affine: SW's
out-of-proc server invokes callbacks back to the calling thread
during the call. Wrong thread = callback lost = both sides wait
forever. Plugin commands don't hit this because their RunAsync
methods have no awaits before their COM calls — everything stays
on Main's thread.
Fix: change the inner Roslyn call to synchronous:
var state = script.RunAsync(globals).GetAwaiter().GetResult();
Forces the script body to run on the caller's thread — same thread
as Main = same thread as the RCW = no thread-affinity mismatch =
no deadlock. ScriptHost.RunAsync's outer async signature unchanged.
Scope: plugin-agnostic ScriptHost code, so every Windows plugin's
run-script benefits. Simple reads (RevisionNumber, GetFirstDocument)
had worked before because they don't callback — this is why the bug
was elusive. Any COM API with progress UI or save dialogs
(OpenDoc6, Save3, SaveAs3, PrintOut4, Workbooks.Open, etc.) was
silently affected until now. VBScript path unaffected (IActiveScript
is synchronous by design).
Verified live: same reproducer that hit 30s timeout on v0.10.1 now
exits 0 with correct output on v0.10.2 (opens the part, closes it,
returns).
Regression check: list-configs / list-components / active-config
still work; run-script still honors ScriptArgs / Stdin / exit-code
propagation from v0.9.0 and v0.8.2; VBScript engine unaffected.
Mirrored to D:\Dev\ScripTree\lib\combridge\ and
R:\ScripTree\lib\combridge\ per the CLAUDE.md deployment mandate.
FR moved to Complete/. Lesson captured at
C:/personal_rag/claude_code/lesson_20260716_roslyn_script_runasync_await_bounces_thread_breaks_com_affinity.md
so the next Roslyn-hosting Windows tool doesn't re-derive the same
30-second-timeout diagnostic.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 26427d9 commit c37e5c5
2 files changed
Lines changed: 109 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
7 | 105 | | |
8 | 106 | | |
9 | 107 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
190 | 190 | | |
191 | 191 | | |
192 | 192 | | |
193 | | - | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
194 | 204 | | |
195 | 205 | | |
196 | 206 | | |
| |||
0 commit comments