誰かがC#でWindowsコンソールアプリケーションのハンドルを取得する方法を教えてもらえますか? Windows Formsアプリケーションでは、通常this.Handle
。
動作するかどうかはわかりませんが、試してみてください:
IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
これを行うための堅牢な方法を次に示します。
Console Win32 API の関連関数は次のとおりです。
_[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("kernel32.dll", SetLastError=true, ExactSpelling=true)]
static extern bool FreeConsole();
_
GetConsoleWindow()
で十分ですAttachConsole
を使用して接続し、GetConsoleWindow
を呼び出し、すぐにFreeConsole
を使用して切り離します。さらに慎重にするには、接続する前にコンソールイベントハンドラーを登録(およびデタッチ後に登録解除)して、コンソールに接続している短い時間枠でコンソールイベントが発生した場合に誤って終了しないようにします。
_[DllImport("kernel32.dll")]
static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine,
bool Add);
delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType);
enum CtrlTypes : uint {
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
bool is_attached=false;
ConsoleCtrlDelegate ConsoleCtrlDelegateDetach = delegate(CtrlType) {
if (is_attached = !FreeConsole())
Trace.Error('FreeConsole on ' + CtrlType + ': ' + new Win32Exception());
return true;
};
_
何かを読むためだけに現在のプロセスに変更を加えることはかなりugいです(これがコンソールプロセスである場合、現在のコンソールの終了を避けるためにヘルパープロセスが必要になるため、これは本当にいものになります)。それでも、さらなる調査により、csrss
プロセスまたはターゲットプロセスに注入する方法は他にないことが示されています。
コンソール通信情報は、_csrss.exe
_(またはVista以来、セッションごとに1つ)に配置されて管理されているため、ReadProcessMemory
などで取得することはできません。 csrss
が公開するのは、 CSRSS LPC API だけです。完全なAPIリストには、SrvGetConsoleWindow
という関連する関数が1つしかありません。また、PIDは受け入れませんが、 代替実装 で見られるように呼び出し側のそれを決定するか、_winsrv.dll
_で関数の逆アセンブリを決定します。
これを試して:
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
public static extern IntPtr FindWindowByCaption(IntPtr zeroOnly, string lpWindowName);
…
Console.Title = "Test";
…
IntPtr handle = FindWindowByCaption(IntPtr.Zero, Console.Title);
私は自分でこの問題を解決しました(残念ながら Thomasの答え の方がずっと早いです)。さて、彼の答えに満足していない人のための別の方法があります。コンソールをウィンドウとして扱う場合は、別の回答+ Program
クラスを設計するより良い方法を提供したいので、この回答を書いています。その設計から始めましょう:
Program
クラスのデフォルトのスタイルを少し変更しました。実際に、プログラムを含むクラスを作成しました。それを表す1つのメソッドだけでなく、コンテンツに他のクラスを使用します。 (意味がわからない場合、重要ではありません)。
私がそれをしなければならなかった理由は、次のイベントハンドラを記述したかったからです。
_private void CatchUnhandled(Object sender, UnhandledExceptionEventArgs e)
{
var exception = e.ExceptionObject as Exception;
MessageBox.Show(this, exception.Message, "Error"); // Check out 1st arg.
}
_
このメソッドをオーバーロードします MessageBox.Show(IWin32Window, String, String)
。
Consoleは _IWin32Window
_ を実装していないため、もちろん1でthis
を呼び出すために、自分で実装する必要がありましたst 引数。
ここにそれと他のすべての実装があります:
注:このコードはアプリケーションからコピーアンドペーストされています。アクセス修飾子を自由に変更できます
Program
クラス宣言:
_internal class Program : IWin32Window
{
...
}
_
_IWin32Window
_ 実装:
_public IntPtr Handle
{
get { return NativeMethods.GetConsoleWindow(); }
}
_
次のクラスを使用します。
_internal static class NativeMethods
{
[DllImport("kernel32.dll")]
internal static extern IntPtr GetConsoleWindow();
}
_
現在、問題は、静的メソッドであるthis
でMain
を実際に呼び出すことができないため、Main
にあるものはすべてStart
という名前の新しいメソッドに移動し、すべてのMain
が実行しているのは新しいProgram
を作成してStart
を呼び出すことです.
_private static void Main()
{
new Program().Start();
}
private void Start()
{
AppDomain.CurrentDomain.UnhandledException += CatchUnhandled;
throw new Exception();
}
_
もちろん、結果は所有者としてのコンソールのウィンドウを持つメッセージボックスでした。
この方法をメッセージボックスに使用することは、もちろんこの方法の1つのアプリケーションにすぎません。
そんなことはないと思います。コンソールウィンドウは、アプリケーションからアクセスできません。独自のプロセス名を探してプロセスリストを反復処理する場合があります。 Process
クラスIIRCには、プログラムのメインウィンドウハンドルのプロパティが含まれています。これはmightコンソールアプリケーションのコンソールウィンドウです。
ダイアゴスティックをコンソールにストリーミングし、マウス入力を無効にしたいコンソールアプリケーションで、GetConsoleWindow(), Process.GetCurrentProcess().MainWindowHandle, and FindWindowByCaption(IntPtr.Zero, Console.Title)
を試しました。これらはそれぞれ、ゼロ以外の同じハンドルを返しましたが、SetConsoleModeでそのハンドルを使用しようとすると、「無効なハンドル」例外がスローされました。最後に、STD_INPUT_HANDLEを-10として定義してSetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode | ENABLE_EXTENDED_FLAGS))
を試しましたが、うまくいきました。 MSのドキュメントでは、コンソールへのハンドルを再割り当てできることが示唆されており、このソリューションに満足したり満足したりすることはできませんが、これまでのところ、プログラムでクイック編集モードを無効にできるのはそれだけです。 GetStdHandle(STD_INPUT_HANDLE)
は '3'を返し、他の呼び出しはプログラムが実行されるたびに異なる7桁の値を返します。