terminal icon indicating copy to clipboard operation
terminal copied to clipboard

Terminal doesn't respect "start /max" and "/min" parameters when running a console app as default terminal

Open bzzrak opened this issue 2 years ago • 5 comments

Windows Terminal version

1.11.3471.0

Windows build number

10.0.22000.434

Other Software

Seemingly any console application (cmd, powershell, python, batch file) -- I'm using python as an example here.

Steps to reproduce

  1. set terminal as default terminal
  2. open command prompt in terminal
  3. run for example "start /max python.exe" (or powershell, or cmd, or some batch file)
  4. the window will show windowed, not maximised

Expected Behavior

New window starts maximised, as it does when the default Windows console is set. The correct behaviour also happens if you run wt.exe itself, i.e. "start /max wt python" image image

Actual Behavior

New window starts windowed image

bzzrak avatar Jan 13 '22 11:01 bzzrak

The /min parameter is even worse. "start /min python.exe" starts the classic console, while "start /min wt python.exe" does make a minimised WT window, but you can't switch to it for some reason.

image image

bzzrak avatar Jan 13 '22 11:01 bzzrak

Alright, so there are three elements here. From the bottom up:

  • start /min wt python.exe we're tracking in #9053, so feel free to continue that element there.
  • "start /min python.exe opens conhost" This is kinda by design for now. There are a LOT of apps that run commandline tools in "hidden" console windows, so defterm is pretty aggressive about not attaching to those kinds of launches. We don't necessarily want to pop up a Terminal window when a console window wouldn't have been visible to the user.
  • "start /max python.exe doesn't open the Terminal maximized" now, that's a real issue. Or at least, it's something we should have an answer for.

We may need to pass some blob of parameters to defterm invocations describing how the terminal application should be launched. That might take care of both /min and /max.

Lemme add @miniksa, see what he thinks

(fat fingered enter, sorry about that)

zadjii-msft avatar Jan 13 '22 12:01 zadjii-msft

Without knowing the details of what's possible, I'd expect Terminal to honor relevant fields in STARTUPINFO after a handoff from conhost. When a new tab (not a window) is created, I'd expect it to use lpTitle and -- if they're still relevant in any way -- dwXCountChars, dwYCountChars, and dwFillAttribute. When a new window is created, I'd expect it to honor the window's initial show state, position, and size: wShowWindow, dx, dy, dwXSize, and dwYSize. If honoring a setting isn't possible or isn't relevant when using Terminal as the default, please document it for STARTUPINFO, or document it in the console docs.

I understand skipping the handoff to Terminal if wShowWindow is SW_HIDE (0). A hidden Terminal window would be dysfunctional since a console app can't programmatically restore the window, and neither can the user. I don't understand skipping the handoff for SW_SHOWMINIMIZED (2), SW_MINIMIZE (6), SW_SHOWMINNOACTIVE (7), and SW_FORCEMINIMIZE (11). In principle, the user can easily restore a minimized terminal. Maybe this was implemented because Terminal doesn't support wShowWindow properly. For example, as mentioned above, start /min wt is broken. It's better to use the classic console until that gets fixed.

eryksun avatar Jan 13 '22 13:01 eryksun

Without knowing the details of what's possible, I'd expect Terminal to honor relevant fields in STARTUPINFO after a handoff from conhost. When a new tab (not a window) is created, I'd expect it to use lpTitle and -- if they're still relevant in any way -- dwXCountChars, dwYCountChars, and dwFillAttribute. When a new window is created, I'd expect it to honor the window's initial show state, position, and size: wShowWindow, dx, dy, dwXSize, and dwYSize. If honoring a setting isn't possible or isn't relevant when using Terminal as the default, please document it for STARTUPINFO, or document it in the console docs.

I get doing lpTitle. That should be easy even if inserting a tab into an existing window. I guess same for dwFillAttribute.

But for the other ones related to sizing and visibility... I think what I'd do is... if the inbound connection specified any of those, I'd ensure the monarch/peasant granted them a fresh window to manipulate however they specified without tampering with the user's existing window. So they can only "join" automatically if they're not going to mess with what is existing and are flexible with the layout.

I understand skipping the handoff to Terminal if wShowWindow is SW_HIDE (0). A hidden Terminal window would be dysfunctional since a console app can't programmatically restore the window, and neither can the user. I don't understand skipping the handoff for SW_SHOWMINIMIZED (2), SW_MINIMIZE (6), SW_SHOWMINNOACTIVE (7), and SW_FORCEMINIMIZE (11). In principle, the user can easily restore a minimized terminal. Maybe this was implemented because Terminal doesn't support wShowWindow properly. For example, as mentioned above, start /min wt is broken. It's better to use the classic console until that gets fixed.

