WaitForSingleObject and CONIN$ #11311

Closed
opened 2026-01-31 02:44:05 +00:00 by claunia · 12 comments
Owner

Originally created by @vefatica on GitHub (Nov 7, 2020).

Environment

Microsoft Windows 10 Pro for Workstations
10.0.18363.1139 (1909)
WindowsTerminalPreview_1.4.2652.0_x64

Windows build number: [run `[Environment]::OSVersion` for powershell, or `ver` for cmd]
Windows Terminal version (if applicable):

Any other software?

Steps to reproduce

Use code like this in a CUI app.

// pcon->hIn is r/w handle to L"CONIN$"
FlushConsoleInputBuffer(pcon->hIn);
WaitForSingleObject(pcon->hIn, INFINITE);

Expected behavior

Behavior in a console (Conhost or OpenConsole) should be the same as in WindowsTerminal.

Actual behavior

When I run it from the Start\Run dialog, it waits for input. When run from Powershell in WindowsTerminal it waits for input. When run from Powershell in a console (provided by either Conhost.exe or OpenConsole.exe) it doesn't wait for input.

The difference may be my fault but I don't know how to fix it.

Originally created by @vefatica on GitHub (Nov 7, 2020). <!-- 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨 I ACKNOWLEDGE THE FOLLOWING BEFORE PROCEEDING: 1. If I delete this entire template and go my own path, the core team may close my issue without further explanation or engagement. 2. If I list multiple bugs/concerns in this one issue, the core team may close my issue without further explanation or engagement. 3. If I write an issue that has many duplicates, the core team may close my issue without further explanation or engagement (and without necessarily spending time to find the exact duplicate ID number). 4. If I leave the title incomplete when filing the issue, the core team may close my issue without further explanation or engagement. 5. If I file something completely blank in the body, the core team may close my issue without further explanation or engagement. All good? Then proceed! --> <!-- This bug tracker is monitored by Windows Terminal development team and other technical folks. **Important: When reporting BSODs or security issues, DO NOT attach memory dumps, logs, or traces to Github issues**. Instead, send dumps/traces to secure@microsoft.com, referencing this GitHub issue. If this is an application crash, please also provide a Feedback Hub submission link so we can find your diagnostic data on the backend. Use the category "Apps > Windows Terminal (Preview)" and choose "Share My Feedback" after submission to get the link. Please use this form and describe your issue, concisely but precisely, with as much detail as possible. --> # Environment Microsoft Windows 10 Pro for Workstations 10.0.18363.1139 (1909) WindowsTerminalPreview_1.4.2652.0_x64 ```none Windows build number: [run `[Environment]::OSVersion` for powershell, or `ver` for cmd] Windows Terminal version (if applicable): Any other software? ``` # Steps to reproduce <!-- A description of how to trigger this bug. --> Use code like this in a CUI app. // pcon->hIn is r/w handle to L"CONIN$" FlushConsoleInputBuffer(pcon->hIn); WaitForSingleObject(pcon->hIn, INFINITE); # Expected behavior Behavior in a console (Conhost or OpenConsole) should be the same as in WindowsTerminal. <!-- A description of what you're expecting, possibly containing screenshots or reference material. --> # Actual behavior <!-- What's actually happening? --> When I run it from the Start\Run dialog, it waits for input. When run from Powershell in WindowsTerminal it waits for input. When run from Powershell in a console (provided by either Conhost.exe or OpenConsole.exe) it doesn't wait for input. The difference may be my fault but I don't know how to fix it.
claunia added the Issue-QuestionNeeds-Tag-FixResolution-Answered labels 2026-01-31 02:44:05 +00:00
Author
Owner

@DHowett commented on GitHub (Nov 8, 2020):

This is likely due to the console input mode it inherits from PowerShell. Can you print out the console mode from the input handle?

@DHowett commented on GitHub (Nov 8, 2020): This is likely due to the console input mode it inherits from PowerShell. Can you print out the console mode from the input handle?
Author
Owner

@vefatica commented on GitHub (Nov 8, 2020):

Thanks, Dustun. Here's more of the code.

GetConsoleMode(pcon->hIn, &dwMode);
// wprintf(L"Mode: 0x%lX\n", dwMode); Sleep(5000);
// pcon->hIn is r/w handle to L"CONIN$"
FlushConsoleInputBuffer(pcon->hIn);
WaitForSingleObject(pcon->hIn, INFINITE);

Funny! When I uncomment the wprintf line it works; i.e., it waits, even in a console. I only tested in a normal, conhost, console.

It prints Mode: 0x1F7. The help page for SetConsoleMode() (7/12/2018) doesn't document 0x100 and 0x80.

