2009-10-15 4 views
4

C#을 사용하여 Windows XP에서 이미 실행중인 프로세스의 표준 출력을 리디렉션하려고합니다. 내가 직접 프로세스를 생성하면이 작업을 수행 할 수 있음을 알고 있지만이 애플리케이션에서는 다른 프로세스에 첨부 할 수있는 "수신기"를 선호합니다.표준을 납치 할 수 있습니까?

순수한 .Net에서 가능합니까? 그렇다면 Win32에서도 가능하지 않습니까?

감사

UPDATE : 모두가 충돌하는 경우 이러한 프로세스를 다시 시작하는 "게이트 키퍼"프로세스에 의해 시작되는 모니터에 내가 노력하고 여러 프로세스가 있습니다. 이로 인해 내가 리다이렉션하는 것이 어렵다.

+0

이미 실행중인 응용 프로그램에 대한 소스를 제어합니까? 또는이 타사 응용 프로그램을 스크래핑하고 싶습니까? – user7116

+0

응용 프로그램을 .NET 어셈블리로 래핑 할 수 있습니까? 의미는 당신이 작성한 코드 내에서 프로세스로 시작하거나, 이런 식으로 끝나면 실패하는 서비스입니다. –

+0

@sixlettervariables : 자체 응용 프로그램이지만 코드를 소유하고 있지 않으므로 변경하기가 어려울 수 있습니다. @ Agent_9191 : 귀하의 의견을 해결하기 위해 질문을 업데이트했습니다. – Justin

답변

3

Detours Library을 사용하여 Win32에서 이것을 쉽게 수행 할 수 있습니다. 상당히입니다. WriteFile에 대한 모든 호출을 살펴보고 표준 출력 여부를 확인하십시오. 또한 콘솔 출력 기능 (예 : WriteConsoleOutput)을 살펴볼 수도 있지만 거의 사용되지 않아 대부분의 프로그램에서 사용하지 않아도됩니다.

Offhand 우회로가 .NET 언어에서의 사용을 직접 지원하는지 여부를 기억하지 않습니다. 그렇지 않다면 P/Invoke를 통해 여전히 사용할 수 있다고 생각하지만 꽤 예쁘다고 생각하지는 않습니다.

편집 : 여러 가지 비슷한 (무료) 라이브러리가 주위에 있습니다. 예를 들어 Jeffrey Richter의 서적 고급 Windows에는이 용도로 사용해야하는 책이 포함되어 있습니다. 빠른보기는 그의 현재 C/C++을 통한 Windows에는 여전히 "DLL 주입 및 API 후킹"섹션이 포함되어 있음을 나타냅니다. 아마 같은 종류의 작업에 적합한 동일한 코드가 포함 된 (그리고 업데이트 된 버전) 것입니다.

+0

매우 흥미 롭다. 나는 전에 이것을 본 적이 없지만 정말 멋지다. 나는 그것을 조사 할 것입니다. – Justin

+2

불행히도 detours 라이센스는 시간당 $ 10,000의 수수료를 지불하지 않으면 상업적 환경에서 라이센스를 사용하지 못하도록 제한합니다. 이렇게, 차가운 동안 이것은 간다. – Justin

1

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 
+2

이것은 자신의 콘솔에서만 작동하며 다른 실행중인 프로세스의 표준 출력에서는 작동하지 않습니다. – itowlson

+0

나는 리다이렉트하려고하는 과정의 코드를 가지고 있지 않다. – Justin

0

사실은이 일의 경험이없는,하지만 난 당신이 StackOverflow question을 살펴한다고 생각합니다. 다음 단계는 thos 핸들과 연관된 객체를 읽기 위해 열고 표준 출력과 오류를 어느 정도 결정하는 것입니다. 네가 그 손잡이를 공중 납치 할 수 있을지 의심 스럽다. 예를 들어, 다른 프로세스가 이미 표준 출력을 리다이렉트하고 핸들을 가지고있을 때 어떤 IPC를 사용하여 다른 프로세스에도 핸들링 할 수있는 시나리오를 상상해보십시오.

가능한지 확실하지 않은 점에 대해 사과드립니다. 나는이 사실을 알고 싶다.

+0

나는 이것을 보게 될 것이다 – Justin

0

이것은 내가 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); 
} 
관련 문제