我正在尝试使用C#在Windows XP上redirect已经运行的进程的标准输出。 我知道,如果我自己产生这个过程,我可以做到这一点,但是对于这个应用程序,我更喜欢一个“侦听器”,我可以附加到另一个进程。
这是纯净的.net可能,如果不是,甚至有可能与Win32?
谢谢
更新:我试图监视的多个进程都是由“门卫”进程启动的,当进程崩溃时将重新启动这些进程。 这使我很难前面做任何redirect。
在Win32中使用Detours库来完成这个工作是相当容易的。 你会看到所有的调用WriteFile,并检查他们是否要标准输出。 你可能也想看一下控制台的输出函数(比如WriteConsoleOutput),但是它们用得很少,所以你可能不需要为大部分程序使用而烦恼。
Offhand我不记得是否detours直接支持从.NET语言使用或不。 如果没有,我想你仍然可以通过P / Invoke来使用它,但是我不认为它会很漂亮。
编辑:有各种类似(免费)的图书馆。 举一个例子,杰弗里·里希特(Jeffrey Richter)的书“ 高级Windows(Advanced Windows)”曾经包含一个应该为此目的而工作的书 快速查看表明,他目前的Windows通过C / C ++仍然包含“DLL注入和API挂钩”部分。 这可能包括(和更新版本)相同的代码,这应该是足够的这种工作。
SetOut方法允许您重定向标准输出。
var sb = new StringBuilder(); using (var writer = new StringWriter(sb)) { Console.SetOut(writer); Console.WriteLine("Hello World"); } var result = sb.ToString(); // The result variable will contain Hello World\r\n
我没有实际的经验,但我认为你应该看看这个StackOverflow的问题 。 下一步将是打开与阅读器相关的对象,并以某种方式确定哪一个是标准输出和错误。 我怀疑你将能够劫持手柄。 例如,假设一些其他进程已经重定向了标准输出并拥有一个句柄,甚至可能使用某个IPC来让其他进程也可以处理的情况。
对不起,这是不可能的。 我自己想知道这个。
这将做你所寻找的,我不知道你是否使用C ++,所以我只是使用C约定。 在使用之前,您需要先清理干净,然后确保关闭手柄,否则会漏水。
// RunCmd.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> #include <strsafe.h> int RunCmd(_TCHAR * Command,_TCHAR **OutPut); bool HasTerminated(PROCESS_INFORMATION PI,DWORD *ExitCode); bool HasData(HANDLE H); void ErrorExit(LPTSTR lpszFunction); int _tmain(int argc, _TCHAR* argv[]) { _TCHAR * Buffer; _TCHAR CmdLine[] = _TEXT("Outputter.exe"); RunCmd(CmdLine,&Buffer); wprintf(_TEXT("Buffer from other pgm \n%s"),Buffer); free(Buffer); } int RunCmd(_TCHAR * Command,_TCHAR ** OutPut) { _TCHAR * CpBUff = NULL; STARTUPINFO SI; memset(&SI,0,sizeof(SI)); *OutPut = NULL; SECURITY_ATTRIBUTES SA; SA.nLength = sizeof(SECURITY_ATTRIBUTES); SA.lpSecurityDescriptor = NULL; SA.bInheritHandle = true; HANDLE ReadOutPut, WriteOutPut; if(!CreatePipe(&ReadOutPut,&WriteOutPut,&SA,0)) { wprintf(_TEXT("Error")); } SI.hStdOutput = WriteOutPut; SI.cb = sizeof(STARTUPINFO); SI.dwFlags = STARTF_USESTDHANDLES; PROCESS_INFORMATION PI; if (!CreateProcess(NULL,Command,&SA,NULL,true,CREATE_NO_WINDOW,NULL,NULL,&SI,&PI)) { ErrorExit(TEXT("CreateProcess")); } Sleep(500); DWORD ExitCode; char Buffer[512]; _TCHAR ConvBuff[512]; int Total =0; bool Zero; while (!HasTerminated(PI,&ExitCode) & HasData(ReadOutPut)) { ZeroMemory(Buffer,512*sizeof(char)); ZeroMemory(ConvBuff,512 * sizeof(_TCHAR)); DWORD NumBytesRead; ReadFile(ReadOutPut,Buffer,512,&NumBytesRead,NULL); Zero = Total == 0; Total += NumBytesRead +1; *OutPut = ((_TCHAR *) realloc(*OutPut,Total*sizeof(_TCHAR))); if(Zero) { ZeroMemory(*OutPut,Total * sizeof(_TCHAR)); } size_t ConChar; mbstowcs_s(&ConChar,ConvBuff,strlen(Buffer)+1,Buffer,511); StringCchCat(*OutPut,Total,ConvBuff); } CloseHandle(PI.hProcess); CloseHandle(PI.hThread); return ExitCode; } bool HasTerminated(PROCESS_INFORMATION PI,DWORD *ExitCode) { return (STILL_ACTIVE == GetExitCodeProcess(PI.hProcess,ExitCode)); } bool HasData(HANDLE H) { char Buffer[25]; DWORD ReadBytes,TotalBytes,TotalLeft; PeekNamedPipe(H,Buffer,25,&ReadBytes,&TotalBytes,&TotalLeft); return ReadBytes > 0; } void ErrorExit(LPTSTR lpszFunction) { // Retrieve the system error message for the last-error code LPVOID lpMsgBuf; LPVOID lpDisplayBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); // Display the error message and exit the process lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR), TEXT("%s failed with error %d: %s"), lpszFunction, dw, lpMsgBuf); MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); LocalFree(lpMsgBuf); LocalFree(lpDisplayBuf); ExitProcess(dw); }