📄 conredirect.cpp
字号:
/**************************************************************************
Project: WinAVRIDE Class: Console with Redirected stdin,stdout,stderr
Copyright (C) 2005 Philipp Schober
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
History
19.Feb 2005 - First Release (V1.0)
****************************************************************************/
#include <vcl\vcl.h>
#pragma hdrstop
#include "ConRedirect.h"
//#include "Unit1.h"
//---------------------------------------------------------------------------
static inline TConRedirect *ValidCtrCheck()
{
return new TConRedirect(NULL);
}
//---------------------------------------------------------------------------
__fastcall TConRedirect::TConRedirect(TComponent* Owner)
: TComponent(Owner)
{
OSVERSIONINFO osv;
osv.dwOSVersionInfoSize = sizeof(osv);
GetVersionEx(&osv);
if (osv.dwPlatformId == VER_PLATFORM_WIN32_NT) isWinNT = true;
else isWinNT = false;
StdIn = NULL;
StdOut = NULL;
StdErr = NULL;
StdInWrite = NULL;
StdOutRead = NULL;
StdErrRead = NULL;
StdOutThread = NULL;
StdErrThread = NULL;
MonThread = NULL;
childrunning = false;
}
//---------------------------------------------------------------------------
__fastcall TConRedirect::~TConRedirect()
{
DWORD exitcode;
GetExitCodeProcess (ChildProcess, &exitcode);
if (exitcode == STILL_ACTIVE) // Check for open Process
{
TerminateProcess (ChildProcess, 0);
WaitForSingleObject(ChildProcess, 2000); // Wait max. 2sec for Termination
}
Terminate ();
}
//---------------------------------------------------------------------------
namespace Conredirect
{
void __fastcall Register()
{
TComponentClass classes[1] = {__classid(TConRedirect)};
RegisterComponents("Beispiele", classes, 0);
}
}
//---------------------------------------------------------------------------
void __fastcall TConRedirect::ClosePipeHandles (void)
{
if (StdIn != NULL) CloseHandle (StdIn);
StdIn = NULL;
if (StdOut != NULL) CloseHandle (StdOut);
StdOut = NULL;
if (StdErr != NULL) CloseHandle (StdErr);
StdErr = NULL;
if (StdInWrite != NULL) CloseHandle (StdInWrite);
StdInWrite = NULL;
if (StdOutRead != NULL) CloseHandle (StdOutRead);
StdOutRead = NULL;
if (StdErrRead != NULL) CloseHandle (StdErrRead);
StdErrRead = NULL;
}
//---------------------------------------------------------------------------
bool __fastcall TConRedirect::RunChild (char *appname, char *params, char *workpath)
{
HANDLE Process;
SECURITY_ATTRIBUTES sa;
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
sa.nLength= sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
// Create the child stdin pipe.
if (!CreatePipe(&StdIn, &StdInWriteTmp, &sa, 0))
{
ClosePipeHandles ();
return false;
}
// Create the child stdout pipe.
if (!CreatePipe(&StdOutReadTmp, &StdOut, &sa, 0))
{
ClosePipeHandles ();
return false;
}
// Create the child stderr pipe.
if (!CreatePipe(&StdErrReadTmp, &StdErr, &sa, 0))
{
ClosePipeHandles ();
return false;
}
Process = GetCurrentProcess();
// Duplicate Handles to non-inheritable Handles
if (!DuplicateHandle(Process, StdInWriteTmp, Process, &StdInWrite, 0,
FALSE, DUPLICATE_SAME_ACCESS))
{
ClosePipeHandles ();
return false;
}
if (!DuplicateHandle(Process, StdOutReadTmp, Process, &StdOutRead, 0,
FALSE, DUPLICATE_SAME_ACCESS))
{
ClosePipeHandles ();
return false;
}
if (!DuplicateHandle(Process, StdErrReadTmp, Process, &StdErrRead, 0,
FALSE, DUPLICATE_SAME_ACCESS))
{
ClosePipeHandles ();
return false;
}
// Close inheritable Handles
CloseHandle(StdInWriteTmp);
CloseHandle(StdOutReadTmp);
CloseHandle(StdErrReadTmp);
// Set up the start up info struct.
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
si.hStdOutput = StdOut;
si.hStdInput = StdIn;
si.hStdError = StdErr;
si.wShowWindow = SW_HIDE;
// Create the NULL security token for the process
LPVOID lpSD = NULL;
LPSECURITY_ATTRIBUTES lpSA = NULL;
// On NT/2000/XP the handle must have PROCESS_QUERY_INFORMATION access.
if (isWinNT)
{
lpSD = GlobalAlloc(GPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor(lpSD, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(lpSD, -1, 0, 0);
lpSA = (LPSECURITY_ATTRIBUTES)GlobalAlloc(GPTR, sizeof(SECURITY_ATTRIBUTES));
lpSA->nLength = sizeof(SECURITY_ATTRIBUTES);
lpSA->lpSecurityDescriptor = lpSD;
lpSA->bInheritHandle = TRUE;
}
// Spawn Child Process.
temp = CreateProcess(appname, params, lpSA, NULL, TRUE, CREATE_NEW_CONSOLE,
NULL, workpath, &si, &pi);
// Free allocated Memory
if (lpSA != NULL) GlobalFree(lpSA);
if (lpSD != NULL) GlobalFree(lpSD);
// Check if Child Process Creation was successful
if (!temp || pi.hProcess == NULL)
{
ClosePipeHandles ();
return false;
}
CloseHandle(pi.hThread);
StdOutThread = new TStdOutThread (true); // Create StdOut Thread
StdOutThread->StdOutRead = StdOutRead;
StdOutThread->OnStdOut = StdOutFunc;
StdErrThread = new TStdErrThread (true); // Create StdErr Thread
StdErrThread->StdErrRead = StdErrRead;
StdErrThread->OnStdErr = StdErrFunc;
MonThread = new TMonThread (true); // Create Monitoring Thread
MonThread->ChildProcess = pi.hProcess;
MonThread->OnChildExit = ChildExitFunc;
StdOutThread->Resume ();
StdErrThread->Resume ();
MonThread->Resume ();
childrunning = true;
ChildProcess = pi.hProcess;
return true;
}
//---------------------------------------------------------------------------
void __fastcall TConRedirect::Terminate (void)
{
childrunning = false;
ClosePipeHandles ();
Sleep(100);
if (StdOutThread != NULL) StdOutThread->Terminate ();
StdOutThread = NULL;
if (StdErrThread != NULL) StdErrThread->Terminate ();
StdErrThread = NULL;
if (MonThread != NULL) MonThread->Terminate ();
MonThread = NULL;
}
//---------------------------------------------------------------------------
void __fastcall TConRedirect::SendChar (char ch)
{
DWORD bread;
char buf[10];
buf[0] = ch;
buf[1] = 0;
WriteFile(StdInWrite,buf,1,&bread,NULL); //send it to stdin
if (ch == '\r')
{
buf[0] = '\n';
WriteFile(StdInWrite,buf,1,&bread,NULL);
}
}
//---------------------------------------------------------------------------
void __fastcall TConRedirect::SendString (AnsiString str)
{
DWORD bread;
WriteFile(StdInWrite,str.c_str (),str.Length (),&bread,NULL); //send it to stdin
}
//---------------------------------------------------------------------------
void __fastcall TConRedirect::StdOutFunc (char *buffer, int len)
{
if (FOnStdOut) FOnStdOut (buffer, len);
}
//---------------------------------------------------------------------------
void __fastcall TConRedirect::StdErrFunc (char *buffer, int len)
{
if (FOnStdErr) FOnStdErr (buffer, len);
}
//---------------------------------------------------------------------------
void __fastcall TConRedirect::ChildExitFunc (int exitcode)
{
Terminate ();
if (FOnChildExit) FOnChildExit (exitcode);
}
//---------------------------------------------------------------------------
bool __fastcall TConRedirect::isChildRunning (void)
{
return (childrunning);
}
//---------------------------------------------------------------------------
//------- StdOut Read Thread
//---------------------------------------------------------------------------
__fastcall TStdOutThread::TStdOutThread(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
//---------------------------------------------------------------------------
void __fastcall TStdOutThread::Execute()
{
AnsiString tmp;
DWORD e;
while (!Terminated)
{
if (!ReadFile(StdOutRead, buffer, BUFFER_SIZE, &length, NULL) || !length)
{
if ((e = GetLastError()) == ERROR_BROKEN_PIPE) break; // pipe done - normal exit path.
else
{
tmp.printf ("Error in StdOut Thread\nErrorcode : %lu", e);
ShowMessage (tmp); // Something bad happened.
break;
}
}
if (length)
{
buffer[length] = '\0';
Synchronize (StdOutWrap);
}
}
}
//---------------------------------------------------------------------------
void __fastcall TStdOutThread::StdOutWrap (void)
{
if (FOnStdOut) FOnStdOut (buffer, length);
}
//---------------------------------------------------------------------------
//------- StdErr Read Thread
//---------------------------------------------------------------------------
__fastcall TStdErrThread::TStdErrThread(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
//---------------------------------------------------------------------------
void __fastcall TStdErrThread::Execute()
{
while (!Terminated)
{
if (!ReadFile(StdErrRead, buffer, BUFFER_SIZE, &length, NULL) || !length)
{
if (GetLastError() == ERROR_BROKEN_PIPE) break; // pipe done - normal exit path.
else
{
ShowMessage ("Error int StdErr Thread"); // Something bad happened.
break;
}
}
if (length)
{
buffer[length] = '\0';
Synchronize (StdErrWrap);
}
}
}
//---------------------------------------------------------------------------
void __fastcall TStdErrThread::StdErrWrap (void)
{
if (FOnStdErr) FOnStdErr (buffer, length);
}
//---------------------------------------------------------------------------
//------- Child Process Monitoring Thread
//---------------------------------------------------------------------------
__fastcall TMonThread::TMonThread(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
//---------------------------------------------------------------------------
void __fastcall TMonThread::Execute()
{
while (!Terminated)
{
WaitForSingleObject(ChildProcess,INFINITE); // Wait until Child Process exits
Terminate (); // Terminate this Thread
}
Sleep (200);
GetExitCodeProcess (ChildProcess, &exitcode);
Synchronize (ChildExitWrap);
}
//---------------------------------------------------------------------------
void __fastcall TMonThread::ChildExitWrap (void)
{
if (FOnChildExit) FOnChildExit (exitcode);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -