从运行中的进程重定向输出(Visual C#)

时间:2019-01-22 21:57:35

标签: c# output io-redirection

我有一个正在运行的控制台,我需要获取输出。我无法使用startprocess来启动控制台,因为它是单独产生的。我无权访问源代码,我只是想在控制台已经运行时从控制台重定向输出。

2 个答案:

答案 0 :(得分:6)

事实证明,不可能使用托管框架将其附加到已经在运行的单独进程中。

但是,可以使用Console Api Functions下的kernel32.dll实现这一目标。

编辑:对代码进行了改进,以提高可用性

为了实现这一点,我们需要使用{中的FreeConsoleAttachConsoleReadConsoleOutputCharacter GetConsoleScreenBufferInfo AttachConsole {1}}

静态外部库的声明:

WinApi

我们首先需要释放当前的控制台句柄,因为我们只能附加到单个控制台

[DllImport("kernel32.dll")]
private extern static IntPtr GetStdHandle(int nStdHandle);

[DllImport("kernel32.dll")]
static extern bool ReadConsoleOutputCharacter(IntPtr hConsoleOutput,
  [Out] StringBuilder lpCharacter, uint nLength, COORD dwReadCoord,
  out uint lpNumberOfCharsRead);

[DllImport("kernel32.dll")]
static extern bool FreeConsole();
[DllImport("kernel32.dll")]
static extern bool AttachConsole(int dwProcessId);

[DllImport("kernel32.dll")]
static extern bool GetConsoleScreenBufferInfo(
    IntPtr hConsoleOutput,
    out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo
);

[StructLayout(LayoutKind.Sequential)]
struct COORD
{
    public short X;
    public short Y;
}

[StructLayout(LayoutKind.Sequential)]
struct CONSOLE_SCREEN_BUFFER_INFO
{

    public COORD dwSize;
    public COORD dwCursorPosition;
    public short wAttributes;
    public SMALL_RECT srWindow;
    public COORD dwMaximumWindowSize;

}

[StructLayout(LayoutKind.Sequential)]
struct SMALL_RECT
{

    public short Left;
    public short Top;
    public short Right;
    public short Bottom;

}

const int STD_OUTPUT_HANDLE = -11;
const Int64 INVALID_HANDLE_VALUE = -1;

改进

  • private static string ReadALineOfConsoleOutput(IntPtr stdout, ref short currentPosition) { if (stdout.ToInt32() == INVALID_HANDLE_VALUE) throw new Win32Exception(); //Get Console Info if (!GetConsoleScreenBufferInfo(stdout, out CONSOLE_SCREEN_BUFFER_INFO outInfo)) throw new Win32Exception(); //Gets Console Output Line Size short lineSize = outInfo.dwSize.X; //Calculates Number of Lines to be read uint numberofLinesToRead = (uint)(outInfo.dwCursorPosition.Y - currentPosition); if (numberofLinesToRead < 1) return null; // read from the first character of the first line (0, 0). COORD dwReadCoord; dwReadCoord.X = 0; dwReadCoord.Y = currentPosition; //total characters to be read uint nLength = (uint)lineSize * numberofLinesToRead + 2*numberofLinesToRead; StringBuilder result = new StringBuilder((int)nLength); StringBuilder lpCharacter = new StringBuilder(lineSize); for (int i = 0; i < numberofLinesToRead; i++) { if (!ReadConsoleOutputCharacter(stdout, lpCharacter, (uint) lineSize, dwReadCoord, out uint lpNumberOfCharsRead)) throw new Win32Exception(); result.AppendLine(lpCharacter.ToString(0, (int)lpNumberOfCharsRead-1)); dwReadCoord.Y++; } currentPosition = outInfo.dwCursorPosition.Y; return result.ToString(); } public static async Task Main() { var processId = 8560; if (!FreeConsole()) return ; if (!AttachConsole(processId)) return; IntPtr stdout = GetStdHandle(STD_OUTPUT_HANDLE); short currentPosition = 0; while (true) { var r1 = ReadALineOfConsoleOutput(stdout, ref currentPosition); if (r1 != null) //write to file or somewhere => //Debug.WriteLine(r1); } } 已添加到ref short currentPosition函数中,用于同步标准输出的currentPosition
  • ReadALineOfConsoleOutput用于获取GetConsoleScreenBufferInfo的控制台
    • lineSize被添加为lineSize
  • short lineSize = outInfo.dwSize.X用于通过控制台的实际位置与光标的当前位置之间的差来计算要读取的行数。
  • 考虑使用uint numberofLinesToRead = (uint) (outInfo.dwCursorPosition.Y - currentPosition)避免垃圾行结尾

答案 1 :(得分:-1)

您需要阅读  https://support.microsoft.com/en-us/help/318804/how-to-set-a-windows-hook-in-visual-c-net具体是底部

  

.NET Framework不支持全局挂钩   除了WH_KEYBOARD_LL低级挂钩和WH_MOUSE_LL低级挂钩,您无法在Microsoft .NET Framework中实现全局挂钩。 要安装全局钩子,钩子必须具有本机DLL导出,才能将自身注入到另一个需要有效,一致函数才能调用的进程中。此行为需要DLL导出。 .NET Framework不支持DLL导出。 托管代码不具有函数指针一致值的概念,因为这些函数指针是动态生成的代理。   在安装钩子的线程上调用低级钩子过程