Изменить дескриптор функций консольного ввода-вывода по умолчанию

Можно ли как-то изменить обработчик стандартных функций ввода-вывода в Windows? Предпочтительный язык C++. Если я правильно понимаю, выбрав консольный проект, компилятор просто предварительно выделяет консоль для вас и запускает все стандартные функции ввода-вывода для работы с ее дескриптором. Итак, что я хочу сделать, так это позволить одному консольному приложению фактически записывать в буфер консоли другого приложения. Я думал, что могу получить первый дескриптор консоли, а затем передать его второму приложению с помощью файла (я мало знаю о межпроцессном взаимодействии, и это кажется простым), а затем каким-то образом использовать, например, prinf с первым дескриптором приложения. Можно ли это сделать? Я знаю, как получить дескриптор консоли, но понятия не имею, как перенаправить printf на этот дескриптор. Это просто учебный проект, чтобы лучше понять работу ОС, стоящую за этим. Меня интересует, как printf знает, с какой консолью он связан.


person B.Gen.Jack.O.Neill    schedule 12.05.2010    source источник


Ответы (3)


Если я правильно понял, вы можете найти исходный код приложения, которое вы хотите написать, в http://msdn.microsoft.com/en-us/library/ms682499%28VS.85%29.aspx. В этом примере показано, как писать в stdin другого приложения и читать его stdout.

Для общего понимания. Компилятор не «предварительно выделяет консоль для вас». Компилятор использует стандартные библиотеки C/C++, которые записывают на выходе. Итак, если вы используете, например, printf(), в конце будет выполнен следующий код:

void Output (PCWSTR pszwText, UINT uTextLenght) // uTextLenght is Lenght in charakters
{
    DWORD n;
    UINT uCodePage = GetOEMCP();    // CP_OEMCP, CP_THREAD_ACP, CP_ACP
    PSTR pszText = _alloca (uTextLenght);

    // in the console are typically not used UNICODE, so
    if (WideCharToMultiByte (uCodePage,  0, pszwText, uTextLenght,
                             pszText, uTextLenght, NULL, NULL) != (int)uTextLenght)
        return;

    WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), pszText, uTextLenght, &n, NULL);
    //_tprintf (TEXT("%.*ls"), uTextLenght, pszText);
    //_puttchar();
    //fwrite (pszText, sizeof(TCHAR), uTextLenght, stdout);
    //_write (
}

Поэтому, если изменить значение STD_OUTPUT_HANDLE, весь вывод будет отправлен в файл/канал и так далее. Если вместо WriteFile программа использует функцию WriteConsole, такое перенаправление не будет работать, но стандартная библиотека C/C++ этого не делает.

Если вы хотите перенаправить stdout не из дочернего процесса, а из текущего процесса, вы можете вызвать SetStdHandle() напрямую (см. http://msdn.microsoft.com/en-us/library/ms686244%28VS.85%29.aspx).

«Распределение консоли» делает загрузчик операционной системы. Он выглядит как слово двоичного EXE-файла (в разделе «Подсистема» IMAGE_OPTIONAL_HEADER см. http://msdn.microsoft.com/en-us/library/ms680339%28VS.85%29.aspx) и если EXE имеет 3 на этом месте (IMAGE_SUBSYSTEM_WINDOWS_CUI), то он использует консоль родительского процесса или создать новый. Это поведение можно немного изменить в параметрах вызова CreateProcess (но только если вы запускаете дочерний процесс в своем коде). Этот флаг Subsystem исполняемого файла, который вы определяете в отношении переключателя/подсистемы компоновщика (см. http://msdn.microsoft.com/en-us/library/fcc1zstk%28VS.80%29.aspx).

person Oleg    schedule 13.05.2010

Если я вас правильно понял, похоже, вам нужна функция Windows API AttachConsole(pid), которая прикрепляет текущий процесс к консоли, принадлежащей процессу, чей PID равен pid.

person Jon Purdy    schedule 12.05.2010
comment
Я думаю ты прав. msdn.microsoft.com/en-us/library/ ms681952%28VS.85%29.aspx - person dss539; 13.05.2010

Если вы хотите перенаправить printf на дескриптор (ФАЙЛ*), просто выполните

fprintf(handle, "...");

Например, репликация printf с fprintf

fprintf(stdout, "...");

Или отчет об ошибках

fprintf(stderr, "FATAL: %s fails", "smurf");

Это также то, как вы пишете в файлы. fprintf(file, "Blah.");

person LukeN    schedule 12.05.2010
comment
Спасибо. Итак, fprintf является перенаправляемым printf? И как printf узнает, какая консоль используется по умолчанию? - person B.Gen.Jack.O.Neill; 13.05.2010
comment
printf по умолчанию переходит к тому, на что ссылается стандартный вывод, на стандартный вывод. В основном консоль, или если вы перенаправляете (ваша программа ›output.txt) перенаправляемый файл. - person LukeN; 13.05.2010