Skip to content

Templates: no console window from a published cui-mini exe, and a demo CUI icon in both templates - #18

Merged
albertwoo merged 3 commits into
mainfrom
fix/mini-template-console-window
Nov 12, 2026
Merged

albertwoo merged 3 commits into
mainfrom
fix/mini-template-console-window

Conversation

@albertwoo

@albertwoo albertwoo commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Three commits; review by commit.

1. No console window from a published cui-mini app (bb105d1)

dotnet new cui-mini generated a file-based app that set no output type, so dotnet publish MiniApp.cs produced a console-subsystem apphost: the published exe opened a black console behind its native window.

  • #:property OutputType=WinExe in the template — the same choice cui-app makes in its csproj.
  • tools/verify-template.ps1 reads the PE subsystem byte out of the published binary and fails unless it is 2 (Windows GUI); it fails on the pre-fix template (subsystem 3).
  • Headless stdio path unaffected: dotnet cui and CUISHARP_HEADLESS=1 launch the apphost with redirected pipes.

2. A demo icon in both templates (7727a77)

Both templates ship a black .ico reading CUI (16/24/32/48/64, classic BMP entries, 34,494 B), wired in with ApplicationIcon:

  • dotnet new cui-app → <Project>.ico beside the project file; replace it and rebuild to change the icon.
  • dotnet new cui-mini → <name>.cs now generates together with <name>.ico.
  • No 256px entry: it would add 262 KB to every published app for a size no shell asks a desktop exe for.

verify-template.ps1 grew a PE resource walk and asserts (Windows) that both published executables carry RT_GROUP_ICON and ≥ 20 KB of RT_ICON — a plain apphost has no resource directory at all, so the check can only pass with the icon embedded. The mini generation check now expects .cs + .ico; docs/SIZE.md, README.md and SKILL.md move with it (mini publish 1,163,264 → 1,198,080 B, app publish 2,244,608 → 2,282,496 B).

3. Put the embedded icon on the window (2fc8e24)

The .NET apphost embeds ApplicationIcon as RT_GROUP_ICON 32512 (IDI_APPLICATION), whereas the CUI window class requests group 1 (cui_app_win32.c:378) and falls back to LoadIconW(NULL, IDI_APPLICATION). Explorer read the embedded icon off the file, while the title bar, taskbar button and Alt+Tab card still wore the generic Windows logo.

  • src/CuiSharp/Hosting/WindowIcon.cs: loads RT_GROUP_ICON 32512 from the host module via LoadImageW at SM_CXICON/SM_CXSMICON once per process and sends WM_SETICON (ICON_SMALL + ICON_BIG) when the window opens (CuiApp.Create and RunState.Hooking). Hosts with no embedded icon leave the class default untouched.
  • tools/verify-template.ps1: probes the live window cross-process with WM_GETICON (0x007F, ICON_BIG) and asserts a non-zero handle.

Evidence

  • pwsh tools/verify-template.ps1 green end to end (53.6 s), including: mini publishes to one file, subsystem 2, RT_ICON 34,408 B embedded in both executables, and the visible-window + WM_GETICON probe.
  • pwsh tools/regen.ps1 -NoNative -NoDiff, dotnet test CuiSharp.slnx -c Release, dotnet format CuiSharp.slnx --verify-no-changes all green.

binwenw added 2 commits November 12, 2026 08:28
The generated file-based app set no OutputType, so dotnet publish produced
a console-subsystem apphost: the published exe opened a black console
behind its window. Set #:property OutputType=WinExe in the template, the
same choice cui-app makes in its csproj, and have verify-template.ps1
read the PE subsystem out of the published binary so the promise cannot
regress silently. The headless stdio path is unaffected: dotnet cui and
CUISHARP_HEADLESS=1 launch the apphost with redirected pipes.

Verified: tools/verify-template.ps1 green end to end, including one file
at 1,163,264 B, subsystem 2 (Windows GUI), and the visible-window probe.
Both templates now carry a black .ico reading CUI, wired in with
ApplicationIcon: cui-app ships <Project>.ico beside the project file,
cui-mini generates <name>.ico beside <name>.cs. Replacing the file and
rebuilding changes the exe icon, and the window follows it because the
CUI window class loads the executable's own icon resource before
falling back to the system default. The icon holds 16/24/32/48/64 as
classic BMP entries (34 494 B): a 256 entry would have added 262 KB to
every published app for a size no shell asks a desktop exe for.

verify-template.ps1 grew a PE resource walk and asserts, on Windows,
that both published executables carry RT_GROUP_ICON and at least 20 KB
of RT_ICON; a plain apphost has no resource directory at all, so the
check can only pass with the icon embedded. The mini generation check
now expects the .cs and the .ico, and docs/SIZE.md carries the two new
publish sizes.
@albertwoo albertwoo changed the title Open no console window from a published cui-mini app Templates: no console window from a published cui-mini exe, and a demo CUI icon in both templates Nov 12, 2026
An apphost embeds ApplicationIcon as RT_GROUP_ICON 32512 — IDI_APPLICATION.
The CUI window class looks for group 1 and falls back to LoadIconW(NULL,
IDI_APPLICATION), the system's generic logo, so a published app showed its
real icon on the file in Explorer and the generic one on the title bar,
taskbar button and Alt+Tab card: Explorer reads the resource, the shell's
window decorations ask the window.

CuiApp now loads RT_GROUP_ICON 32512 from the host module with LoadImageW
at SM_CXICON and SM_CXSMICON and sends WM_SETICON when the window opens —
in Create for the loop-style host and in Hooking, which runs on the first
frame of Run and on live attach. The handles are process-lifetime, loaded
once; a host with no embedded icon keeps the system default untouched.

The verify gate's WM_GETICON probe asks the live window from another
process (0x007F — the earlier 0x0033 is not WM_GETICON, which made the
first gate version probe a nonexistent message) and polls, because the
icon goes in on the first frame. Proven on a published AOT exe: both
WM_GETICON(ICON_SMALL) and WM_GETICON(ICON_BIG) answer with real handles.
@albertwoo
albertwoo merged commit 0122ae1 into main Nov 12, 2026
22 of 23 checks passed
@albertwoo
albertwoo deleted the fix/mini-template-console-window branch November 12, 2026 01:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant