Chinaunix首页 | 论坛 | 博客
  • 博客访问: 990898
  • 博文数量: 158
  • 博客积分: 4380
  • 博客等级: 上校
  • 技术积分: 2367
  • 用 户 组: 普通用户
  • 注册时间: 2006-09-21 10:45
文章分类

全部博文(158)

文章存档

2012年(158)

我的朋友

分类: C/C++

2012-11-23 15:59:10

#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) |
给主人留下些什么吧!~~