JPBlanc の提案に従って PowerShellInside をインストールしましたが、あまり長く使用していませんでした。1 つの接続ということはあまりにも制限的であり、私は制限されるのが好きではありません (特に、その制限が利益に基づくものである場合、それは私が踏み込むべきではない別の議論です)。また、元の問題の解決策であるにもかかわらず、私が遭遇したプログラミングの問題を解決していないため、満足のいくものではありません。
ただし、最終的には、ラッパー プロセスで Windows API 呼び出しを使用して、この問題を解決することができました。かなりの数の落とし穴があるため、私は自分自身の質問に答えて、同じ問題を見ている他の人にいくつかの指針を与えることにしました。基本的な構造は次のとおりです。
- リダイレクトされた stdin/-out (および必要に応じて stderr) を使用してラッパー プロセスを開始します。(私の場合、stdin と out は xterm 制御シーケンスとデータのストリームになります。これが ssh の方法だからです)
- GetStdHandle() を使用して、リダイレクトされた入力ハンドルと出力ハンドルを取得します。次に SetStdHandle() を "CONIN$" と "CONOUT$" の CreateFile() に渡し、子プロセスがコンソールを継承し、ラッパー プロセスのリダイレクトを持たないようにします。(createfile には、継承を許可するセキュリティ記述子が必要であることに注意してください)
- コンソール モード、サイズ、タイトル、Ctrl-C ハンドラーなどをセットアップします。注: Unicode サポートが必要な場合は、必ずフォントを設定してください。Lucida Console (.FontFamily = 54, .FaceName = "Lucida Console") を使用しました。これがないと、コンソール出力から文字を読み取ると、コードページ化されたバージョンが返されます。これは、マネージ コードで操作するには恐ろしいものです。
- 出力の読み取りは SetWinEventHook() で行うことができます。コンテキスト外通知を必ず使用してください。マネージ アプリケーションを別のプロセス コンテキスト/アドレス空間で突然実行することは、悪い考え™ (I'私も試していないことを確信しています)。このイベントは、自分のコンソール ウィンドウだけでなく、すべてのコンソール ウィンドウに対して発生します。そのため、コールバックへのすべての呼び出しをウィンドウ ハンドルでフィルタリングします。GetConsoleWindow() を使用して、現在のコンソール アプリケーションのウィンドウ ハンドルを取得します。また、アプリケーションが完了したらコールバックをフック解除することを忘れないでください。
- この時点までは、System.Console クラスを使用 (または負荷の原因となるようなこと) をしないでください。この時点以降の使用は、サブプロセスが出力に書き込んだかのように動作します。
- 必要なサブプロセスを生成します (注: .UseShellExecute = false を使用する必要があります。そうしないと、コンソールを継承しません)
- WriteConsoleInput() を使用して、コンソールへの入力の提供を開始できます。
- この時点で (または別のスレッドで)、Windows メッセージ ループを実行する必要があります。そうしないと、コンソール イベント通知のコールバックを受信できません。これを行うには、パラメーターなしの Application.Run() を使用するだけです。メッセージ ループを中断するには、ある時点で終了メッセージをメッセージ ループに投稿する必要があります。サブプロセスの .Exited イベントで Application.Exit() を使用してこれを行いました。(これを機能させるには .EnableRaisingEvents を使用することに注意してください)
- コンソールで何かが変更されたときに、勝利イベントのコールバックが呼び出されるようになりました。スクロール イベントに注意してください。これは、予期しない動作をする可能性があります。また、同期配信についても想定しないでください。サブプロセスが 3 行を書き込む場合、最初のイベントを処理するまでに、残りの 3 行は既に書き込まれている可能性があります。公平を期すために言うと、Windows は、単一の文字の変更に圧倒されず、変更についていくことができるように、イベントを構成するという優れた仕事をします。
- 入力または出力のどこかに文字が含まれている場合は、必ずすべての PInvoke 定義を CharSet=CharSet.Unicode でマークしてください。PInvoke.net は、これらのかなりの数を見逃していました。
これらすべての最終結果: Windows コンソール API のラッパー アプリケーション。ラッパーは、リダイレクトされた stdin と stdout を読み書きして、世界と通信できます。もちろん、気を使いたい場合は、ここで任意のストリーム (名前付きパイプ、tcp/ip など) を使用できます。いくつかの xterm 制御シーケンスを実装し、Windows コンソール プロセスをラップし、xterm 入力をターゲット アプリケーションのコンソール入力の入力に変換し、アプリケーションの出力を xterm 制御シーケンスに処理できる、完全に機能するターミナル ラッパーを取得することができました。マウスも動かせました。サブ プロセスとして powershell.exe を開始すると、ssh セッションで powershell を実行する際の元の問題が解決されるようになりました。Cmd.exe も動作します。誰かが興味を持っている場合は、完全なコードをどこかに投稿することについて確認します。