c# - 重定向正在运行的进程的输出 (Visual C#)
问题描述
我有一个正在运行的控制台,我需要获取输出。我不能startprocess
用来启动控制台,因为它是单独生成的。我无权访问源代码,我只是试图在控制台已经运行时重定向输出。
解决方案
事实证明,使用托管框架附加到已经运行的单独进程是不可能的。
Console Api Functions
但是,可以使用under来实现这一点kernel32.dll
。
编辑:改进了代码以获得更好的可用性
为了实现这一点,我们需要使用FreeConsole
, AttachConsole
, ReadConsoleOutputCharacter
, GetConsoleScreenBufferInfo
and AttachConsole
fromWinApi
静态外部库的声明:
[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
添加到ReadALineOfConsoleOutput
用于同步标准输出的 currentPosition 的功能GetConsoleScreenBufferInfo
用于获取lineSize
控制台short lineSize = outInfo.dwSize.X
为 lineSize 添加
uint numberofLinesToRead = (uint) (outInfo.dwCursorPosition.Y - currentPosition)
用于使用控制台的实际位置和光标的当前位置之间的差异来计算要读取的行数。- 考虑
lpNumberOfCharsRead
避免垃圾行结束
推荐阅读
- php - 来自php的DocuSign
- apache - 禁用重定向到根路径/Apache HTTPD
- node.js - 如何从 S3 存储桶读取大型 XML 文件,然后使用 AWS Lambda 将其用作 HTTP 请求正文
- sql - 如何使用 puppeteer 将图像值推送到数据库?
- python-3.x - strptime() 无法读取时间格式,尽管理论上是正确的
- appium - Robotframework 当资源ID相同时,有什么方法可以检查元素状态
- firebase - 面临将 vuex 数据添加到 Firestore 的问题
- java - 在 Spring Boot 中使用 ldap 时凭据错误
- c# - 如何使用 iText7 从 PDF 文件中读取特定部分?
- react-native - X轴标签在react-native svg-charts中重叠