This was just a matter of scoping it. You're right, Terminal doesn't support wShowWindow completely/properly yet and we hadn't thought through all those scenarios, so the minimum scope to get the "hard part" of the actual handoff out of the way was my goal. Additionally, when I was doing my testing, two things stood out to me: 1. Applications that don't set any of the flags or any settings and ask for a completely blank console session are most commonly destined for an interactive session. 2. Applications that mess with all the flags during the ::CreateProcess call are usually extraordinarily sensitive to changes and performance characteristics, so I didn't want to impact them right away.

miniksa avatar Mar 11 '22 17:03 miniksa

Brief notes from 1-1:

  • conhost reads the Cac, decides if it wants to handoff. It does not drain the Cac from the driver
  • openconsole gets handed off to, it reads the driver. The message in flight has the original Cac

so OpenConsole can read the startup info, without rev'ing the defterm interface. We know this works because the OpenConsole does get the title from the STARTUPINFO, so OpenConsole does get that info somehow.

Rev'ing ITerminalHandoff is okay, since that's OpenConsole->WindowsTerminal and that's all in the package.


Verbatims

  • start /max python
  • start minimized? - maybe best we not
  • I'd expect it to use lpTitle
  • I'd expect it to honor the window's initial show state, position, and size: wShowWindow, dx, dy, dwXSize, and dwYSize. If honoring a setting isn't possible or isn't relevant when using Terminal as the default, please document it for STARTUPINFO, or document it in the console docs.
  • I'd ensure the monarch/peasant granted them a fresh window to manipulate however they specified without tampering with the user's existing window. So they can only "join" automatically if they're not going to mess with what is existing and are flexible with the layout.
  • if we get the lnk filename or the exe path from ITerminalHandoff, we can cobble together a fake profile (based on the console settings in the lnk or registry) that "looks-like-" what conhost would have looked like for that lnk or exe
    • font
    • colors (? how will this work with schemes?)
    • cursor
    • icon

Todo's

  • [ ] start /max python
  • [ ] STARTUP_INFO members:
    • [x] lpTitle
    • [ ] wShowWindow
    • [ ] dx
    • [ ] dy
    • [ ] dwXSize
    • [ ] dwYSize
    • [ ] When x/y/w/h are specified, and the monarch wants to attach to an existing window, instead create a new window with those args.
  • [ ] Properties from lnk/reg:
    • [ ] font
    • [ ] colors (? how will this work with schemes?)
    • [ ] cursor
    • [ ] icon
      • Probably able to fake with start "C:\WINDOWS\system32\notepad.EXE" cmd

Notes

  • in srvinit.cpp@ConsoleEstablishHandoff, we attempt to handoff->EstablishPtyHandoff to the Terminal. There, we have a PCONSOLE_API_MSG connectMessage we can use.
  • (elsewhere) IoDispatchers::ConsoleHandleConnectionRequest is responsible for unpacking the connection request. It creates a CONSOLE_API_CONNECTINFO via ConsoleInitializeConnectInfo(PCONSOLE_API_MSG,...)
    • srvinit.cpp@ConsoleInitializeConnectInfo shows how we unpack/pack that thing.
    • pay attention to the Cac->ConsoleInfo member, that's a Settings, a la the console settings.
    • srvinit.cpp@ConsoleAllocateConsole shows how we create a conhost with that
    • Especially Settings::ApplyStartupInfo
    • refer to https://github.com/microsoft/terminal/blob/7b775684e8206abdd12a6720252d0888f1c9d6d0/src/interactivity/win32/SystemConfigurationProvider.cpp#L172-L188 for the icon loading
    • OpenConsole!615061

zadjii-msft avatar Jul 14 '22 17:07 zadjii-msft

Note: For discussion:

I'm leaning towards closing this out with the combo of #14222 and #13838. We can pass the startup info into the Terminal now, but I'm reluctant to change the behavior where defterm filters out start /min cli-app.exe invocations. start /min wt cli-app.exe will work, and start /max cli-app.exe will both launch into the terminal, and start /min cli-app.exe will open a minimized conhost running cli-app.exe. As further noted in https://github.com/microsoft/terminal/pull/14222#issuecomment-1499276623

zadjii-msft avatar Apr 06 '23 15:04 zadjii-msft