有人能告诉我如何在C#中获取Windows控制台应用程序的句柄吗?在Windows窗体应用程序中,我通常会尝试this.Handle
。
答案 0 :(得分:56)
不确定是否有效,但您可以尝试:
IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
答案 1 :(得分:24)
Process.MainWindowHandle
method only works for the process that started the console FindWindowByCaption
method本来就不可靠这是一种强有力的方法:
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;
};
更改当前进程只是为了阅读某些东西是相当丑陋的(当这是一个控制台进程时,这变得非常难看,因为它需要帮助程序进程以避免终止当前控制台)。然而,进一步的调查表明,没有其他方法可以注入csrss
流程或目标流程。
控制台对应信息位于csrss.exe
(或其中众多,每个会话一个,自Vista以来),因此无法使用ReadProcessMemory
之类的内容进行检索。 csrss
公开的所有内容都是CSRSS LPC API。完整的API列表中只有一个相关函数SrvGetConsoleWindow
。并且它不接受PID,但确定an alternative implementation中的主叫方或winsrv.dll
中函数的反汇编。
答案 2 :(得分:10)
试试这个:
[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);
答案 3 :(得分:7)
我刚刚为自己解决了这个问题(不幸的是,在看到Thomas's answer之前更快)。那么,对于那些对他的答案不满意的人来说,这是另一种方式。我写这个答案是因为我想提供另一个答案+如果你将控制台视为一个窗口,那么设计Program
类的更好方法。让我们从这个设计开始:
我有点改变了Program
类的默认样式。我实际上把它变成了一个包含程序的类,而不仅仅是一个表示它并使用其他类来表示内容的方法。 (如果你不知道我的意思,不重要)。
我必须这样做的原因是因为我想编写以下事件处理程序:
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 st 参数中调用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();
}
现在,问题是你实际上无法在this
中调用Main
,这是一个静态方法,所以Main
中的任何内容都转移到了一个名为的新方法Start
以及所有Main
正在创建一个新的Program
并致电Start
。
private static void Main()
{
new Program().Start();
}
private void Start()
{
AppDomain.CurrentDomain.UnhandledException += CatchUnhandled;
throw new Exception();
}
当然,结果是一个消息框,我的控制台窗口是所有者。
将此方法用于消息框,当然只是此方法的一个应用程序。
答案 4 :(得分:1)
我认为不存在这样的事情。应用程序无法访问控制台窗口。您可能会尝试迭代进程列表,查找您自己的进程名称。 Process
类IIRC包含程序主窗口句柄的属性,可能是控制台应用程序的控制台窗口 - 我不确定。
答案 5 :(得分: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位数值,每次运行程序时都会有所不同。
答案 6 :(得分:0)
VB.Net 中关于如何在控制台窗口顶部显示 MessageBox 的另一个版本
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