You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/docs/reference/ironrust/internals.md
+15-18Lines changed: 15 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
<!-- docs-title: Internals -->
2
2
3
-
IronRust compiles RustScript bytecode into a CLR assembly and executes a generated `IPdVmProgram`. The WinForms path adds metadata-derived CLR bindings, object handles, a dedicated STA dispatcher, and an event queue.
3
+
IronRust compiles RustScript bytecode into a CLR assembly and executes a generated `IPdVmProgram`. The WinForms path adds metadata-derived CLR bindings, object handles, callable RSS functions, and a main-form application session on the Runner's STA thread.
4
4
5
5
## Components
6
6
@@ -12,12 +12,14 @@ IronRust compiles RustScript bytecode into a CLR assembly and executes a generat
12
12
|`PdVm.Compiler.PdVmVmbcReader`| Decodes VMBC into `PdVmProgramModel`. |
13
13
|`PdVm.Compiler.PdVmStackAnalyzer`| Computes reachable operand-stack depths before IL emission. |
14
14
|`PdVm.Compiler.PdVmClrCompiler`| Emits and saves the generated CLR program assembly. |
15
-
|`PdVm.Runtime.PdVmProgramBase`| Stores resumable program state and implements shared host-call behavior. |
15
+
|`PdVm.Runtime.PdVmProgramBase`| Stores resumable program state, real call frames, callable values, and the serialized callback queue. |
16
+
|`PdVm.Runtime.IPdVmCallableProgram`| Exposes exported and runtime callable values, managed callback creation, reset, and shutdown. |
17
+
|`PdVm.Runtime.PdVmScriptCallback`| Converts managed event arguments, posts RSS callable invocations, and optionally schedules them on a synchronization context. |
16
18
|`PdVm.Runtime.PdVmAssemblyLoader`| Loads the generated assembly and creates its concrete `IPdVmProgram`. |
|`PdVm.Runtime.PdVmWinFormsDispatcher`|Owns the WinForms STA thread and marshals UI work onto it. |
20
-
|`PdVm.Runtime.PdVmWinFormsEventLoop`|Converts WinForms events into RustScript action strings and tracks form state. |
21
+
|`PdVm.Runtime.PdVmWinFormsApplication`|Attaches a callable program to the current STA context, owns callback resources, registers the main form, and runs its message loop. |
22
+
|`PdVm.Runtime.PdVmWinFormsEventLoop`|Binds WinForms events directly to RSS callable values and tracks close permission. |
21
23
22
24
## Source-to-assembly pipeline
23
25
@@ -99,9 +101,11 @@ The operand stack normally lives in generated CLR locals. IronRust materializes
99
101
100
102
For a saved DLL, `PdVmAssemblyLoader.LoadProgram` registers the output directory for dependency resolution, loads the assembly, finds a non-abstract parameterless type implementing `IPdVmProgram`, and creates it.
101
103
102
-
For direct `.rss` execution, the Runner compiles to a temporary DLL and calls `PdVmAssemblyLoader.CreateProgram` on an in-memory assembly. Both paths then create the console host, register `PdVmDotNetHost.Call` as fallback host dispatch, and call `PdVmExecution.RunAsync`.
104
+
For direct `.rss` execution, the Runner compiles to a temporary DLL and calls `PdVmAssemblyLoader.CreateProgram` on an in-memory assembly. Both paths then create the console host and register `PdVmDotNetHost.Call` as fallback host dispatch.
103
105
104
-
`PdVmExecution.RunAsync` repeatedly calls `RunStep` until the program halts. A waiting status is completed through `IAsyncPdVmHost.WaitAsync`, then passed back with `ResumePending`. `--max-steps` supplies the total instruction limit, while checks inside generated CLR code enforce the remaining budget during a single `RunStep` call.
106
+
For non-WinForms profiles, `PdVmExecution.RunAsync` repeatedly calls `RunStep` until the program halts. A waiting status is completed through `IAsyncPdVmHost.WaitAsync`, then passed back with `ResumePending`. `--max-steps` supplies the total instruction limit, while checks inside generated CLR code enforce the remaining budget during a single `RunStep` call.
107
+
108
+
The WinForms profile requires a callable VMBC v10 program implementing `IPdVmCallableProgram`. The Runner sets a callback error observer, attaches `PdVmWinFormsApplication`, executes top-level RSS setup with `PdVmExecution.Run`, then calls `RunMessageLoop` when `Ui::Show` registered a main form.
105
109
106
110
## CLR values and object handles
107
111
@@ -116,19 +120,12 @@ A generated release call removes both mappings. If the CLR object implements `ID
116
120
117
121
## WinForms threading and events
118
122
119
-
`PdVmWinFormsDispatcher` starts one background thread named `PdVm WinForms UI`, sets it to STA, initializes per-monitor-v2 DPI awareness and WinForms visual styles, creates a hidden `Form` as an invoker, and enters `Application.Run()`.
120
-
121
-
UI-bound exact calls are sent to that thread with `BeginInvoke`. `PdVmDotNetHost.RequiresWinFormsDispatcher` dispatches members from the `System.Windows.Forms` assembly and most `PdVmWinFormsEventLoop` methods there. `Wait` and `WaitTimeout` are deliberately excluded because they block while waiting for queued work.
122
-
123
-
`PdVmWinFormsEventLoop` stores one `FormState` per form in a `ConditionalWeakTable`. Each state contains:
123
+
`Program.Main` carries `[STAThread]` and initializes WinForms before entering the Runner. `PdVmWinFormsApplication.Attach` records the callable program and host in an application session bound to that thread. `Ui::Show(form)` registers one main form; after top-level RSS setup completes, `RunMessageLoop` invokes `Application.Run(form)` on the same thread.
124
124
125
-
-`ConcurrentQueue<QueuedEvent>` for action strings and optional pointer snapshots
126
-
-`AutoResetEvent` to wake `Wait` or `WaitTimeout`
127
-
- the close-permission flag
128
-
- the most recently dequeued pointer snapshot
125
+
Every `BindClick`, `BindShown`, `BindClosing`, pointer, and timer binding accepts an RSS callable value. The application session converts that value into a `PdVmScriptCallback`, schedules it on a `ControlSynchronizationContext` backed by the form's `BeginInvoke`, and tracks both callback and event subscription for disposal.
129
126
130
-
A click or pointer event runs on the UI thread, enqueues a small record, and signals the waiter. The RustScript VM waits on its execution thread, so the WinForms message loop remains available.
127
+
The CLR event handler calls `Post` and returns without running RustScript inside the managed event stack. `PdVmProgramBase` serializes callback work, restores the callable's function or closure environment, executes it through the generated program, and reports asynchronous failures through `CallbackErrorObserver`.
131
128
132
-
`BindClosing` installs a delegate matching the form's `FormClosing` event. Before an explicit close is allowed, the handler sets the event argument's `Cancel` property and queues the configured action. `Close` sets `AllowClose`, then invokes the form's `Close` method on the dispatcher thread.
129
+
`BindClosing` installs a delegate matching the form's `FormClosing` event. Until an explicit close is allowed, the handler sets the event argument's `Cancel` property and posts the bound RSS callable. `Ui::Close` sets `AllowClose` and invokes the form's `Close` method from that callback.
133
130
134
-
This division keeps window creation and application behavior in `examples/dotnet-typed-winforms.rss`; the C# event adapter only provides thread marshalling, action delivery, dialog invocation, pointer snapshots, and close coordination.
131
+
This division keeps window creation and application behavior in `examples/dotnet-typed-winforms.rss`; the C# layer supplies callable adaptation, UI-thread scheduling, dialog invocation, pointer payload conversion, timer subscriptions, and close coordination.
Copy file name to clipboardExpand all lines: content/docs/reference/ironrust/winforms-example.md
+28-29Lines changed: 28 additions & 29 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,7 +30,7 @@ dotnet run --project PdVm.Runner -- run `
30
30
--profile winforms
31
31
```
32
32
33
-
The process remains active until the RustScript event loop handles the close action.
33
+
The Runner executes the top-level RustScript setup, then keeps the process active with the main form's WinForms message loop until the form closes.
34
34
35
35
## Keep the compiled assembly
36
36
@@ -81,7 +81,7 @@ CLR objects cross the RustScript boundary as integer handles. Strings, booleans,
81
81
82
82
Overloaded members receive generated suffixes such as `String`, `Bool`, or `Array`. Use the exact name accepted by the generated module; the example demonstrates names selected from the current .NET metadata, including `NewToolStripMenuItemString`.
83
83
84
-
## Event-loop methods
84
+
## Callable event handlers
85
85
86
86
The example imports the IronRust adapter as `Ui`:
87
87
@@ -91,38 +91,37 @@ use System::Windows::EventLoop as Ui;
91
91
92
92
| Method | What it does |
93
93
| --- | --- |
94
-
|`Ui::Show(form)`| Shows the form on IronRust's WinForms dispatcher thread. |
95
-
|`Ui::BindClick(form, control, action)`| Subscribes to `Click` and queues the supplied action string. |
96
-
|`Ui::BindDialog(form, control, dialog, action)`| Uses the control's click event to queue an action. The RustScript handler decides when to call `ShowDialog`. |
97
-
|`Ui::BindClosing(form, action)`| Intercepts `FormClosing`, cancels that close attempt, and queues the action until RustScript calls `Ui::Close`. |
98
-
|`Ui::Wait(form)`| Waits on the VM execution thread until an action is queued. The UI thread remains available to process Windows messages. |
99
-
|`Ui::WaitTimeout(form, milliseconds)`| Returns a queued action, or an empty string after the timeout. |
94
+
|`Ui::Show(form)`| Registers the main form. After top-level RSS setup halts, the Runner enters `Application.Run(form)` on its STA thread. |
95
+
|`Ui::BindClick(form, control, callable)`| Subscribes to `Click` and posts a zero-argument RSS callable. |
96
+
|`Ui::BindDialog(form, control, dialog, callable)`| Convenience click binding for a zero-argument RSS callable; the handler can call `ShowDialog`. |
97
+
|`Ui::BindShown(form, callable)`| Posts a zero-argument RSS callable when the main form is shown. |
98
+
|`Ui::BindClosing(form, callable)`| Cancels the close attempt and posts a zero-argument RSS callable until that handler calls `Ui::Close`. |
99
+
|`Ui::BindMouseDown/Up/DoubleClick/Leave(form, control, callable)`| Posts an RSS callable with a map containing pointer-event data. |
100
+
|`Ui::BindTimer(form, milliseconds, callable)`| Starts a WinForms timer and posts a zero-argument RSS callable on each tick. |
100
101
|`Ui::ShowDialog(form, dialog)`| Calls `ShowDialog(IWin32Window)` with the form as owner and returns the dialog result name. |
101
-
|`Ui::Close(form)`| Allows closing, then calls `Close` on the dispatcher thread. |
`BindDialog` does not display a dialog itself. It queues the action, then the RustScript branch opens the dialog and handles its result.
127
+
The CLR event adapter returns immediately after posting the callback. IronRust serializes callbacks through the callable program and schedules each handler through the main form's synchronization context, so UI operations execute on the owning STA thread. The application no longer needs a polling loop: each click, close request, pointer event, or timer tick invokes its bound RSS handler directly.
0 commit comments