This question already has answers here:
How and why does QuickEdit mode in Command Prompt freeze applications?
(2 answers)
Closed 6 years ago.
for an application of mine I have been playing around with the Windows API a bit, namely creating a very small wrapper for window functionality. Since I like to have console output as well, I created a console via AllocConsole(). I then noticed that highlighting text in this console (like if you want to copy something) 'freezes' the open window, ie. no messages will be processed, it is not click- or closable. Message loop and wndProc are both standard.
Two questions: is that intended/documented behaviour (I couldn't find anything about it) and if yes, is there a way to disable it? It's kind of annoying.
Thanks in advance
EDIT: as requested, the console creation code:
FILE *conOut = NULL;
FILE *conIn = NULL;
if (::AllocConsole())
{
::freopen_s(&conIn, "CONOUT$", "r", stdin);
::freopen_s(&conOut, "CONOUT$", "w", stdout);
// ...
if (conOut != NULL)
::fclose(conOut);
if (conIn != NULL)
::fclose(conIn);
::FreeConsole();
}
I created a test Win32 application with a basic Win32 project. I added a simple class to handle the console creation and tested two scenarios. What I found was the console window output will stop as if the thread generating the output is suspended when an Edit->Mark is done until the Mark is completed with a Copy or canceled.
The two scenarios tested with the Win32 application were: (1) printing to console window in a separate thread and (2) printing to console window in the main window message handling logic.
The particulars of the test program and details of the two scenarios tested are as follows.
Console.h
#pragma once
#include <stdio.h>
class CConsole
{
public:
CConsole(void);
~CConsole(void);
int Create(void);
public:
FILE *m_conOut;
FILE *m_conIn;
};
Console.cpp
#include "StdAfx.h"
#include "Console.h"
CConsole::CConsole(void)
{
}
CConsole::~CConsole(void)
{
}
int CConsole::Create(void)
{
if (::AllocConsole())
{
::freopen_s(&m_conIn, "CONIN$", "r", stdin);
::freopen_s(&m_conOut, "CONOUT$", "w", stdout);
}
return 0;
}
In the main file at the near the top where the Win32 project wizard put some global variables, I added an additional global variable CConsole myConsole; for my console and then I added a bit further down a simple function that is the target of a _beginthreadex(). The function looks like:
unsigned __stdcall myThread( void *x )
{
HWND hWnd = (HWND)x;
// allow for two different test scenarios depending on whether the
// SendMessage() is commented out or the fprintf() is commented out.
// if SendMessage() is live then the main window will write to the console window
// if fprintf() is live then this thread will write to the console window.
for (int i = 0; i < 50; i++) {
// SendMessage (hWnd, WM_USER, i, 0); // send a message to main window to request print
fprintf (myConsole.m_conOut, "This is line %d\n", i); // print from this thread
Sleep (1000);
}
return 0;
}
In the InitInstance(HINSTANCE hInstance, int nCmdShow) just before the return statement, I added the following two lines of code:
myConsole.Create();
_beginthreadex (NULL, 0, myThread, hWnd, 0, NULL);
Finally in the main message loop that handles the messages for the main window I added an additional message target:
case WM_USER:
fprintf (myConsole.m_conOut, "This is line %d\n", wParam);
break;
I then tried two different experiments by commenting out one of the two lines in my function that is the target of the _beginthreadex().
One was to print to the console window using fprintf() within that thread. The second test case was to send a message of WM_USER to the main window and ask it to use fprintf() to print to the console window.
What I found was that with the printing being done by the thread then I observed the following behavior when I used the Edit->Mark to begin the procedure of marking text to copy:
the main window was responsive to menu choices
the console window output stopped
when I cleared the mark or copied text, console window output resumed
The behavior was as if the thread writing to the console window was suspended until the Mark and Copy procedure was completed.
When the printing was done by the main window's message loop when handling the WM_USER message then I observed the following behavior when I used the Edit->Mark to begin the procedure of marking text to copy:
the main window was unresponsive to menu choices
the console window output stopped
when I cleared the mark or copied text, main window responsiveness returned as did console output
For some additional information about the Console Window Subsystem see Consoles. For a bit of information about the technology see WinEventProc Callback Function along with SetWinEventHook which describes this functionality to some extent as well as What Are WinEvents? and In-Context Hook Function Precautions.
See also Console Window Host in the book Windows Internals for a brief overview of the Console Window Subsystem.
And see Windows 7 / Windows Server 2008 R2: Console Host for an introduction to the architecture changes.
Finally The Console Host Process in Windows 7 from the book Inside Windows Debugging shows how to "discover the various layers involved in the printf sequence".
It may be possible to use the Console functions at a lower level to directly interface with the Console Window Subsystem in order to prevent the freezing of the thread which is doing I/O to the console window.
Related
I am asking if there is any way, and how to print text like the Windows installation "We're setting things up for you" to the middle of the screen? If I can, can I make it so only the text gets displayed and the text background should be your desktop.
The classic way to deal with the console in Windows is via the Console API. To get the console size you can use GetConsoleScreenBufferInfo(). Here's a very simple example that draws a string at the center of the screen
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdint>
#include <windows.h>
int main(void)
{
auto stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
std::string str;
CONSOLE_SCREEN_BUFFER_INFO oldcsbi{};
COORD coord{};
while (1)
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(stdout_handle, &csbi);
if (csbi.srWindow.Bottom != oldcsbi.srWindow.Bottom || csbi.srWindow.Right != oldcsbi.srWindow.Right)
{
std::fill(str.begin(), str.end(), ' ');
SetConsoleCursorPosition(stdout_handle, coord);
std::cout << str; // clear the old text
oldcsbi = csbi;
std::ostringstream s;
s << "Console size: " << csbi.srWindow.Right << 'x' << csbi.srWindow.Bottom;
str = s.str();
coord.X = (short)((csbi.srWindow.Right - str.size()) / 2);
coord.Y = (short)(csbi.srWindow.Bottom/2);
SetConsoleCursorPosition(stdout_handle, coord);
std::cout << str; // draw the new text
}
Sleep(1000);
}
}
The above code gets the console size periodically and redraws the screen if the size has been changed. It loops indefinitely until you press Ctrl+C or close the program
For more information about the Console API see Using the Console
But of course polling the size like that isn't very good because it makes the output not very smooth and also eats up CPU cycles. The real solution is to listen to the resize events and do the necessary things in that callback function
There's a mode called ENABLE_WINDOW_INPUT which passes the resize events to the console where you can read by the blocking ReadConsoleInput() or PeekConsoleInput() APIs. You can see an example in Reading Input Buffer Events. Just run it and resize the window, the resize events will be printed out
Unfortunately in that mode only the console buffer size change event is fired through the WINDOW_BUFFER_SIZE_RECORD and there's no console screen size change event, so if you change the number of rows then most of the time no events are generated. That means you'll need to go to a lower level and listen to the Console Winevent named EVENT_CONSOLE_LAYOUT:
HWINEVENTHOOK eventHook = SetWinEventHook(EVENT_CONSOLE_LAYOUT, EVENT_CONSOLE_LAYOUT,
NULL, EventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
...
MSG msg;
while (GetMessage(&msg, g_hWindow, EVENT_CONSOLE_LAYOUT, EVENT_CONSOLE_LAYOUT)) {
DispatchMessage(&msg);
You can find more details in
How do I disable or detect mode changes in Windows Console?
Can I prevent the user of my program to resize the console window? (in C)
The easier and even better way is to use ncurses and handle something similar to SIGWINCH. There were many Windows ports for ncurses in the past, and given Windows 10 console supports ANSI sequences it's even easier to write an ncurses port. In fact nowadays it's recommended to use ANSI sequences for terminal interaction instead of the ole Console API for portability
Is ncurses available for windows?
NCurses-Like System for Windows
Any Windows Substitutes For Curses/NCurses?
Ncurses for Windows
<Window x:Class="YourApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="600" Width="800" WindowStyle="None" AllowsTransparency="True" Background="Transparent" Topmost="True">
<StackPanel>
<TextBlock Text="Your Text Here"/>
</StackPanel>
</Window>
Please note that this will work only until some other application declares itself TopMost.
Suggestion by Window “on desktop”
I wrote a simple test program (TestProgram.exe) to learn how to handle the CTRL_CLOSE_EVENT and here are my observations and my question:
1) When I double click TestProgram.exe to launch it, and if I now go to Task Manager, TestProgram.exe is listed under "Apps". When I do "End Task" on TestProgram.exe, my handler for CTRL_CLOSE_EVENT is getting called.
BUT
2) When I open a command prompt and launch TestProgram.exe, it is listed under "Background Processes" under Task Manager and doing an "End Task" on the same doesn't result in a CTRL_CLOSE_EVENT.
My real application is used as described in case 2) above. I want to do some cleanup when users do an End Task on my app (which is listed under Background processes in Task Manager).
Thanks,
Krishna
In general, when a process is listed as an "Application", it means Task Manger has detected the process has a GUI, and an "End Task" on a GUI will first attempt to graceful close the GUI via standard WM_CLOSE and/or WM_QUIT messages before then resorting to a brute-force termination of the GUI's process via TerminateProcess(). On the other hand, doing an "End Task" on a "Background Process" will perform a brute-force termination immediately.
So in your situation, double-clicking on the .exe file results in a new dedicated console process that is running just your app by itself, so the console's GUI gets flagged as an "Application", but when you open a console window first and execute your .exe via the command-line, your app is running within the existing console and is sharing the console's original GUI, so your app does not have its own GUI and thus gets flagged as a "Background Process" instead.
When a process is terminated (not closed) nothing realy can be done unless you start do some hooking, either by hooking TerminateProcess or NtTerminateProcess in the Task Manger process, example of how it works:
#include <windows.h>
#include <assert.h>
BOOL WINAPI MyTerminateProcess(HANDLE hProcess, UINT uExitCode ) {
MessageBox(NULL, TEXT("Do some cleanup"), NULL, MB_OK);
ExitProcess(0);
return TRUE;
}
#pragma pack(1)
typedef struct __PATCHDATA {
BYTE push;
DWORD address;
BYTE ret;
} PATCHDATA;
#pragma pack()
int main(int argc, char **argv) {
HMODULE hModule;
DWORD written;
// This struct contains assembly instruction that do:
// push address ; 0x68 MyTerminateProcess
// ret ; 0xc3
// so the execution will return to our hook
PATCHDATA patch = {0x68, (DWORD) MyTerminateProcess, 0xc3};
// remove this code, the program will terminate itself.
// TODO: check the memory protection and modify it.
WriteProcessMemory(GetCurrentProcess(),
TerminateProcess,
&patch,
sizeof(PATCHDATA),
&written);
TerminateProcess(NULL, 0);
return 0;
}
This hooks TerminateProcess in the same process, you need to ship it in a DLL and inject it in the Task Maneger process, didn't test it. But this method is overwork and not safe, some AV products may detect it as harmful program.
A simple solution is to clean up on the program start-up as #Martin James suggested. On your program start-up create a file or use the registry to store some value like 0, if the program was closed, received WM_CLOSE if it's GUI or CTRL_CLOSE_EVENT if you closed the command prompt, you do the clean-up and store 1.
On the next start-up you you check back that value if it stills 0, this mean do the program was not closed properly, do do the clean up, if it's 1 no need to the clean-up, store 0 and move on.
Many programs use this method to detect if the program was closed properly.
I have a program where I record data through an ADC system from National Instruments (NI).
The device buffers information for some time, and then the program collects the buffer data at some point. If the program collects data larger than the buffer, then the buffer would have to free without my program receiving the data, which will cause the NI library to throw an exception saying that requested data isn't available anymore, since it was lost.
Since my program is a command-prompt program, if the user clicks and holds the scrollbar, the program pauses, which could get this problem to happen.
How can I get over this problem without increasing the buffer size? Can I disable this holding thing in Windows?
Thanks.
Only the thread that is attempting to output to the console is blocked. Make this a separate thread, and your problem goes away.
Of course, you'll need to buffer up your output, and do something sensible if the buffer overflows.
For reference, here's the simple code I used to test this, you will note that the counter continues to increase even when the scroll bar is held down:
#include <Windows.h>
#include <stdio.h>
volatile int n = 0;
DWORD WINAPI my_thread(LPVOID parameter)
{
for (;;)
{
n = n + 1;
Sleep(800);
}
}
int main(int argc, char ** argv)
{
if (!CreateThread(NULL, 0, my_thread, NULL, 0, NULL))
{
printf("Error %u from CreateThread\n", GetLastError());
return 0;
}
for (;;)
{
printf("Hello! We're at %u\n", n);
Sleep(1000);
}
return 0;
}
Whilst there may be ways to bypass each individual problem you can possibly conceive with the output [including for example running it over a network on a sometimes slow output link, or some such], I think the correct thing to do is to disconnect your output from your collecting of data. It shouldn't be hard to do this by adding a separate thread that collects the data, and having the main thread display to the command prompt window. That way, not matter which variation of "output is blocked" Windows throws at you, it will work - at least until you run out of RAM, but tat that point it's YOUR program's decision to do something [e.g. throw away some data or some such].
This is generally how the problem "I need to collect something, and I also need to allow users to view the data, but I don't want the two to interfere with each other" is solved.
First use the GetConsoleWindow winapi function and get the HWND of your console.
now i suggest two ways to do this,
Method I
Subclass the window by creating your own WindowProcedure. (get help from here)
Now that you have subclassed it, you can intercept the WM_VSCROLL and WM_HSCROLL messages and do your own remedy to your code.
Method II
Change the size of the window using some function like SetWindowPos so that the scroll bars are not needed.
or Change the size of the console screen buffer so that the scroll bars are not needed.
Method I has lot of control over the application, but its a little bit complex than the method II which is very simple.
If you want to forbid the user from resizing the console window, just remove the WS_THICKFRAME from the WindowStyle of the console window.
I was in a similar situation and found that this kind of blocking behaviour could be caused by the quick edit "feature" of the command prompt. This question explains about it and the answer shows how to disable it. Hope that helps, even after some years :)
What i want:
An application, where there are a gui window and console window. Window can be clicked on, dragged, etcetera. At any given moment, console can be chosen, and a line entered, that will be processed.
What i already have:
An application, that allocates and attaches console to itself, then redirects standard streams to it. Code is:
AllocConsole() ;
AttachConsole( GetCurrentProcessId());
freopen("CONIN$","rb",stdin); // reopen stdin handle as console window input
freopen("CONOUT$","wb",stdout); // reopen stout handle as console window output
freopen("CONOUT$","wb",stderr); // reopen stderr handle as console window output
Then registers window class, creates and shows a window. Output into console works fine, interaction with window is correct.
However, i cannot input anything into console. I can make a guess about it: if i call something like std::cin >> my_string, i will be able to enter a line - but interaction with a window will stop until the input is completed. Is that correct? How can i make application behave in a way i described above?
update:
I have found related question: Test if stdin has input for C++ (windows and/or linux)
The code for determining, whether there are characters in console input was given there as follows:
bool StdinOpen() {
static HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD bytes_left;
PeekNamedPipe(handle, NULL, 0, NULL, &bytes_left, NULL);
return bytes_left;
}
However, it returns some exorbitant numbers, as if there always is input in console.
I'd start by initializing the bytes_left variable and check the return value.
bool StdinOpen() {
static HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD bytes_left = 0;
if (!PeekNamedPipe(handle, NULL, 0, NULL, &bytes_left, NULL))
return false;
return bytes_left != 0;
}
So I have a GUI program and for some reason it does not let me debug using printf().
When I use printf(), it does not go to the Visual Studio debugger for some reason.
Anyways, I wanted to make my own separate window that opens up when the GUI opens up,
and basically be able to feed information into that console and talk to it.
For example:
void talk(std::string info){
//Add the value of info to the next line in the console
}
Anyone know how to do this?
Basically create a command line and talk to it so I can see output:
CommandLine c;
c.talk("hey!");
You can create a console using AllocConsole to create a console, then write to that explicitly (there are a few methods, GetStdHandle and file write will work). You can also use OutputDebugString to write to the VS output window.
void makeConsole()
{
AllocConsole();
console = GetStdHandle(STD_OUTPUT_HANDLE);
}
void talk(std::string info)
{
WriteFile(console, info.c_str(), info.length()); // To console
OutputDebugString(info.c_str()); // To output window
}
(pseudo-code, functions may not be quite right)
Edit:
If you're writing to the console only through your talk function, this will work fine. If you're using printf/cout throughout your code, you definitely want to use Ben's method (much simpler to use repeatedly).
#peachykeen has half the solution. If you want to make printf and cout work, try this:
AllocConsole();
freopen("CONOUT$", "w", stdout);