53

C# で Windows コンソール アプリケーションのハンドルを取得する方法を教えてもらえますか? Windows フォーム アプリケーションでは、通常はthis.Handle.

4

7 に答える 7

69

うまくいくかどうかはわかりませんが、試すことができます:

IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
于 2009-08-14T12:33:36.217 に答える
31

これを行うための堅牢な方法を次に示します。

コンソール 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、 callGetConsoleWindowを使用してそれにアタッチし、 ですぐにデタッチし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;
};

何かを読み取るためだけに現在のプロセスに変更を加えるのはかなり見苦しいものです (これがコンソール プロセスの場合、現在のコンソールの終了を回避するためにヘルパー プロセスが必要になるため、これは非常に見苦しくなります)。csrssそれにもかかわらず、さらに調査すると、プロセスまたはターゲット プロセスに注入する以外に方法がないことがわかります。

コンソールの対応情報はcsrss.exe(または、Vista 以降、セッションごとに 1 つずつ、多数の) に配置され、管理されているため、ReadProcessMemory. csrss公開するのはCSRSS LPC APIだけです。完全な API リストの中で、関連する関数は 1 つだけSrvGetConsoleWindowです。また、PID を受け入れませんが、別の実装または の関数の逆アセンブリに見られるように、呼び出し側のそれを決定しwinsrv.dllます。

于 2015-02-19T21:03:22.813 に答える
11

これを試して:

[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);
于 2011-02-04T07:32:29.127 に答える
8

私はこの問題を自分で解決しました(残念ながら、はるかに速いトーマスの答えを見る前に)。さて、彼の答えに満足できない人のために別の方法があります。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を呼び出すために自分で実装する必要がありthisました。

それと他のすべての実装は次のとおりです。

注: このコードは私のアプリケーションからコピーして貼り付けたものです。アクセス修飾子は自由に変更できます。

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();
}

さて、問題は、静的メソッドである in を実際thisに呼び出すことができないことです.MainMainStartMainProgramStart

private static void Main()
{
    new Program().Start();
}

private void Start()
{
    AppDomain.CurrentDomain.UnhandledException += CatchUnhandled;

    throw new Exception();
}

もちろん、その結果は、私のコンソールのウィンドウを所有者とするメッセージ ボックスでした。
このメソッドをメッセージ ボックスに使用することは、もちろん、このメソッドの 1 つのアプリケーションにすぎません。

于 2013-02-24T04:53:39.533 に答える
1

そんなことはないと思います。アプリケーションからコンソール ウィンドウにアクセスできません。あなた自身のプロセス名を探して、プロセスリストを反復しようとするかもしれません. Processクラス IIRC には、プログラムのメイン ウィンドウ ハンドルのプロパティが含まれています。これは、コンソール アプリケーションのコンソール ウィンドウである可能性がありますが、よくわかりません。

于 2009-08-14T12:29:42.583 に答える
0

診断をコンソールにストリーミングし、マウス入力を無効にしたいコンソールアプリケーションで、 GetConsoleWindow(), Process.GetCurrentProcess().MainWindowHandle, and FindWindowByCaption(IntPtr.Zero, Console.Title). これらのそれぞれがゼロ以外の同じハンドルを返しましたが、SetConsoleMode でそのハンドルを使用しようとすると、「無効なハンドル」例外がスローされました。最後にSetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode | ENABLE_EXTENDED_FLAGS))、STD_INPUT_HANDLE を -10 として定義してみましたが、うまくいきました。MS のドキュメントは、コンソールへのハンドルが再割り当てされる可能性があることを示唆しており、私はこの解決策に満足していません。GetStdHandle(STD_INPUT_HANDLE)'3' を返します。他の呼び出しは、プログラムが実行されるたびに変化する 7 桁の値を返します。

于 2017-06-21T20:08:48.243 に答える
0

コンソール ウィンドウの上に MessageBox を表示する方法に関する VB.Net のもう 1 つのバージョン

Imports System.Runtime.InteropServices
Imports System.Windows.Forms

Friend Module NativeMethods
    <DllImport("kernel32.dll")> Friend Function GetConsoleWindow() As IntPtr
    End Function
End Module

NotInheritable Class WndProxy
    Implements IWin32Window
    ReadOnly Property Handle As IntPtr Implements IWin32Window.Handle
    Sub New(_hwnd As IntPtr)
        Handle = _hwnd
    End Sub
End Class

Module Module1

    Sub Main()
        ' using MainWindowHandle
        Dim w = New WndProxy(Process.GetCurrentProcess().MainWindowHandle)
        MessageBox.Show(w, "Hi")
        ' using GetConsoleWindow api
        Dim s = New WndProxy(NativeMethods.GetConsoleWindow)
        MessageBox.Show(s, "Hi")
    End Sub

End Module
于 2021-03-23T15:30:42.317 に答える