Enabling ANSI escape code processing on the modern Windows command line? [C] - c

I've heard that modern Windows consoles support ANSI escape codes (COLORS), but you have to enable them.
Using the 19042.746 build of Windows 10, it should just be a simple affair of enabling it using the SetConsoleMode(consoleHandle, ENABLE_VIRTUAL_TERMINAL_PROCESSING); // from windows.h, but after setting it, it still doesn't support ANSI escape colors. What am I missing?
Real life examples
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleMode(hConsole, ENABLE_VIRTUAL_TERMINAL_PROCESSING);
printf("\033[32mThis is green");
Prints out
[31mThis is green
Sources:
SetConsoleMode function
Bash tips: Colors and formatting (ANSI/VT100 Control sequences)

You also need to add ENABLE_PROCESSED_OUTPUT. You need to use GetConsoleMode first to get the current mode (it usually contains ENABLE_PROCESSED_OUTPUT), and then add ENABLE_VIRTUAL_TERMINAL_PROCESSING to the mode:
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode = 0;
GetConsoleMode(hConsole, &mode); //
SetConsoleMode(hConsole, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
printf("\033[32mThis is green");
Result:

Related

Same GLUT application using single and double buffer?

Can I have a GLUT program with one of the windows with single buffer while the other uses double buffer?
The display mode can be set using the glutInitDisplayMode() but how to set it differently to different windows?
I tried using the glutSetWindow(), but either one of the two windows does not work.
glutInitDisplayMode sets the mode that will be used for the next window that is created. Therefore you can call it multiple times, once for each window:
glutInitDisplayMode(GLUT_DOUBLE);
int id0 = glutCreateWindow("double buffered");
glutInitDisplayMode(GLUT_SINGLE);
int id1 = glutCreateWindow("single buffered");
Alternatively, you can temporarily turn off double buffering by directly drawing onto the front buffer.
glDrawBuffer(GL_FRONT);
// ... single buffered drawing ...
glDrawBuffer(GL_BACK); // switch back to double buffered

How to get the "output" (console screen buffer) Handle for GetConsoleMode() in Windows?

I want to do GetConsoleMode() on both input and output because I want to change some flags.
Input is pretty straightforward:
HANDLE hStdin;
DWORD fdwSaveOldMode;
hStdin = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(hStdin, &fdwSaveOldMode)
The output, on the other hand, doesn't seem as easy. One would think that just putting STD_OUTPUT_HANDLE would be enough, but the "help" pages talk about having to make and set your own buffer.
This, and a page about handles mention:
Specify the CONOUT$ value in a call to CreateFile to open a handle to a console's active screen buffer.
Sounds like a clue, but frankly, I'm unsure what this even means. Can someone show me how to do it properly? Why is output so different than input?
Thank you!
One would think that just putting STD_OUTPUT_HANDLE would be enough
It is. The "Clearing the Screen" example has a snippet demonstrating setting console output modes, and it uses GetStdHandle():
HANDLE hStdOut;
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
// Fetch existing console mode so we correctly add a flag and not turn off others
DWORD mode = 0;
if (!GetConsoleMode(hStdOut, &mode))
{
return ::GetLastError();
}
// Hold original mode to restore on exit to be cooperative with other command-line apps.
const DWORD originalMode = mode;
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
// Try to set the mode.
if (!SetConsoleMode(hStdOut, mode))
{
return ::GetLastError();
}
Some cases where GetStdHandle wouldn't work together with console-specific functions would be if the application isn't console-mode (you can get a console in a GUI-mode application by calling AllocConsole) or if stdout was redirected.
In those cases, you'd need to open a console handle via CreateFile and the special filename "CONOUT$". That will always access a console, if one is associated with your process, even in case stdout is not mapped to that console.

Can Win32 applications open the system's settings from code?

Is it possible to open Windows' settings dialogs using Win32 API calls from C? Such as the monitor settings (the one that allows you to set the monitor's resolution), and the network settings (the one that allows you to set the Wifi settings).
If it is possible, how to do that?
Or, is this not possible at all, and the user has to manually open them?
Launch the Windows Settings app explains how to pull up the Windows Settings app using the ms-settings: URI scheme. It also lists the supported URIs, including the ones this question is asking for (ms-settings:network-wifi and ms-settings:display).
While the documentation proposes using the Windows Runtime API Launcher.LaunchUriAsync this is a fair bit complex with C (as opposed to C++). Since the URIs can be invoked from the command prompt using the start command (e.g. start ms-settings:display), it's reasonable to assume that ShellExecuteExW can handle the ms-settings: URI scheme as well.
And indeed, this does appear to work:
#include <Windows.h>
#include <stdio.h>
int main() {
SHELLEXECUTEINFOW sei = {
.cbSize = sizeof(sei),
.hwnd = NULL,
.lpVerb = L"open",
.lpFile = L"ms-settings:display",
//.lpFile = L"ms-settings:network-wifi",
.nShow = SW_SHOWNORMAL,
};
if (!ShellExecuteExW(&sei))
{
printf("Failed with error code %d", GetLastError());
}
}
I wasn't able to find any documentation that specifies this behavior, so this may well be an unsupported implementation detail. I will also mention that while SHELLEXECUTEINFOW has an lpClass field that can be used to specify a URI protocol scheme, none of my iterations to use it worked for the ms-settings: URI scheme.

Capture QEMU Semihosted I/O

For unit testing purposes, I want to be able to run a bare-metal binary with qemu and capture it's output.
Sample file:
#include <stdio.h>
#include <stdint.h>
static void qemu_exit() {
register uint32_t r0 __asm__("r0");
r0 = 0x18;
register uint32_t r1 __asm__("r1");
r1 = 0x20026;
__asm__ volatile("bkpt #0xAB");
}
int main(void) {
puts("This is some example text that I want to capture");
qemu_exit();
return 0;
}
Running with:
qemu-system-gnuarmeclipse --nographic --no-reboot \
--board STM32F4-Discovery --mcu STM32F429ZI \
--semihosting-config enable=on,target=native \
--image <binary>
Displayed to the console is:
QEMU 2.8.0-13 monitor - type 'help' for more information
(qemu) This is some example text that I want to capture
This 'example text' is generated within QEMU and so redirecting stdout to a file does not capture it (only: QEMU 2.8.0-13 monitor - type 'help' for more information
(qemu)). Looking at the available qemu logging options -d help does not offer anything as far as I can see.
EDIT
A hacky solution is to use script to capture terminal session:
script --quiet --command <qemu-shell-script-wrapper>
That's not an upstream QEMU, and 2.8 is also quite old, but hopefully the same things that work with upstream QEMU will work there.
Firstly, assuming you're not actually using the monitor, you can get rid of that part of the output by dropping '--nographic' and instead using '-display none'. (--nographic does a lot of things all at once, including both "no graphical display" and also "default serial output to the terminal, add a QEMU monitor and multiplex the monitor and the serial", among other things. It's convenient if that's what you want but sometimes it's less confusing to specify everything separately.)
Secondly, you say you're using semihosting output but is the guest's stdlib definitely using semihosting for its puts() string output and not serial port (UART) output? The output will come out on the terminal either way but how you tell QEMU to redirect it somewhere else will differ. (I suspect it may be using UART output, because if it were using semihosting output then the redirection of stdout that you tried should have worked.)
If the output from the guest is via the serial port then you can control where it goes using the '-serial' option (most simply, "-serial stdio" to send to stdout, but you can also do more complicated things like sending to files, pipes or TCP sockets.). If it's via semihosting then you can control where it goes using the 'chardev=id' suboption of -semihosting-config.