@vefatica commented on GitHub (Nov 8, 2020): Thanks, Dustun. Here's more of the code. GetConsoleMode(pcon->hIn, &dwMode); // wprintf(L"Mode: 0x%lX\n", dwMode); Sleep(5000); // pcon->hIn is r/w handle to L"CONIN$" FlushConsoleInputBuffer(pcon->hIn); WaitForSingleObject(pcon->hIn, INFINITE); Funny! When I uncomment the wprintf line it works; i.e., it waits, even in a console. I only tested in a normal, conhost, console. It prints Mode: 0x1F7. The help page for SetConsoleMode() (7/12/2018) doesn't document 0x100 and 0x80.
Author
Owner

@vefatica commented on GitHub (Nov 8, 2020):

It was not the wprintf() that got it working in a console, it was the Sleep(). Here, Sleep(50) is sufficient to make it work; Sleep(20) is not.

If I run it from CMD in a console the mode is also 0x1F7 and it works without a Sleep();

@vefatica commented on GitHub (Nov 8, 2020): It was not the wprintf() that got it working in a console, it was the Sleep(). Here, Sleep(50) is sufficient to make it work; Sleep(20) is not. If I run it from CMD in a console the mode is also 0x1F7 and it works without a Sleep();
Author
Owner

@DHowett commented on GitHub (Nov 8, 2020):

Ah, that’s interesting. I bet I know what’s happening!

When you launch it from a shell in the traditional console, you pressing Enter generates a key down event and releasing it generates a key up event.

I believe (?) that the application is getting launched and starting to wait between the key down and key up event. This means that the input handle immediately has a key up event waiting to be read on it.

When you run from the run dialog, there’s no key events generated (for the console subsystem.)

When you run it from Terminal, the key down and key up events are generated simultaneously—the release event is generated before you release the key. There’s nothing left for the application to read.

You can likely help confirm this by reporting the first key event you read off the input handle using ReadConsoleInputW. ReadFile and ReadConsole will discard key up events.

@DHowett commented on GitHub (Nov 8, 2020): Ah, that’s interesting. I bet I know what’s happening! When you launch it from a shell in the traditional console, you pressing Enter generates a key down event and releasing it generates a key up event. I believe (?) that the application is getting launched and starting to wait between the key down and key up event. This means that the input handle immediately has a key up event waiting to be read on it. When you run from the run dialog, there’s no key events generated (for the console subsystem.) When you run it from _Terminal_, the key down and key up events are generated simultaneously—the release event is generated **before** you release the key. There’s nothing left for the application to read. You can likely help confirm this by reporting the first key event you read off the input handle using `ReadConsoleInputW`. `ReadFile` and `ReadConsole` will discard key up events.
Author
Owner

@DHowett commented on GitHub (Nov 8, 2020):

(The Flush doesn’t necessarily help because of when the release event is generated. It probably empties the queue in the Terminal case though!)

You can also test it in PowerShell by moving the sleep to before you launch the application: sleep 1; .\thing.exe. If my hunch is correct, this will work the same in both conhost and Terminal.

@DHowett commented on GitHub (Nov 8, 2020): (The Flush doesn’t necessarily help because of _when_ the release event is generated. It probably empties the queue in the Terminal case though!) You can also test it in PowerShell by moving the sleep to before you launch the application: `sleep 1; .\thing.exe`. If my hunch is correct, this will work the same in both conhost and Terminal.
Author
Owner

@DHowett commented on GitHub (Nov 8, 2020):

And lastly, if you’re curious about the weird mode...

ae550e0969/src/host/getset.cpp (L363-L369)

@DHowett commented on GitHub (Nov 8, 2020): And lastly, if you’re curious about the weird mode... https://github.com/microsoft/terminal/blob/ae550e0969595f062b15c2ff5cc33d4afe8ebc3f/src/host/getset.cpp#L363-L369
Author
Owner

@vefatica commented on GitHub (Nov 8, 2020):

It seems you're right. "Sleep 1; thing.exe" fixes it in PS and "delay 1 & thing.exe" fixes it in TCC. That INPUT_RECORD is a KEY_EVENT (that's as far as I got).

I found the 0x80 flag (ENABLE_EXTENDED_FLAGS) in a routine I wrote many years ago to disable/enable QuickEdit. And I found 0x100 (ENABLE_AUTO_POSITION) in a header; it's easy to imagine what that indicates.

The app writes a ruler on the current line and, after a keystroke, restores whatever might have been there. It's crude for now but works pretty well when running a Windows shell in WindowsTerminal ... and pretty badly in wsl/bash in WindowsConsole!

image
image

I don't know how that happened. The ruler is a single string and it doesn't contain any newlines.

I was going to make it a key-action that would run in the current tab/pane but I read the docs and figured out that you can't do that (and for good reason I imagine).

