terminal
terminal copied to clipboard
Add --wait command line parameter
Add ability to wait for console close for scripts
I would like to add a command line parameter that causes wt.exe invocations to wait until the newly created window closes before returning.
Perhaps something like:
wt.exe --wait [other args]
This would block the caller of wt.exe until the newly created window closes. Useful for scripts that want output visible in another window but needs to know when the launched command exits.
Proposed technical implementation details (optional)
So for the record, I don't think this is possible.
For some background: there are two "subsystems" of processes on Windows. "Console" apps, which are attached to a console by default, and "Windows" apps, which aren't attached to a console. Windows apps are expected to have a HWND and be interactable through their own windows. wt
is a "Windows" application, not a console one, because we don't want a new conhost.exe
spawning every time you open wt.exe
.
I believe that both powershell
and cmd.exe
won't wait for a Windows subsystem process to exit, by default. When they detect the exe they're about to launch is a Windows one, they'll create the process, and immediately return to the prompt. For console subsystem applications, they'll wait until the process exits before returning to the prompt.
So this isn't really something that can be solved by wt.exe
.
Now that I'm thinking on this, I wonder how feasible this is with the legacy conhost. If you're a commandline exe, and you spawn a child commandline exe in a new console (with a new conhost window), then you should be able to wait for that process. Might need to do it with Win32 APIs, but that should be possible. I'm gonna tag in @miniksa here, because we'll want to make sure that's still possible to do once defterm (#492) lands.
The trick is getting at the child process ID. If you launch wt -- {some process}
, then the child process is wt.exe
, but the one you really want to wait on is {some process}
. That's a thinker.
Thanks for the detailed explanation. First, let me say what I really want, and you can tell me if it's possible or not. :)
Current Scenario
We have some simulators that rely on a launching program to launch both a workload application and an external simulator process and coordinating communication between those two child processes. The workload application can inherit the command console of the launching program. However, I ideally (if executed to begin with in Windows Terminal), I would like the simulator process to open a new pane that is automatically closed after process termination.
I currently do some variation of:
-
Workload: CreateProcess with
cmd /C <process_exe> [process_args] | tee.exe workload.log
-
Sim: CreateProcess with
cmd /C start "Simulator Window" /WAIT cmd /C <process_exe> [process_args] | tee simulator.log
At end of workload I can wait for the Sim "process" (actually a cmd.exe process) to finish (or kill it, etc.)
Desired Scenario
What I really want is for (#4472) to be implemented and, if launched within a WT session, have the Sim launched in a separate pane.
And, what I really, really want is for the Visual Studio Integrated Terminal to be replaced with Windows Terminal and have all of this work within VS. But, that's an issue for another day. :)
Possible Solution
Given that cmd and powershell have no way of waiting for a windows subsystem app to finish, I propose adding a wtc.exe
console application interface that communicates with wt.exe
. This wtc.exe
would take mostly the same parameters as wt.exe
, but would also provide the needed --wait
argument. It could then use some private IPC mechanism to retrieve the child process ID (or handle) launched by wt.exe and wait for it to complete.
For example, I could use the following to launch the Sim workload:
wtc.exe --wait --session %WT_SESSION_ID% split-pane -p %WT_PROFILE_ID% -- <sim_command> [sim_command_args]
We've discussed (in specs and as a team) adding a wtc
in the past, though it's always been in the context of "a helper for working with wt
from the commandline", and less "a launcher for wt.exe
". Our vision with wtc
was more for things like wtc --version
, wtc --help
, etc. - things that usually would be printed to the console, but we have to use a gross message box for, since we're a windowed application.
I think part of the problem with your proposal is: what happens when multiple subcommands are provided to wtc
? Ex: wtc -s 0 --wait new-tab commandline1.exe ; split-pane commandline2.exe ; etc.exe
? Do we wait for all of them? The first one?
Uhg this gets even more complicated. If you spawn wt -w 0 child.exe
, then the child process isn't actually spawned as a child of the wt.exe
you're spawning. It's going to be spawned as a child of the wt that ends up actually hosting it.
So in a diagram, parent.exe
is running in a terminal window.
wt.exe (1)
└── parent.exe
parent.exe now tries to create a new child in the same terminal window
wt.exe (1)
└── parent.exe
└── wt.exe -w 0 child.exe
However, that second wt.exe
instance is actually just going to tell the first one to create the child process, so the tree will end up looking like:
wt.exe (1)
├── parent.exe
└── child.exe
Getting the parent to wait on the child process is gonna be really challenging here.
Our vision with wtc was more for things like wtc --version, wtc --help, etc. - things that usually would be printed to the console, but we have to use a gross message box for, since we're a windowed application.
That makes sense, too.
I think part of the problem with your proposal is: what happens when multiple subcommands are provided to wtc? Ex: wtc -s 0 --wait new-tab commandline1.exe ; split-pane commandline2.exe ; etc.exe ? Do we wait for all of them? The first one?
Naively, I would wait for all of them. Or, disallow multiple subcommands with --wait and throw an error.
parent.exe now tries to create a new child in the same terminal window
wt.exe (1) └── parent.exe └── wt.exe -w 0 child.exe
The parent would actually spawn wtc.exe
, which is a different process than wt.exe (1)
. The wtc.exe
instance would communicate with wt.exe (1)
to launch the process and retrieve the pid(s) and wait for it(them). I'm fairly confident this would work fine. I don't think you have to be a parent process to wait on another process - is this a false assumption?
wt.exe (1)
├── parent.exe
| └── wtc.exe
└── child.exe
Alternatively, instead of --wait
, directly expose a method to return the pid of the launched process from wtc.exe
(return value?). This would definitely require limiting to one launched process at a time.
Alternatively, instead of
--wait
, directly expose a method to return the pid of the launched process fromwtc.exe
(return value?). This would definitely require limiting to one launched process at a time.
I don't like this. I don't want PIDs or hierarchy as an API. We want the ability and freedom to restructure how our processes launch at any given time in the future. I've seen too many things in the OS need to change their hierarchy, split into processes, combine processes, or what not for security or performance reasons over time that I am not willing to commit to a direct dependency on the process model.
So for the record, I don't think this is possible.
For some background: there are two "subsystems" of processes on Windows. "Console" apps, which are attached to...
Yeah this is down the right path. The thing is that we are beholden to what the caller shell is doing in terms of WaitForSingleObject
or not. It's really just a CMD.exe policy that it will WaitForSingleObject
on the process handle for any application that is !IMAGE_SUBSYSTEM_WINDOWS_GUI
(and note there are more than 2 choices.... technically.... though today really only CUI and GUI are used...) What each individual shell decides to do is up to it.
So while wt.exe
as a IMAGE_SUBSYSTEM_WINDOWS_GUI
will for sure not block cmd.exe
and a wtc.exe
with IMAGE_SUBSYSTEM_WINDOWS_CUI
stamped in would.... I can't say (without more research than I'm willing to do in this instant) what it would do for Python, Perl, PowerShell, and so on.
If we had a wtc.exe
eventually... that, by nature of being part of the Windows Terminal package/suite of applications, could know the intricate details of process hierarchy and IPC to appropriately WaitForSingleObject
or WaitForMultipleObjects
itself on the correct subprocess/thread/etc... And therefore if you did wtc.exe --wait
, it could opaquely wait on the correct thing and I wouldn't be too upset by that.
Current Scenario
We have some simulators that rely on a launching program to launch both a workload application and an external simulator process and coordinating communication between those two child processes. The workload application can inherit the command console of the launching program. However, I ideally (if executed to begin with in Windows Terminal), I would like the simulator process to open a new pane that is automatically closed after process termination.
I currently do some variation of:
- Workload: CreateProcess with
cmd /C <process_exe> [process_args] | tee.exe workload.log
- Sim: CreateProcess with
cmd /C start "Simulator Window" /WAIT cmd /C <process_exe> [process_args] | tee simulator.log
At end of workload I can wait for the Sim "process" (actually a cmd.exe process) to finish (or kill it, etc.)
Do note that in the Default Application world, which I'm still working on, that launching the child cmd.exe
detached would end up coming back into a new tab or pane on the already opened Windows Terminal
.
(In specific, if you had registered Windows Terminal as your default application and you had it set to have "inbound connections" drop into new panes... then any detached console application or any fresh console application started on the system that is bound to be interactive would be relayed from the old conhost.exe
in the box to whatever handler is registered to take it... for instance Windows Terminal, and display per whatever preferences the user set. And of course, this would be preference based, not explicitly configurable per script or scenario like calling wtc.exe
from a script would be.)
And, what I really, really want is for the Visual Studio Integrated Terminal to be replaced with Windows Terminal and have all of this work within VS. But, that's an issue for another day. :)
I thought Visual Studio's Integrated Terminal WAS now using the Windows Terminal control...
Do note that in the Default Application world, which I'm still working on, that launching the child cmd.exe detached would end up coming back into a new tab or pane on the already opened Windows Terminal.
That's great, but I have a lot of tabs / panes open already. I think I need the ability to control which current pane gets split. Maybe that's another feature request.
I thought Visual Studio's Integrated Terminal WAS now using the Windows Terminal control...
Perhaps it is, but is there any way to split panes in the integrated terminal? I really want the integrated terminal to obey all of the settings that are in place for Windows Terminal.
<off-topic>
I thought Visual Studio's Integrated Terminal WAS now using the Windows Terminal control...
Perhaps it is, but is there any way to split panes in the integrated terminal? I really want the integrated terminal to obey all of the settings that are in place for Windows Terminal.
They're using the same core that we implemented, but that doesn't include support for things like panes, tabs, etc. Their control is implemented in WPF, because they couldn't get WinUI ingested into VS just for the terminal control.
</off-topic>
Given that cmd and powershell have no way of waiting for a windows subsystem app to finish
In cmd, START /WAIT notepad
waits for the notepad process to finish. And if a batch file runs notepad
, then it waits even without START /WAIT
.
In PowerShell, Start-Process -Wait notepad
likewise waits.
Given that cmd and powershell have no way of waiting for a windows subsystem app to finish
In cmd,
START /WAIT notepad
waits for the notepad process to finish. And if a batch file runsnotepad
, then it waits even withoutSTART /WAIT
.In PowerShell,
Start-Process -Wait notepad
likewise waits.
That's a good point. Using either start
or Start-Process
allows one to wait for any launched GUI application to exit.
Given this fact, I probably don't require having a console wtc.exe
front-end if the existing wt.exe
were to handle --wait
. Although, as stated earlier, having console output from wtc.exe
may be useful.
I did notice that start /WAIT
will return the return value of the launched process. This isn't necessarily required in my scenario, but I can see how that would be useful. So, there probably needs to be some thought to how combining --wait with creating multiple tabs / panes would work. I suppose the last process to exit would have it's return value propagated? Maybe return the first non-zero value? Not sure what makes sense.
@KalleOlaviNiemitalo thanks for the correction. I forgot about that flag when looking yesterday. I guess the spirit of it is that I cannot guarantee what any particular shell would do. But if it's capable of waiting on a process handle no matter what, that makes it easier.
One last requirement I thought of:
If wt.exe
/ wtc.exe
is alive and waiting for processes to complete, and that process is forcefully killed, it should also kill all of the processes that it is waiting for. This will probably require some explicit handling as there is no parent-child relationship of the processes being waited on.
One last requirement I thought of:
If
wt.exe
/wtc.exe
is alive and waiting for processes to complete, and that process is forcefully killed, it should also kill all of the processes that it is waiting for. This will probably require some explicit handling as there is no parent-child relationship of the processes being waited on.
That's usually possible with a job object so it shouldn't be tough for either the caller or for wt.exe
/wtc.exe
to classify things launched downstream into a job.
You know, I've thought about this for a long time. I no longer hate it. I'm going to put it on the backlog.
I think there needs to also be an option to wait until the terminal window is open. Not until it closes. This would entirely be for use with the -w flag though, so maybe just build the wait into that.
Hello,
i'm having the need to wait for the launched wt session to be over, in order to do some subsequent tasks in a script. So i second this proposal for a --wait
parameter, or something similar.
In the meanwhile i ask: is there any way at all to do this, as of today? Is there any way (for example) to determine the PID of the launched session (whether it's a window, tab, or panel) so that i can wait for that process to be over? I'm using powershell.
Solutions like listing every running process with WindowsTerminal.exe
as a parent process and filtering on the command line (for example filtering for myapp.exe
if i launched wt.exe myapp.exe
) wouldn't work if i don't specify something to launch or if i launch the same program multiple times.
Hello, i'm in need of a wait command too as i figured out that using Start /wait otherbatchscript.bat
while the script is elevated opens the "normal" CMD window and not the terminal even tho i got the terminal set to being the default terminal application