Я хочу иметь возможность перенаправить весь стандартный вывод приложения Windows в стандартный дескриптор вывода Win32 вместо использования дескриптора консоли.
В контексте часто задаваемых вопросов по Emacs Win32 говорится следующее:
Программы, которые явно используют дескриптор консоли (CON или CON :) вместо stdin и stdout, не могут использоваться в качестве подпроцессов для Emacs, и они также не будут работать в режиме оболочки [...]. Это не удобный способ для Emacs или любой оболочки, используемой в режиме оболочки, для перенаправления ввода и вывода таких процессов из консоли в каналы ввода и вывода. Единственный обходной путь - использовать другую реализацию программы, которая не использует консоль напрямую. (https://www.gnu.org/software/emacs/manual/html_node/efaq-w32/Subprocess-hang.html)
У меня возникла проблема, описанная в FAQ: при запуске из Emacs программа запускается, но ни один из ее выводов не отображается в окне shell
Emacs, пока программа не закроется, как если бы стандартный вывод был буферизован и не сбрасывался во время работы. Эта же программа выведет стандартный вывод в режиме реального времени, как и ожидалось, если запустить из cmd.exe
или ConEmu.
Что я хочу сделать, это сделатьвсе выходные данные программы отображаются в оболочке Emacs, поэтому я могу сразу перейти к месту ошибки компилятора. Я хочу переписать исходный код программы, чтобы добиться этого. Я хочу знать, что такое «другая реализация»Для этого нужно использовать детали, используя «stdin and stdout» вместо «дескриптор консоли».
Из того, что я понимаю:
- Существует несколько видов ввода / вывода. O в Windows, включая среду выполнения C (
printf
и т. Д.) И слой Win32 (ReadFile
и т. Д.). - Я предполагаю, что "stdin and stdout" относится к
STD_INPUT_HANDLE
иSTD_OUTPUT_HANDLE
шкоторый может быть изменен с помощью SetStdHandle()
. - Внешние DLL, загруженные программой, наследуют каналы времени выполнения C
stdin
и stdout
, но это происходит при инициализации программы до того, как вызовы SetStdHandle()
будут выполнены. называется, так что есть еще что-то, что вам нужно сделать, чтобы перенаправить их вывод.
Я пытался использовать этот код:
#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;
}
Это имеет желаемый эффект, но толькопри использовании printf
и std::cout
в том же двоичном файле, что и код перенаправления. Моя программа загружает внешнюю DLL, которая использует printf
, и ни один из ее выводов не перенаправляется.
Кроме того, я не хочу использовать AllocConsole()
или подобное, так как это открывает отдельное окно, которое не интегрируетсяс родительским процессом (Emacs). Я хочу перенаправить весь стандартный вывод, чтобы он отображался в том же терминале / консоли, где запущена программа, а не в другом окне (если это имеет смысл). Поскольку я не использую AllocConsole()
, то код, подобный _open_osfhandle((long)hStdout, O_WRONLY|O_TEXT)
, всегда по какой-то причине возвращает -1
, поэтому кажется, что я не могу использовать dup2()
, как описано здесь .
См. Также: