WinAPI - Как перенаправить все стандартный вывод программы и внешние библиотеки DLL на стандартный дескриптор вывода Win32? - PullRequest
0 голосов
/ 11 ноября 2019

Я хочу иметь возможность перенаправить весь стандартный вывод приложения 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» вместо «дескриптор консоли».

Из того, что я понимаю:

  1. Существует несколько видов ввода / вывода. O в Windows, включая среду выполнения C (printf и т. Д.) И слой Win32 (ReadFile и т. Д.).
  2. Я предполагаю, что "stdin and stdout" относится к STD_INPUT_HANDLE иSTD_OUTPUT_HANDLE шкоторый может быть изменен с помощью SetStdHandle().
  3. Внешние 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(), как описано здесь .

См. Также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...