WinForms Host
The WinForms host embeds the engine inside a WinForms window and drives it from the form's UI thread. Its UI is deliberately minimal: a panel the game renders into and a working Pause/Resume button, ready to be extended with your own controls.
Use It
The host is opt-in and runs only on Windows:
dnx 2dog add --winforms
dotnet new 2dog -n MyGame --winforms true # new project
dotnet run --project MyGame.winformsThe repository's own instance is demos/showcase/showcase.winforms.
Capabilities
- Embeds Godot in a native WinForms window.
- Interleaves Godot frames and WinForms events on one STA UI thread.
- Lets event handlers safely access the scene tree.
- Builds on non-Windows systems with
EnableWindowsTargeting, although it cannot run there.
How It Works
Godot 4.7 supports embedding out of the box via the --wid <window_id> argument – the same mechanism the Godot editor uses for its embedded game window. Given a native window handle, the engine creates its main window as a borderless popup owned by that handle instead of a regular top-level window. Because 2dog hosts pass arguments to Godot verbatim, no engine or API changes are involved:
_engine = new Engine("MyGame", args:
[
"--wid", Handle.ToInt64().ToString(CultureInfo.InvariantCulture),
"--resolution", $"{panel.ClientSize.Width}x{panel.ClientSize.Height}",
"--position", "0,0",
]);Three consequences shape the host code:
- The host owns geometry. The embedded popup lives in screen coordinates and Godot refuses
window_set_sizefor it, so the form drives the window with rawSetWindowPosfromResizeandLocationChangedhandlers – exactly how the editor drives its embedded game window. - The host owns the frame loop. A classic WinForms game loop pumps
Iteration()fromApplication.Idlewhenever the message queue is empty, so Godot frames and UI events interleave on one STA thread, and WinForms event handlers can touch the scene tree directly. - Teardown happens before the owner window dies. The form disposes the instance and engine in
OnFormClosing, while its own handle still exists.
The Pause button toggles SceneTree.Paused (the actual gameplay pause) and sends the GodotInstance.Pause()/Resume() application-lifecycle notification straight from its click handler - the UI thread is the pump thread, so game state (including the scene tree via engine.Tree) is safe to touch from event handlers.
Limitations
- Windows only. For a cross-platform GUI host, use the Avalonia host; for the same embedding under the Windows App SDK, use the WinUI 3 host.
- The embedded window always draws above the form's client area, so WinForms controls cannot overlap the game rectangle - the Avalonia host composites instead, which lifts this restriction.
--widmarks the instance as embedded (Engine.is_embedded_in_editor()returnstrueto scripts).