Можно ли подделать консоль windows api?

Я написал ssh-сервер в С#, и я подумал, что было бы удобно подключать powershell как оболочку. Я пробовал 2 метода, чтобы заставить это работать правильно, но оба они далеки от совершенства. Вот что я пробовал:

  • Запустите powershell.exe и перенаправьте его std (in/out). Это не хорошо работает, так как powershell.exe обнаруживает, что он перенаправлен, изменения это поведение. Что еще, он ожидает ввода данных на stdid, а не команды. Поэтому он использует консоль api для чтения команд.
  • Host powershell в приложении "wrapper". Это имеет то преимущество, что возможность предоставить "консольную" реализацию powershell (через PSHostRawUserInterface). Это работает лучше, но вы все равно можете ссылаться команд (в основном, реальных консольных приложений), таких как "... больше", которые ожидают чтобы иметь возможность использовать консоль api, а затем попытаться прочитать из консоль процесса обертки.

Так что я хотел бы сделать, это набор функций, которые заменяют обычные функции ввода/вывода консоли, которые используют консольные приложения, поэтому я могу их обработать. Но это кажется довольно резким, поскольку это плохая идея дизайна (imo).

Сейчас я собираюсь манипулировать консолью, отправив соответствующие ключи с помощью функций native/Pinvoke, таких как WriteConsoleInput. Я понимаю, что можно было бы подделать консоль именно так. Но я не вижу, как бы тогда "читать", что происходит на консоли.

Также имейте в виду, что это услуга, поэтому желательно, чтобы она не создавала фактическое окно консоли, хотя, возможно, в сеансе Windows 0, который не отображался и не имел значения.

Ответ 1

У вас PSSession для этой цели и Enter-PSSession CmdLet. Что ваш SSH с Powershell сделает, что PSSession не делает?

Но если вы хотите сделать это, то это решение без написания чего-либо: Использование PowerShell через SSH


Отредактировано 02/11/2011

PowerShell внутри предоставляет другой способ сделать это без написания чего-либо (бесплатно для личного использования).

образец Host03, может предоставить базовый код для выполнения того, что вы должны делать.

Ответ 2

Я установил PowerShellInside, как было предложено JPBlanc, но не использовал его очень долго. Одно соединение просто слишком ограничено, и я не люблю быть ограниченным (особенно, если это ограничение основано на прибыли, но это целая другая дискуссия, в которую я не должен попасть). И, несмотря на то, что это решение исходной проблемы, оно кажется неудовлетворительным, поскольку оно не решает проблему программирования, с которой я столкнулся.

Однако в конечном итоге мне удалось решить указанную проблему, действительно, используя вызовы windows api в процессе обертки. Потому что есть довольно много подводных камней, я решил ответить на свой вопрос и дать другим взглянуть на одну и ту же проблему с некоторыми указателями. Базовая структура выглядит следующим образом:

  • Запустите процесс оболочки с перенаправленным stdin/-out (и stderr, если хотите). (В моем случае stdin и out будут потоками управляющих последовательностей xterm и данных, потому что это путь ssh)
  • Использование GetStdHandle() для получения перенаправленных входных и выходных дескрипторов. Далее SetStdHandle() в CreateFile() из "CONIN $" и "CONOUT $", так что дочерние процессы наследуют консоль и не имеют перенаправления процесса обертки. (Обратите внимание, что для создания файла необходим дескриптор безопасности, позволяющий наследовать)
  • Настройка режима консоли, размера, заголовка, обработчика Ctrl-C и т.д. Примечание. Обязательно установите шрифт, если хотите поддержку юникода, я использовал Lucida Console (.FontFamily = 54,.FaceName = "Lucida Console" ). Без этого, считывание символов с вашего вывода на консоль будет возвращать кодовые страницы, которые ужасно работают с управляемым кодом.
  • Чтение вывода может быть выполнено с помощью SetWinEventHook(), обязательно используйте внеконтекстное уведомление, потому что я уверен, что если ваше управляемое приложение неожиданно запускается в другом контексте/адресном пространстве процесса, это Bad Idea ™ (Я так уверен, что даже не пытался). Событие будет срабатывать для каждого окна консоли, а не только для вашего. Поэтому фильтруйте все вызовы на обратный вызов с помощью дескриптора окна. Верните дескриптор окна текущего консольного приложения с помощью GetConsoleWindow(). Также не забудьте отменить обратный вызов, когда приложение будет выполнено.
  • Обратите внимание, что до этого момента не следует использовать (или делать что-либо, что вызывает нагрузку) класс System.Console, или что-то более чем вероятно, пойдет не так. Использование после этой точки будет вести себя так, как если бы субпроцесс был записан на выходе.
  • Создайте необходимый подпроцесс (обратите внимание, вы должны использовать .UseShellExecute = false или он не наследует консоль)
  • Вы можете начать ввод ввода в консоль с помощью WriteConsoleInput()
  • В этот момент (или в отдельном потоке) вам нужно запустить цикл сообщений Windows или вы не получите обратные вызовы уведомления о событиях в консоли. Вы можете просто использовать беззатратное приложение Application.Run(). Чтобы разбить цикл сообщения, вы должны в какой-то момент отправить сообщение о выходе в свой цикл сообщений. Я сделал это с Application.Exit() в подпроцессе. Exited event. (Обратите внимание на использование .EnableRaisingEvents, чтобы это работало)
  • Теперь вызовы будут отправлены на ваш обратный вызов, когда что-то на вашей консоли изменится. Обратите внимание на событие прокрутки, это может показаться несколько неожиданным. Также не делайте предположений о синхронной доставке. Если подпроцесс записывает 3 строки, к моменту обработки первого события оставшиеся 3 строки могут быть уже записаны. Справедливости ради следует обратить внимание на то, что окна прекрасно справляются с составлением событий, так что вы не получаете болота с отдельными изменениями символов и можете идти в ногу с изменениями.
  • Обязательно отметьте все определения PInvoke символом CharSet = CharSet.Unicode, если они содержат символ в любом месте ввода или вывода. PInvoke.net пропустил немало из них.

Конечный результат всего этого: приложение-оболочка для консоли windows api. Обертка может читать/записывать перенаправленные stdin и stdout для общения с миром. Конечно, если вы хотите получить фантазию, вы можете использовать любой поток здесь (named pipe, tcp/ip и т.д.). Я реализовал несколько контрольных последовательностей xterm и сумел получить полностью рабочую оболочку терминала, которая должна быть способна обертывать любой процесс консоли Windows, транслировать вход xterm для ввода на вход целевой консоли приложения и обрабатывать вывод приложения в последовательности управления xterm. У меня даже есть мышь, чтобы работать. Запуск powershell.exe в качестве подпроцесса теперь решает исходную проблему запуска powershell в сеансе ssh. Cmd.exe также работает. Если кто-нибудь будет проинтервьюирован, я увижу где-нибудь размещать полный код.