@vefatica commented on GitHub (Nov 8, 2020): It seems you're right. "Sleep 1; thing.exe" fixes it in PS and "delay 1 & thing.exe" fixes it in TCC. That INPUT_RECORD is a KEY_EVENT (that's as far as I got). I found the 0x80 flag (ENABLE_EXTENDED_FLAGS) in a routine I wrote many years ago to disable/enable QuickEdit. And I found 0x100 (ENABLE_AUTO_POSITION) in a header; it's easy to imagine what that indicates. The app writes a ruler on the current line and, after a keystroke, restores whatever might have been there. It's crude for now but works pretty well when running a Windows shell in WindowsTerminal ... and pretty badly in wsl/bash in WindowsConsole! ![image](https://user-images.githubusercontent.com/61856645/98457567-d63a9680-2156-11eb-9f2d-01190f4e7980.png) ![image](https://user-images.githubusercontent.com/61856645/98457580-fbc7a000-2156-11eb-826a-45268d7c3c60.png) I don't know how that happened. The ruler is a single string and it doesn't contain any newlines. I was going to make it a key-action that would run in the current tab/pane but I read the docs and figured out that you can't do that (and for good reason I imagine).
Author
Owner

@DHowett commented on GitHub (Nov 9, 2020):

Interesting that the size is wrong. Might be reasonable to look at how you're printing the ruler and how you're measuring the size of the screen.

For now, though, this question is getting closed as answered 😄

@DHowett commented on GitHub (Nov 9, 2020): Interesting that the size is wrong. Might be reasonable to look at how you're printing the ruler and how you're measuring the size of the screen. For now, though, this question is getting closed as answered :smile:
Author
Owner

@vefatica commented on GitHub (Nov 9, 2020):

Nothing fancy. The length of the ruler is csbi.dwSize.X and I print it with WriteConsole to a CONOUT$ handle.

If, instead, I make the ruler an array of CHAR_INFOs and print it with WriteConsoleOutput if comes out OK in WT/bash.

Here's another peculiarity with bash. I'm now using _getwch() to dismiss the ruler (it's so easy). Before that, I turn the cursor off (L"\x1b[?25l"). In any Windows shell, the cursor is off at the _gerwch(); in bash it's on. The same is true if I go back to using the WaitFor... and ReadConsoleInput, and in or out of WindowsTerminal.

I don't know exactly what takes place when a Windows EXE is run in WSL but I figure (naively) that at some point it's solely a matter of the EXE and the console. So the differences in WSL are a bit surprising.

@vefatica commented on GitHub (Nov 9, 2020): Nothing fancy. The length of the ruler is csbi.dwSize.X and I print it with WriteConsole to a CONOUT$ handle. If, instead, I make the ruler an array of CHAR_INFOs and print it with WriteConsoleOutput if comes out OK in WT/bash. Here's another peculiarity with bash. I'm now using _getwch() to dismiss the ruler (it's so easy). Before that, I turn the cursor off (L"\x1b[?25l"). In any Windows shell, the cursor is off at the _gerwch(); in bash it's on. The same is true if I go back to using the WaitFor... and ReadConsoleInput, and in or out of WindowsTerminal. I don't know exactly what takes place when a Windows EXE is run in WSL but I figure (naively) that at some point it's solely a matter of the EXE and the console. So the differences in WSL are a bit surprising.
Author
Owner

@DHowett commented on GitHub (Nov 9, 2020):

When you run a Windows executable from WSL, it actually runs inside a separate ConPTY session brokered by the inbox conhost.exe. This causes exactly many problems as it sounds like it would.

@DHowett commented on GitHub (Nov 9, 2020): When you run a Windows executable from WSL, it actually runs inside a separate ConPTY session brokered by the inbox `conhost.exe`. This causes exactly many problems as it sounds like it would.
Author
Owner

@vefatica commented on GitHub (Nov 9, 2020):

Thanks! It's no big deal. I only run bash to test things.

@vefatica commented on GitHub (Nov 9, 2020): Thanks! It's no big deal. I only run bash to test things.
Author
Owner

@vefatica commented on GitHub (Sep 2, 2022):

Bitten by this again! I made a new and simple observation that I'd like to understand. I hope this adequately describes it.

// GetCondoleMode says console modes are the same TCC, CMD, Powershell, and WSL (tcsh), namely 0x1E7 (in) and 0x7 (out)
// yet modifier-down (Shift|Ctrl|Alt) satisfies this wait in the first three but not when run in WSL!
WaitForSingleObject(pcon->hIn, INFINITE); // L"CONIN$"

Is there any documentation about which console-related Win32 API functions will not work as expected when run in WSL?

@vefatica commented on GitHub (Sep 2, 2022): Bitten by this again! I made a new and simple observation that I'd like to understand. I hope this adequately describes it. ``` // GetCondoleMode says console modes are the same TCC, CMD, Powershell, and WSL (tcsh), namely 0x1E7 (in) and 0x7 (out) // yet modifier-down (Shift|Ctrl|Alt) satisfies this wait in the first three but not when run in WSL! WaitForSingleObject(pcon->hIn, INFINITE); // L"CONIN$" ``` Is there any documentation about which console-related Win32 API functions will not work as expected when run in WSL?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#11311