How can I make the printer work in C in MS VC++ Express edition?

I am using VC++ 2008 express edition for C. When I try to run this:
/* Demonstrates printer output. */
#include <stdio.h>
main()
{
float f = 2.0134;
fprintf(stdprn, "This message is printed.\n\n");
fprintf(stdprn, "And now some numbers:\n\n");
fprintf(stdprn, "The square of %f is %f.", f, f*f);
/* Send a form feed */
fprintf(stdprn, "\f");
}
I get four of these errors: error C2065: 'stdprn' : undeclared identifier.
On this forum, they wrote that it works to define the printer as follows:
FILE *printer;
printer = fopen("PRN", "w");
EDIT
It builds with a warning that fopen is unsafe. When it runs the error appears:
Debug Assertion fails.
File: f:\dd\vctools\crt_bld\self_x86\crt\src\fprintf.c
Line: 55
Expression: (str != NULL)
The stdprn stream was an extension provided by Borland compilers - as far as I know, MS have never supported it. Regarding the use of fopen to open the printer device, I don't think this will work with any recent versions of Windows, but a couple of things to try:
use PRN: as the name instead of PRN (note the colon)
try opening the specific device using (for example) LPT1: (once again, note the colon). This will of course not work if you don't have a printer attached.
don't depend on a printer dialog coming up - you are not really using the WIndows printing system when you take this approach (and so it probably won't solve your problem, but is worth a try).
I do not have a printer attached, but I do have the Microsoft XPS document writer installed, s it shoulod at least bring up the standard Windows Print dialog from which one can choose the printer.
No. It wouldn't bring up a dialogue. This is because you are flushing data out to a file. And not going through the circuitous Win32 API.
The print doesn't work because the data is not proper PDL -- something that the printer could understand. For the print to work fine, you need to push in a PDL file, with language specific constructs. This varies from printer to printer, a PS printer will need you to push in a PostScript snippet, a PCL -- a PCL command-set and in case of MXDW you will have to write up XML based page description markup and create a zip file (with all resources embedded in it) i.e. an XPS file to get proper printout.
The PDL constructs are important because otherwise the printer doesn't know where to put the data, which color to print it on, what orientation to use, how many copies to print and so on and so forth.
Edit: I am curious why you are doing this. I understand portability is probably something you are trying to address. But apart from that, I'd like to know, there may be better alternatives available. Win32 Print Subsytem APIs are something that you ought to lookup if you are trying to print programmatically on Windows with any degree of fidelity.
Edit#2:
EDIT It builds with a warning that fopen is unsafe.
This is because MS suggests you use the safer versions nowadays fopen_s . See Security Enhancements in the CRT.
When it runs the error appears:
Debug Assertion fails. File: f:\dd\vctools\crt_bld\self_x86\crt\src\fprintf.c Line: 55
Expression: (str != NULL)
This is because fopen (whose return value you do not check) returns a NULL pointer. The file open failed. Also, if it did succeed a matching fclose call is called for.
There's no such thing as stdprn in ANSI C, it was a nonstandard extension provided by some compilers many years ago.
Today to print you have to use the specific APIs provided on your platform; to print on Windows you have to use the printing APIs to manage the printing of the document and obtain a DC to the printer and the GDI APIs to perform the actual drawing on the DC.
On UNIX-like OSes, instead, usually CUPS is used.
You can substitute the printer using this command with net use, see here on the MSDN kb
NET USE LPT1 \\server_name\printer_name
There is an excellent chapter on printing in DOS using the BIOS, ok, its a bit antiquated but interesting to read purely for nostalgic sake.
Onto your problem, you may need to use CreateFile to open the LPT1 port, see here for an example, I have it duplicated it here, for your benefit.
HANDLE hFile;
hFile = CreateFile("LPT1", GENERIC_WRITE, 0,NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
// handle error
}
OVERLAPPED ov = {};
ov.hEvent = CreateEvent(0, false, false, 0);
char szData[] = "1234567890";
DWORD p;
if (!WriteFile(hFile,szData, 10, &p, &ov))
{
if (GetLastError() != ERROR_IO_PENDING)
{
// handle error
}
}
// Wait for write op to complete (maximum 3 second)
DWORD dwWait = WaitForSingleObject(ov.hEvent, 3000);
if (dwWait == WAIT_TIMEOUT)
{
// it took more than 3 seconds
} else if (dwWait == WAIT_OBJECT_0)
{
// the write op completed,
// call GetOverlappedResult(...)
}
CloseHandle(ov.hEvent);
CloseHandle(hFile);
But if you insist on opening the LPT1 port directly, error checking is omitted...
FILE *prn = fopen("lpt1", "w");
fprintf(prn, "Hello World\n\f");
fclose(prn);
Hope this helps,
Best regards,
Tom.

Resources