上述不可靠的only works for the process that started the consoleThe FindWindowByCaption method is inherently Process.MainWindowHandle method
这里有一个强大的方法来实现这一点:
Console Win32 API中的相关函数包括:
代码语言:javascript运行复制[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() is 就足够了;也可以使用AttachConsole连接到该控制台;调用GetConsoleWindow,使用FreeConsole.立即断开连接
为了格外谨慎,在附加之前注册一个控制台事件处理程序(并在分离之后注销它),这样如果控制台事件在您附加到控制台的很短的时间内发生,您就不会意外地被终止:
代码语言:javascript运行复制[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。在完整的接口列表中只有一个相关的函数,即SrvGetConsoleWindow。它不接受PID,但确定调用方的PID,就像在an alternative implementation或winsrv.dll中看到的函数的反汇编一样。