В Windows, как работает владение окна консоли? - PullRequest
5 голосов
/ 11 мая 2010

Когда консольное приложение запускается из другого консольного приложения, как работает владение консолью?

Я вижу четыре варианта:

  1. Второе приложение наследует консоль от первого приложения в течение своего срока службы, при этом консоль возвращается исходному владельцу при выходе.
  2. Каждое приложение имеет собственную консоль. Затем Windows каким-то образом объединяет содержимое этих двух элементов в то, что «консоль» видна пользователю
  3. Второе приложение получает дескриптор консоли, которая принадлежит первому приложению.
  4. Консоль помещена в общую память, и оба приложения имеют равную «собственность»

Вполне возможно, что я что-то упустил, и ни один из этих четырех вариантов не описывает адекватно то, что Windows делает со своими консолями.

Если ответ близок к варианту 4. Мой дополнительный вопрос: какой из двух процессов отвечает за управление окном? (Обработка графических обновлений, когда необходимо обновить / перерисовать экран и т. Д.)

Конкретный пример: запустить CMD. Затем, используя CMD, запустите [консольное приложение]. [Консольное приложение] запишет в то же самое окно консоли, которое использовала CMD.

Ответы [ 6 ]

6 голосов
/ 14 мая 2010

Ни одна из ваших четырех возможностей на самом деле не подходит, и ответ на ваш дополнительный вопрос: «Какой из двух процессов отвечает за управление окном?», Заключается в том, что ни один процесс не отвечает , Программы TUI вообще не должны ничего знать об окнах , а под крышками не обязательно даже подключаться к GUI.

Консоли - это объекты, доступ к которым осуществляется с помощью таких же дескрипторов, как файлы, каталоги, каналы, процессы и потоки. Один процесс не «владеет» консолью через свой дескриптор, так же как процесс «владеет» любым файлом, к которому у него есть открытый дескриптор. Дескрипторы к консолям наследуются дочерними процессами от их родителей так же, как и все другие (наследуемые) дескрипторы. Ваше приложение TUI, созданное CMD, просто наследует стандартные дескрипторы, которые CMD сказал, что оно должно наследовать, когда оно вызывает CreateProcess() & mdash; которые обычно будут стандартным вводом, выводом и ошибкой CMD (если командная строка не указала CMD использовать некоторые другие дескрипторы в качестве стандартного ввода, вывода и ошибки дочернего элемента).

Консоли не зависят от CMD. Они существуют до тех пор, пока есть (а) какие-либо открытые дескрипторы входных или выходных буферов консоли или (б) любые процессы, иным образом "прикрепленные" к консоли. Таким образом, в вашем примере вы можете убить CMD, но консоль на самом деле будет уничтожена только тогда, когда вы также завершите дочерний процесс.

Процесс, отвечающий за отображение окон графического интерфейса пользователя, в которых представлены консоли, в Windows NT до версии 6.1, CSRSS, - подсистема времени выполнения клиент-сервер. Код обработки окна находится в WINSRV.DLL, который содержит «консольный сервер», который & mdash; под одеялом & ndash; Программы Win32, выполняющие консольный ввод / вывод, выполняют LPC-вызовы. В Windows NT 6.1 эта функциональность по причинам , охваченным Рэймондом Ченом , перешла из CSRSS в менее привилегированный процесс, который порождает CSRSS.

1 голос
/ 11 мая 2010

То, как SDK говорит об этом, очень напоминает 1. Это вариант с CreateProcess, описанный следующим образом:

CREATE_NEW_CONSOLE
Новый процесс имеет новую консоль вместо того, чтобы наследовать консоль своего родителя (по умолчанию). Для получения дополнительной информации см. Создание консоли.

Вывод, однако, происходит через дескрипторы, вы получите один с GetStdHandle (). Передача STD_OUTPUT_HANDLE возвращает дескриптор консоли, при условии, что вывод не перенаправлен. Фактический вывод осуществляется через WriteFile () или WriteConsole / Output (). Если оба процесса продолжают записывать выходные данные в дескриптор, то их выходные данные будут случайно перемешаны. В противном случае это неотличимо от того, что происходит, когда две программы пишут в один и тот же дескриптор файла.

Логически, есть экранный буфер, связанный с консолью. Вы можете повозиться с ним с помощью SetConsoleScreenBufferXxx (). С этой точки зрения вы можете назвать это разделяемой памятью. Фактическая реализация не обнаруживаема, обрабатывает их абстрагирование, как и любой Win32 API. Это наверняка значительно изменилось в Vista с новым процессом conhost.exe.

1 голос
/ 11 мая 2010

Я предполагаю, что где-то между 3 и 4. Консоль является автономным объектом, который имеет стандартные потоки ввода, вывода и ошибок. Эти потоки присоединяются к первому процессу, который использует консоль. Последующие процессы также могут наследовать эти потоки, если они не перенаправлены (например, выполнить команду с перенаправлением в файл.)

Обычно нет конфликтов, поскольку родительские процессы обычно ждут завершения своих дочерних процессов, и асинхронные процессы обычно запускают свою собственную консоль (например, попробуйте "start cmd" в командной строке) или перенаправляют стандартный вывод.

Однако ничто не мешает обоим процессам выполнять запись в выходной поток одновременно - потоки являются общими. Это может быть проблемой при использовании некоторых библиотек времени выполнения, так как запись в стандартный вывод / ошибка может не сразу сбрасываться, что приводит к смешанному искаженному выводу. В общем, необходимость активных процессов записи в один и тот же поток вывода, как правило, не очень хорошая идея, если только вы не примете меры для координации их вывода с помощью примитивов параллелизма, таких как Mutexes, Events и т.п.

0 голосов
/ 11 мая 2010

Я думаю, это довольно хорошо прописано в документации .

0 голосов
/ 11 мая 2010

CMD «владеет» консолью. Когда он создает процесс для приложения, это приложение наследует дескрипторы консоли. Он может читать и писать те. Когда процесс завершается, CMD продолжает владение.

Примечание: я не совсем уверен, что слово «владение» здесь подходит. Windows закроет консоль при выходе из CMD, но это может быть простой настройкой.

0 голосов
/ 11 мая 2010

Каждое приложение будет запускаться в своем собственном домене приложений. Каждый домен приложения должен иметь собственную консоль.

Ах, ты прав. Я думал о запуске исполняемых файлов в рамках процесса и забыл, что они запускают свой собственный процесс - я недостаточно углубился.

...