#include
#include
typedef void (__stdcall* SNIFFER_THREAD_START_ROUTINE)( HANDLE hRead, HANDLE hWrite, LPVOID userfunparam );
struct SnfParam_
{
SNIFFER_THREAD_START_ROUTINE userfunction;
HANDLE hRead;
HANDLE hWrite;
LPVOID userfunparam;
};
DWORD __stdcall sniffer_( LPVOID lpParam )
{
SnfParam_& ps = *(SnfParam_*)lpParam;
(*ps.userfunction)( ps.hRead, ps.hWrite, ps.userfunparam );
return 0;
}
#define IF_BAD_GOTO(EXPR,LABEL) if( !(EXPR) ) goto LABEL
#define CHECK(EXPR) if( !(EXPR) ) goto error
#define CLOSEHANDLE(H) if(INVALID_HANDLE_VALUE!=H) CloseHandle(H)
bool redirector( LPCTSTR cmd, SNIFFER_THREAD_START_ROUTINE lpSnfStartAddress, LPVOID lpSnfParam, LPDWORD lpRetVal=0, WORD wShowWindow=SW_HIDE
, LPSECURITY_ATTRIBUTES lpCmdProcessAttributes=0, LPSECURITY_ATTRIBUTES lpCmdThreadAttributes=0, DWORD dwCmdCreationFlags=NORMAL_PRIORITY_CLASS, LPVOID lpCmdEnvironment=0, LPCTSTR lpCmdCurrentDirectory=0
, LPSECURITY_ATTRIBUTES lpSfrThreadAttributes=0, SIZE_T dwSfrStackSize=0 // sniffer
)
{
HANDLE hInput=INVALID_HANDLE_VALUE, hOutput=INVALID_HANDLE_VALUE, hError=INVALID_HANDLE_VALUE;
HANDLE hRead_=INVALID_HANDLE_VALUE, hWrite_=INVALID_HANDLE_VALUE, hRead=INVALID_HANDLE_VALUE , hWrite=INVALID_HANDLE_VALUE;
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), 0, TRUE };
HANDLE hProc = GetCurrentProcess();
SnfParam_ sp;
HANDLE hSnf = INVALID_HANDLE_VALUE;
STARTUPINFO si;
LPTSTR cmdline = 0;
// 创建管道
CHECK( CreatePipe(&hInput,&hWrite_,&sa,0) );
CHECK( CreatePipe(&hRead_,&hOutput,&sa,0) );
CHECK( DuplicateHandle(hProc,hOutput,hProc,&hError,0,TRUE,DUPLICATE_SAME_ACCESS) ); // 防止被获取数据的进程关闭hOutput时hError同时实效
CHECK( DuplicateHandle(hProc,hRead_,hProc,&hRead,0,FALSE,DUPLICATE_SAME_ACCESS) ); // 不可继承
CHECK( DuplicateHandle(hProc,hWrite_,hProc,&hWrite,0,FALSE,DUPLICATE_SAME_ACCESS) ); // 不可继承
CloseHandle(hRead_); hRead_=INVALID_HANDLE_VALUE;
CloseHandle(hWrite_); hWrite_=INVALID_HANDLE_VALUE;
// 创建获取数据的线程
sp.userfunction = lpSnfStartAddress;
sp.userfunparam = lpSnfParam;
sp.hRead = hRead;
sp.hWrite = hWrite;
hSnf = CreateThread( lpSfrThreadAttributes, dwSfrStackSize, &sniffer_, &sp, 0, 0 );
CHECK( hSnf );
// 创建被获取数据的进程
GetStartupInfo( &si );
si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.wShowWindow = wShowWindow;
si.hStdInput = hInput;
si.hStdOutput = hOutput;
si.hStdError = hError;
PROCESS_INFORMATION pi;
cmdline = _tcsdup( cmd );
CHECK( cmdline );
CHECK( CreateProcess(NULL,cmdline,lpCmdProcessAttributes,lpCmdThreadAttributes,TRUE,dwCmdCreationFlags,lpCmdEnvironment,lpCmdCurrentDirectory,&si,&pi) );
free(cmdline); cmdline=0;
// 等待被获取数据的进程退出
CHECK( WAIT_FAILED != WaitForSingleObject(pi.hProcess,INFINITE) );
// 获取被获取数据的进程退出码
if(lpRetVal) GetExitCodeProcess(pi.hProcess,lpRetVal);
// 关闭被获取数据的进程句柄
CloseHandle(pi.hThread ); pi.hThread =INVALID_HANDLE_VALUE;
CloseHandle(pi.hProcess); pi.hProcess=INVALID_HANDLE_VALUE;
// 关闭被获取数据的进程使用到的句柄
CloseHandle(hInput ); hInput =INVALID_HANDLE_VALUE;
CloseHandle(hOutput); hOutput=INVALID_HANDLE_VALUE;
CloseHandle(hError ); hError =INVALID_HANDLE_VALUE;
// 等待获取数据的线程退出
CHECK( WAIT_FAILED != WaitForSingleObject(hSnf,INFINITE) );
// 关闭获取数据的线程句柄
CloseHandle(hSnf); hSnf=INVALID_HANDLE_VALUE;
// 关闭获取数据的线程使用到的句柄
CloseHandle(hRead ); hRead =INVALID_HANDLE_VALUE;
CloseHandle(hWrite); hWrite=INVALID_HANDLE_VALUE;
// 返回
return true;
error:
CLOSEHANDLE( pi.hProcess );
CLOSEHANDLE( pi.hThread );
free( cmdline );
CLOSEHANDLE( hSnf );
CLOSEHANDLE( hInput );
CLOSEHANDLE( hOutput );
CLOSEHANDLE( hError );
CLOSEHANDLE( hRead );
CLOSEHANDLE( hWrite );
CLOSEHANDLE( hRead_ );
CLOSEHANDLE( hWrite_ );
return false;
}
#include
#include
#include
using namespace std;
void __stdcall foo( HANDLE hRead, HANDLE hWrite, LPVOID userfunparam )
{
TCHAR buf[100] = _T("test\n");
DWORD dwRead;
BOOL ret = WriteFile( hWrite, buf, (DWORD)_tcslen(buf)*sizeof(buf[0]), &dwRead, 0 );
assert( ret && dwRead==_tcslen(buf)*sizeof(buf[0]) );
while( ReadFile(hRead,buf,sizeof(buf),&dwRead,0) )
{
_tprintf( _T("%.*s"), dwRead/sizeof(buf[0]), buf );
}
}
int main( int argc, char** agrv )
{
if( argc == 1 )
{
cout << "----------------------------" << endl;
DWORD ret;
BOOL f = redirector( _T("debug\\cpp16.exe x"), &foo, 0, &ret );
cout << "----------------------------" << endl;
if( f )
cout << "redirector success, and cmd return " << ret << '.' << endl;
else
cout << "redirector failed." << endl;
}
else
{
string str;
cin >> str;
cout << str << endl;
}
return 0;
}
几个疑问:
1。如果使用UNICODE方式,那么ReadFile读到的不是 0074 0065 0073 0074 000d 000a,而是
0074 0065 0073 0074 0a0d,还有可能是更奇怪的结果。按理应当加上 cmd.exe /U
/C,但还是错误。
2。如果被获取数据的程序同时使用 cout(有缓冲标准输出),cerr(无缓冲错误输出), clog(有缓冲错误输出)
,fprintf(stdout,...),fprintf(stderr,...)那么获取到的次序有点混乱。用 cmd.exe /C app
1>log.txt 2>&1 也同样如此,估计是没办法了。
3。对于直接写屏函数的输出,比如 _cputs,那么无法获取到。用
cmd.exe /C app 1>log.txt 2>&1
也同样如此,估计是没办法了。
4。对于DOS16程序,向标准错误设备的输出,比如 fprintf(stderr,...) ,在 xp 下可以获取到,但在
vista 下不行。
阅读(1053) | 评论(0) | 转发(0) |