Можно ли как-то изменить обработчик стандартных функций ввода-вывода в Windows? Предпочтительный язык C++. Если я правильно понимаю, выбрав консольный проект, компилятор просто предварительно выделяет консоль для вас и запускает все стандартные функции ввода-вывода для работы с ее дескриптором. Итак, что я хочу сделать, так это позволить одному консольному приложению фактически записывать в буфер консоли другого приложения. Я думал, что могу получить первый дескриптор консоли, а затем передать его второму приложению с помощью файла (я мало знаю о межпроцессном взаимодействии, и это кажется простым), а затем каким-то образом использовать, например, prinf с первым дескриптором приложения. Можно ли это сделать? Я знаю, как получить дескриптор консоли, но понятия не имею, как перенаправить printf на этот дескриптор. Это просто учебный проект, чтобы лучше понять работу ОС, стоящую за этим. Меня интересует, как printf знает, с какой консолью он связан.
Изменить дескриптор функций консольного ввода-вывода по умолчанию
Ответы (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).
Если я вас правильно понял, похоже, вам нужна функция Windows API AttachConsole(pid)
, которая прикрепляет текущий процесс к консоли, принадлежащей процессу, чей PID равен pid
.
Если вы хотите перенаправить printf
на дескриптор (ФАЙЛ*), просто выполните
fprintf(handle, "...");
Например, репликация printf
с fprintf
fprintf(stdout, "...");
Или отчет об ошибках
fprintf(stderr, "FATAL: %s fails", "smurf");
Это также то, как вы пишете в файлы. fprintf(file, "Blah.");