Skip to content

Docs: hosting CliHost from a GUI-subsystem (WinExe) app leaks literal ANSI; AttachConsole alone is not enough #38

Description

@tig

What happened

I hosted CliHost inside a WinForms app (tig/mcec#252): OutputType=WinExe, with the classic hybrid pattern of AttachConsole(ATTACH_PARENT_PROCESS) when args are present so --help/--version/--opencli print to the parent terminal.

--version and --opencli were fine, but myapp help printed the rendered help with ANSI escapes as literal text ([39m[49m[1m## Commands...), and the mangled lines wrapped, wrecking the table layout.

Root cause

MarkdownRenderer.RenderToAnsi writes VT escape sequences produced by Driver.ToAnsi(). Every shipped host (greet, clet, the survey example in #9) is a console-subsystem app, which inherits a console session whose output mode the shell/terminal already set up (VT processing on). A GUI-subsystem process that attaches to a console does not get ENABLE_VIRTUAL_TERMINAL_PROCESSING on its output, so conhost renders the escape bytes as text.

The fix on the host side is one call after AttachConsole:

IntPtr stdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (GetConsoleMode(stdout, out uint mode)) {
    SetConsoleMode(stdout, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
}

Suggestions

  1. Docs: add a "Hosting from a GUI app (WinExe)" section to the README/library spec: AttachConsole + enable VT processing, plus the caveat that the shell prompt returns immediately for a WinExe. None of the examples cover this shape, and it is a natural one for TG.Cli (an existing GUI app that wants a scriptable CLI surface without becoming a console app).
  2. Library (optional but nicer): MarkdownRenderer.RenderToAnsi already fixes up the console when writing to the real console (Console.OutputEncoding → UTF-8). Enabling VT processing on Windows in that same spot would make every host correct by construction, including hybrids, with no behavior change for console apps (the flag is already set there).

Happy to PR either.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions