// Run.cpp : implementation file
//
#include "StdAfx.h"
#include <aFXWIN.H>
#include "run.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// Run
Run::Run()
{
m_dwProcessId = DWORD(-1);
m_pReadThread = NULL;
m_pReadThread2 = NULL;
m_hChildStdinRd = NULL;
m_hChildStdinWr = NULL;
m_hChildStdinWrDup = NULL;
m_hChildStdoutRd = NULL;
m_hChildStdoutWr = NULL;
m_hChildStdoutRdDup = NULL;
m_hChildErrorRd = NULL;
m_hChildErrorWr = NULL;
m_hChildErrorRdDup = NULL;
params[0] = params[1] = NULL;
}
Run::~Run()
{
}
/////////////////////////////////////////////////////////////////////////////
// Run message handlers
#define BUFSIZE 1024*32
BOOL Run::CreateShellRedirect()
{
SECURITY_ATTRIBUTES saAttr;
BOOL bSuccess;
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// The steps for redirecting child process's STDOUT:
// 1. Save current STDOUT, to be restored later.
// 2. Create anonymous pipe to be STDOUT for child process.
// 3. Set STDOUT of the parent process to be write handle to
// the pipe, so it is inherited by the child process.
// 4. Create a noninheritable duplicate of the read handle and
// close the inheritable read handle.
// Save the handle to the current STDOUT.
HANDLE hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&m_hChildStdoutRd, &m_hChildStdoutWr, &saAttr, 0))
{
TRACE0(_T("Stdout pipe creation failed\n"));
return FALSE;
}
// Set a write handle to the pipe to be STDOUT.
if (!SetStdHandle(STD_OUTPUT_HANDLE, m_hChildStdoutWr))
{
TRACE0(_T("Redirecting STDOUT failed\n"));
return FALSE;
}
// Create noninheritable read handle and close the inheritable read handle.
bSuccess = DuplicateHandle(GetCurrentProcess(), m_hChildStdoutRd,
GetCurrentProcess(), &m_hChildStdoutRdDup,
0, FALSE,
DUPLICATE_SAME_ACCESS);
if (!bSuccess)
{
TRACE0(_T("DuplicateHandle failed\n"));
return FALSE;
}
CloseHandle(m_hChildStdoutRd);
// The steps for redirecting child process's ERROR:
// 1. Save current ERROR, to be restored later.
// 2. Create anonymous pipe to be ERROR for child process.
// 3. Set ERROR of the parent process to be write handle to
// the pipe, so it is inherited by the child process.
// 4. Create a noninheritable duplicate of the read handle and
// close the inheritable read handle.
// Save the handle to the current ERROR.
HANDLE hSaveError = GetStdHandle(STD_ERROR_HANDLE);
// Create a pipe for the child process's ERROR.
if (!CreatePipe(&m_hChildErrorRd, &m_hChildErrorWr, &saAttr, 0))
{
TRACE0(_T("Error pipe creation failed\n"));
return FALSE;
}
// Set a write handle to the pipe to be ERROR.
if (!SetStdHandle(STD_ERROR_HANDLE, m_hChildErrorWr))
{
TRACE0(_T("Redirecting ERROR failed\n"));
return FALSE;
}
// Create noninheritable read handle and close the inheritable read handle.
bSuccess = DuplicateHandle(GetCurrentProcess(), m_hChildErrorRd,
GetCurrentProcess(), &m_hChildErrorRdDup,
0, FALSE,
DUPLICATE_SAME_ACCESS);
if (!bSuccess)
{
TRACE0(_T("DuplicateHandle failed\n"));
return FALSE;
}
CloseHandle(m_hChildErrorRd);
// The steps for redirecting child process's STDIN:
// 1. Save current STDIN, to be restored later.
// 2. Create anonymous pipe to be STDIN for child process.
// 3. Set STDIN of the parent to be the read handle to the
// pipe, so it is inherited by the child process.
// 4. Create a noninheritable duplicate of the write handle,
// and close the inheritable write handle.
// Save the handle to the current STDIN.
HANDLE hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);
// Create a pipe for the child process's STDIN.
if (!CreatePipe(&m_hChildStdinRd, &m_hChildStdinWr, &saAttr, 0))
{
TRACE0(_T("Stdin pipe creation failed\n"));
return FALSE;
}
// Set a read handle to the pipe to be STDIN.
if (!SetStdHandle(STD_INPUT_HANDLE, m_hChildStdinRd))
{
TRACE0(_T("Redirecting Stdin failed\n"));
return FALSE;
}
// Duplicate the write handle to the pipe so it is not inherited.
bSuccess = DuplicateHandle(GetCurrentProcess(), m_hChildStdinWr,
GetCurrentProcess(), &m_hChildStdinWrDup,
0, FALSE, // not inherited
DUPLICATE_SAME_ACCESS);
if (!bSuccess)
{
TRACE0(_T("DuplicateHandle failed\n"));
return FALSE;
}
CloseHandle(m_hChildStdinWr);
// Now create the child process.
if (!CreateChildProcess())
{
TRACE0(_T("CreateChildProcess failed\n"));
return FALSE;
}
// After process creation, restore the saved STDIN and STDOUT.
if (!SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))
{
TRACE0(_T("Re-redirecting Stdin failed\n"));
return FALSE;
}
if (!SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
{
TRACE0(_T("Re-redirecting Stdout failed\n"));
return FALSE;
}
delete params[0]; delete params[1];
MakeParams();
m_pReadThread = AfxBeginThread((AFX_THREADPROC)ReadPipeThreadProc, (LPVOID)(params[0]));
if (!m_pReadThread)
{
TRACE0(_T("Cannot start read-redirect thread!\n"));
return FALSE;
}
m_pReadThread2 = AfxBeginThread((AFX_THREADPROC)ReadPipeThreadProc, (LPVOID)(params[1]));
if (!m_pReadThread2)
{
TRACE0(_T("Cannot start read2-redirect thread!\n"));
return FALSE;
}
return TRUE;
}
BOOL Run::CreateChildProcess()
{
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
// Set up members of STARTUPINFO structure.
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
siStartInfo.wShowWindow = SW_HIDE;
siStartInfo.hStdInput = m_hChildStdinRd;
siStartInfo.hStdOutput = m_hChildStdoutWr;
siStartInfo.hStdError = m_hChildErrorWr;
TCHAR shellCmd[_MAX_PATH];
if (!GetEnvironmentVariable(_T("ComSpec"), shellCmd, _MAX_PATH))
return FALSE;
#ifdef _UNICODE
_tcscat(shellCmd, _T(" /U"));
#else
_tcscat(shellCmd, _T(" /A"));
#endif
// Create the child process.
BOOL bRet = CreateProcess(NULL,
shellCmd, // applicatin name
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
CREATE_NEW_CONSOLE, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
if (bRet)
m_dwProcessId = piProcInfo.dwProcessId;
return bRet;
}
void Run::WriteToPipe(LPCTSTR line, bool files)
{
if(files)
{
params[0]->open("log.txt");
params[1]->open("errlog.txt");
}
DWORD dwWritten;
if(!WriteFile(m_hChildStdinWrDup, line, _tcslen(line)*sizeof(TCHAR),
&dwWritten, NULL))
AfxMessageBox("Error");
}
UINT Run::ReadPipeThreadProc(LPVOID pParam)
{
DWORD dwRead;
TCHAR chBuf[BUFSIZE];
RunParams* params = (RunParams*)pParam;
TRACE0(_T("ReadPipe Thread begin run\n"));
memset(chBuf,'1',BUFSIZE);
for(;;)
{
if (!ReadFile(params->handle, chBuf, BUFSIZE, &dwRead, NULL) || dwRead == 0)
{
AfxMessageBox("Error");
break;
}
chBuf[dwRead/sizeof(TCHAR)] = _T('\0');
params->addText(chBuf);
}
return 1;
}
void Run::OnDestroy()
{
if (m_dwProcessId != DWORD(-1))
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwProcessId);
if (hProcess)
{
TerminateProcess(hProcess, 0);
WriteToPipe(_T("exit\r\n"),false);
//WaitForSingleObject(hProcess, INFINITE);
WaitForSingleObject(hProcess, 2000);
CloseHandle(hProcess);
}
}
if (m_pReadThread)
{
TerminateThread(m_pReadThread->m_hThread, 0);
delete m_pReadThread;
m_pReadThread = NULL;
}
if (m_pReadThread2)
{
TerminateThread(m_pReadThread2->m_hThread, 0);
delete m_pReadThread2;
m_pReadThread2 = NULL;
}
CloseHandle(m_hChildStdinRd);
CloseHandle(m_hChildStdoutWr);
CloseHandle(m_hChildErrorWr);
CloseHandle(m_hChildStdinWrDup);
CloseHandle(m_hChildStdoutRdDup);
CloseHandle(m_hChildErrorRdDup);
m_dwProcessId = DWORD(-1);
delete params[0]; delete params[1];
}