I want to be able to redirect all standard output of a Windows application to the Win32 standard output handle, instead of using a console handle.
For context, the Emacs Win32 FAQ says this:
Programs that explicitly use a handle to the console (CON or CON:) instead of stdin and stdout cannot be used as subprocesses to Emacs, and they will also not work in shell-mode [...] There is no convenient way for either Emacs or any shell used in shell-mode to redirect the input and output of such processes from the console to input and output pipes. The only workaround is to use a different implementation of the program that does not use the console directly. (https://www.gnu.org/software/emacs/manual/html_node/efaq-w32/Subprocess-hang.html)
I'm experiencing the issue the FAQ describes: when started from Emacs, the program will run but none of its output is displayed in Emacs' shell
window until the program exits, as if stdout was buffered and didn't flush while it was running. The same program will output stdout in real-time as expected if run from cmd.exe
or ConEmu.
What I want to accomplish is making all the output of the program appear in an Emacs shell so I can jump to a compiler error location as soon as it's printed. I'm willing to rewrite the source of the program to accomplish this. I want to know what "different implementation" details are necessary to accomplish this by using "stdin and stdout" instead of "a handle to the console".
From what I understand:
- There are multiple kinds of I/O in Windows, including the C runtime (
printf
, etc.) and the Win32 layer (ReadFile
, etc.). - I'm assuming "stdin and stdout" refer to
STD_INPUT_HANDLE
andSTD_OUTPUT_HANDLE
which can be modified bySetStdHandle()
. - External DLLs loaded by a program will inherit the C runtime
stdin
andstdout
pipes, but this happens on program initialization, before any calls toSetStdHandle()
are called, so there is something else you have to do to redirect their output.
I've tried using this code:
#include <windows.h>
#include <cstdlib>
int main()
{
HANDLE hStdout = CreateFile(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hStdin = CreateFile(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
SetStdHandle(STD_OUTPUT_HANDLE, hStdout);
SetStdHandle(STD_ERROR_HANDLE, hStdout);
SetStdHandle(STD_INPUT_HANDLE, hStdin);
std::cout << "Hello, world." << std::endl;
printf("Hello, world.\n");
std::cin.get();
return 0;
}
This has the desired effect, but only on usages of printf
and std::cout
within the same binary as the redirection code. My program loads an external DLL that uses printf
and none of its output is redirected.
Also, I don't want to use AllocConsole()
or similar since that opens a separate window, which does not integrate with the parent process (Emacs). What I want is to redirect all stdout so it shows up within the same terminal/console that is running the program instead of a different window (if that makes sense). Since I don't use AllocConsole()
, then code like _open_osfhandle((long)hStdout, O_WRONLY|O_TEXT)
always returns -1
for some reason, so it seems like I can't use dup2()
as described here.
See also: