预备知识:
SECURITY_ATTRIBUTES
该结构包含一个
对象
的安全描述符,并指定
检索
到指定这个
结构
的句柄是否是可继承的。这种结构提供了安全设置的CreateFile,CREATEPIPE,CreateProcess的,RegCreateKeyEx的,或RegSaveKeyEx 各种功能,如创建的对象。
typedef的结构_SECURITY_ATTRIBUTES {
DWORD nLength; / /结构体的大小,可用SIZEOF取得
LPVOID lpSecurityDescriptor; / /
安全描述符
BOOL bInheritHandle ;/ /安全描述的对象能否被新创建ÆÆ的进程继承
} SECURITY_ATTRIBUTES,* PSECURITY_ATTRIBUTES;
STARTUPINFO结构 该结构用于指定新进程的主窗口特性
PROCESS_INFORMATION 结构
typedef struct_PROCESS_INFORMATION{
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
}PROCESS_INFORMATION;
其中成员含义如下。
① hProcess:返回新进程的句柄。
② hThread:返回
主线程的句柄。
创建到终止,该值始终有效。
建到终止,该值始终有效。
CreateProcess()
readFile()
此处使用readFile()读取管道;管道不支持异步读写,所以在读的时候经常会卡在readFile()这里,readFile()返回条件:
The ReadFile function returns when one of the following conditions occur:
A write operation completes on the write end of the pipe.
The number of bytes requested is read.
An error occurs.
所以采用创建子线程读取管道内容,避免主线程卡死;
GetExitCodeProcess()
BOOL WINAPI GetExitCodeProcess(
__in HANDLE hProcess,
__out LPDWORD lpExitCode
);
获取一个已中断进程的退出代码
返回值:
Long,非零表示成功,零表示失败。会设置GetLastError
参数表:
hProcess Long,想获取退出代码的一个进程的句柄
lpExitCode Long,用于装载进程退出代码的一个长整数
变量。如进程尚未中止,则设为常数STILL_ACTIVE
管道:
管道(Pipe)实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机。一个进程在向管道写入数据后,另一进程就可以从管道的另一端将其读取出来。匿名管道(Anonymous Pipes)是在父进程和子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信。
匿名管道由CreatePipe()函数创建,该函数在创建匿名管道的同时返回两个句柄:管道读句柄和管道写句柄。CreatePipe()的函数原型为:
BOOL CreatePipe(PHANDLE hReadPipe, // 指向读句柄的指针
PHANDLE hWritePipe, // 指向写句柄的指针
LPSECURITY_ATTRIBUTES lpPipeAttributes, // 指向安全属性的指针
DWORD nSize // 管道大小
);
原文地址:http://blog.youkuaiyun.com/zfmcmm/article/details/11895917
代码:
BOOL CTestItem::fnExecuetTask(CString &csTaskPath)
{
ACT_INTERRUPT
CString csErrorInfo;
CString csInfo;
SECURITY_ATTRIBUTES sa;
HANDLE hRead,hWrite;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
if (!CreatePipe(&hRead,&hWrite,&sa,0))
{
csErrorInfo.Format("CreatePipe()错误\r\n");
OutputText(1,csErrorInfo,RGB(255,0,0));
return FALSE;
}
STARTUPINFO si;
ZeroMemory(&si,sizeof(si));
PROCESS_INFORMATION pi;
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.hStdError = hWrite;
si.hStdOutput = hWrite;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
//创建子进程,在测试代码中子进程启动时会有两个进程cmd.exe 和(win7中)conhost.exe,后者应该是从父进程继承,csTaskPath是要执行的命令行.bat文件
if (!CreateProcess((LPSTR)(LPCTSTR)csTaskPath,NULL,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi))
{
csErrorInfo.Format("CreateProcess()错误\r\n");
OutputText(1,csErrorInfo,RGB(255,0,0));
return FALSE;
}
//创建线程读取管道内容(管道不支持异步读写)
CONSOLE *paramEx = new CONSOLE;
paramEx->hRead = hRead;
paramEx->m_pPlatUI = this->m_pPlatUI;
HANDLE hThreadRead = (HANDLE)_beginthread(fnReadPipeThread,0,(void *)paramEx);
if (-1 == (int)hThreadRead)
{
csErrorInfo.Format("_beginthread()错误\r\n");
OutputText(1,csErrorInfo,RGB(255,0,0));
return FALSE;
}
DWORD dwExitCode;
while(TRUE)
{
//判断进程是否退出;
GetExitCodeProcess(pi.hProcess,&dwExitCode);
if (dwExitCode != STILL_ACTIVE)
{
break;
}
//如果测试中断
if(IsTestStop())
{
//结束进程
if (pi.hProcess)
{
GetExitCodeProcess(pi.hProcess,&dwExitCode);
if (!TerminateProcess(pi.hProcess,dwExitCode))//强制结束进程,在测试程序中,此处只能关闭cmd.exe不能关闭conhost.exe
{
csErrorInfo.Format("TerminateProcess()错误\r\n");
OutputText(1,csErrorInfo,RGB(255,0,0));
return FALSE;
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
//关闭子进程继承的控制台窗口(conhost.exe),通过设置si.wShowWindow = SW_SHOW能看到此窗口,通过Microsoft Spy++查看该窗口信息
HWND hwCmd;
hwCmd = FindWindow("ConsoleWindowClass","C:\\ATE\\Bin\\PlatForm.exe");//窗口标题在调试的时候和打包运行的时候不一样,所以在下面再关闭了一次
// str.Format("HWND1 ===== %d \r\n",(int)hwCmd);
// OutputText(1,str,RGB(255,0,0));
::SendMessage(hwCmd,WM_CLOSE,(WPARAM)0,(LPARAM)0);//使用TerminateProcess无法关闭
//获取系统版本号
OSVERSIONINFO osi;
ZeroMemory(&osi,sizeof(OSVERSIONINFO));
osi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osi);
//判断系统是否是XP(区分在xp和WIN7)
if (osi.dwMinorVersion >= 1 && osi.dwMajorVersion == 5)
{
hwCmd = FindWindow("ConsoleWindowClass","C:\\Documents and Settings\\All Users\\桌面\\v3.lnk");
}
else
{
hwCmd = FindWindow("ConsoleWindowClass","C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\v3\\v3.lnk");
}
// str.Format("HWND2 ===== %d \r\n",(int)hwCmd);
// OutputText(1,str,RGB(255,0,0));
::SendMessage(hwCmd,WM_CLOSE,(WPARAM)0,(LPARAM)0);
}
break;
}
Sleep(100);
}
//结束线程
GetExitCodeThread(hThreadRead,&dwExitCode);
if (dwExitCode == STILL_ACTIVE)
{
if (!TerminateThread(hThreadRead,0))
{
csErrorInfo.Format("TerminateThread()错误\r\n");
OutputText(1,csErrorInfo,RGB(255,0,0));
return FALSE;
}
CloseHandle(hThreadRead);
}
CloseHandle(hRead);
CloseHandle(hWrite);
if (paramEx != NULL)
{
delete paramEx;
}
return TRUE;
}
//读取cmd打印信息线程
void __cdecl fnReadPipeThread(void *parm)
{
CString csInfo;
char buffer[1024] = {0};
DWORD bytesRead;
CONSOLE *sTransmit = (CONSOLE *)parm;
HANDLE hRead = sTransmit->hRead;
IDllPlatUI* m_pPlatUI =sTransmit->m_pPlatUI ;
// Attempt an asynchronous read operation.
//bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead,
// &gOverlapped) ;
// If there was a problem, or if the asynchronous operation
// is still pending.
while(TRUE)
{
BOOL bResult = ReadFile(hRead,buffer,1023,&bytesRead, NULL);
bool bBreak = false;
if (!bResult)
{
// Deal with the error code.
switch ( GetLastError() )
{
case ERROR_HANDLE_EOF: //如果读取到结尾
{
// WCode to handle the end of the file
// during the call to ReadFile
bBreak = true;
break;
}
default:
break;
}
if( bBreak )
break;
} // end if
csInfo.Format("%s\r\n",buffer);
CString szColor;
szColor.Format("color=%d,%d,%d",GetRValue(1),GetGValue(0),GetBValue(0));
if (NULL == m_pPlatUI)
return ;
m_pPlatUI->OutputSet(1,szColor);
m_pPlatUI->Output(1,csInfo);
}
_endthread();
}