Repository navigation
Templates: no console window from a published cui-mini exe, and a demo CUI icon in both templates - #18
Merged
Conversation
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.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three commits; review by commit.
1. No console window from a published cui-mini app (
bb105d1)dotnet new cui-minigenerated a file-based app that set no output type, sodotnet publish MiniApp.csproduced a console-subsystem apphost: the published exe opened a black console behind its native window.#:property OutputType=WinExein the template — the same choicecui-appmakes in its csproj.tools/verify-template.ps1reads 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).dotnet cuiandCUISHARP_HEADLESS=1launch the apphost with redirected pipes.2. A demo icon in both templates (
7727a77)Both templates ship a black
.icoreading CUI (16/24/32/48/64, classic BMP entries, 34,494 B), wired in withApplicationIcon:dotnet new cui-app→<Project>.icobeside the project file; replace it and rebuild to change the icon.dotnet new cui-mini→<name>.csnow generates together with<name>.ico.verify-template.ps1grew a PE resource walk and asserts (Windows) that both published executables carryRT_GROUP_ICONand ≥ 20 KB ofRT_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.mdandSKILL.mdmove 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
ApplicationIconasRT_GROUP_ICON 32512(IDI_APPLICATION), whereas the CUI window class requests group1(cui_app_win32.c:378) and falls back toLoadIconW(NULL, IDI_APPLICATION). Explorer read the embedded icon off the file, while the title bar, taskbar button andAlt+Tabcard still wore the generic Windows logo.src/CuiSharp/Hosting/WindowIcon.cs: loadsRT_GROUP_ICON 32512from the host module viaLoadImageWatSM_CXICON/SM_CXSMICONonce per process and sendsWM_SETICON(ICON_SMALL+ICON_BIG) when the window opens (CuiApp.CreateandRunState.Hooking). Hosts with no embedded icon leave the class default untouched.tools/verify-template.ps1: probes the live window cross-process withWM_GETICON(0x007F,ICON_BIG) and asserts a non-zero handle.Evidence
pwsh tools/verify-template.ps1green end to end (53.6 s), including: mini publishes to one file, subsystem 2,RT_ICON 34,408 Bembedded in both executables, and the visible-window +WM_GETICONprobe.pwsh tools/regen.ps1 -NoNative -NoDiff,dotnet test CuiSharp.slnx -c Release,dotnet format CuiSharp.slnx --verify-no-changesall green.