📄 subprocess.cpp
字号:
//####COPYRIGHTBEGIN####// // ----------------------------------------------------------------------------// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.//// This program is part of the eCos host tools.//// This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 of the License, or (at your option) // any later version.// // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details.// // You should have received a copy of the GNU General Public License along with// this program; if not, write to the Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.//// ----------------------------------------------------------------------------// //####COPYRIGHTEND####//===========================================================================//===========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): sdf// Contact(s): sdf// Date: 1998/08/11// Version: 0.01// Purpose: // Description: This is the implementation of the class which allows for spawning subprocesses//// Requires: // Provides: // See also: // Known bugs: // Usage: ////####DESCRIPTIONEND####////===========================================================================#include "subprocess.h"const UINT CSubprocess::PROCESS_KILL_EXIT_CODE=0xCCFFCCFF;CSubprocess::CSubprocess(bool bVerbose): m_dwParentThreadId(0), m_pstrOutput(0), m_idProcess(0), m_bThreadRunning(false), m_bVerbose(bVerbose), m_dwExitCode(0xffffffff), m_bAutoDelete(false), m_hThread(0), m_pfnLogfunc(0), m_pLogparam(0), m_hwndParent(0){}// Run (non-blocking and discarding output)/* static */ unsigned int CSubprocess::Run(LPCTSTR pszCmd,LPCTSTR pszDir){ CSubprocess *psp=new CSubprocess(false); psp->m_bAutoDelete=true; String strOutput; return psp->Run(strOutput,pszCmd,pszDir);}unsigned int CSubprocess::Run(LogFunc *pfnLog,void * pLogparam, LPCTSTR pszCmd,LPCTSTR pszDir){ unsigned int rc; if(m_bThreadRunning){ rc=0; } else { m_pfnLogfunc=pfnLog; m_pLogparam=pLogparam; m_strCmd=pszCmd; m_strDir=pszDir; rc=CreateProcess(); if(rc){ ThreadFunc(); } } return rc;}#ifdef _WIN32// Non-blocking: WM_SUBPROCESS messages are posted to HWND supplied as argumentunsigned int CSubprocess::Run(HWND hwndParent,LPCTSTR pszCmd,LPCTSTR pszDir){ unsigned int rc; if(m_bThreadRunning){ rc=0; } else { m_hwndParent=hwndParent; m_strCmd=pszCmd; m_strDir=pszDir; rc=CreateProcess(); if(rc){ DWORD dwID; m_bThreadRunning=true; m_hThread=::CreateThread(NULL,0,ThreadFunc,this,0,&dwID); } } return rc;}// Non-blocking: WM_SUBPROCESS messages are posted to thread supplied as argumentunsigned int CSubprocess::Run(DWORD dwParentThreadId,LPCTSTR pszCmd,LPCTSTR pszDir){ unsigned int rc; if(m_bThreadRunning){ rc=0; } else { m_dwParentThreadId=dwParentThreadId; m_strCmd=pszCmd; m_strDir=pszDir; rc=CreateProcess(); if(rc){ DWORD dwID; m_bThreadRunning=true; m_hThread=::CreateThread(NULL,0,ThreadFunc,this,0,&dwID); } } return rc;}#endif// Blocking: output is placed in string supplied as argumentunsigned int CSubprocess::Run(String &strOutput,LPCTSTR pszCmd,LPCTSTR pszDir){ strOutput=_T(""); m_strCmd=pszCmd; m_strDir=pszDir; m_pstrOutput=&strOutput; unsigned int rc=CreateProcess(); if(rc){ ThreadFunc(); } return rc;}CSubprocess::~CSubprocess(){ Kill(); if(m_hThread){ // running non-blocking and thread started (but possibly already finished) if(WAIT_TIMEOUT==WaitForSingleObject(m_hThread,1000)){ // In general this is bad news, but we can't allow the thread to live on if // the class object is about to be deleted. if(m_bVerbose){ Output(_T("*** CSubprocess: Forcibly terminating thread\n")); } ::TerminateThread(m_hThread,0); } ::CloseHandle(m_hThread); }}#ifdef _WIN32unsigned int CSubprocess::CreateProcess(){ STARTUPINFO si; // For CreateProcess call HANDLE hrPipe,hwPipe,hwPipe2; // Create the anonymous pipe SECURITY_ATTRIBUTES saPipe; // Security for anonymous pipe saPipe.nLength = sizeof(SECURITY_ATTRIBUTES); saPipe.lpSecurityDescriptor = NULL; saPipe.bInheritHandle = true; ::CreatePipe(&m_hrPipe,&hwPipe,&saPipe,80); // In most cases you can get away with using the same anonymous // pipe write handle for both the child's standard output and // standard error, but this may cause problems if the child app // explicitly closes one of its standard output or error handles. If // that happens, the anonymous pipe will close, since the child's // standard output and error handles are really the same handle. The // child won't be able to write to the other write handle since the // pipe is now gone, and parent reads from the pipe will return // ERROR_BROKEN_PIPE and child output will be lost. To solve this // problem, simply duplicate the write end of the pipe to create // another distinct, separate handle to the write end of the pipe. // One pipe write handle will serve as standard out, the other as // standard error. Now *both* write handles must be closed before the // write end of the pipe actually closes. ::DuplicateHandle(::GetCurrentProcess(), // Source process hwPipe, // Handle to duplicate ::GetCurrentProcess(), // Destination process &hwPipe2, // New handle, used as stderr by child 0, // New access flags - ignored since DUPLICATE_SAME_ACCESS true, // It's inheritable DUPLICATE_SAME_ACCESS); ::CreatePipe(&hrPipe,&m_hwPipe,&saPipe,80); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.hStdOutput = hwPipe; si.hStdError = hwPipe2; si.hStdInput = hrPipe; si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOW; LPCTSTR pszDir=0; if(m_strDir.GetLength()){ pszDir=m_strDir; // NULL = start in current } PROCESS_INFORMATION pi; unsigned int rc=(::CreateProcess(NULL, // Application name m_strCmd.GetBuffer(m_strCmd.GetLength()), // Full command line for child NULL, // Process security descriptor NULL, // Thread security descriptor true, // Inherit handles? Also use if STARTF_USESTDHANDLES // Creation flags of // CREATE_NEW_PROCESS_GROUP so we can use // GenerateConsoleCtrlEvent to // terminate the child DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP, NULL, // Inherited environment address pszDir,&si,&pi) ? pi.dwProcessId : 0); m_strCmd.ReleaseBuffer(); String strMsg; if(rc){ m_idProcess=pi.dwProcessId; m_hProcess=pi.hProcess; strMsg.Format(_T("*** Process %d created \"%s\"\n"),m_idProcess,(LPCTSTR)m_strCmd); m_dwExitCode=STILL_ACTIVE; } else { strMsg.Format(_T("*** Failed to create process \"%s\"\n"),(LPCTSTR)m_strCmd); m_dwExitCode=GetLastError(); } if(m_bVerbose){ Output(strMsg); } ::CloseHandle(hrPipe); ::CloseHandle(hwPipe); ::CloseHandle(hwPipe2); ::CloseHandle(pi.hThread); return rc; }#else // UNIXunsigned int CSubprocess::CreateProcess(){ int pipe_ends_w[2]; if (pipe(pipe_ends_w) < 0 ) { Log(_T("Failed to create pipe_ends_w - %s\n"),strerror(errno)); } else { int pipe_ends_r[2]; if (pipe(pipe_ends_r) < 0 ) { Log(_T("Failed to create pipe_ends_r - %s\n"),strerror(errno)); } else { int pid=fork(); switch (pid) { // Fork failed case -1:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -