#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <tchar.h>
/*
Quick note:
*/
#define SLEEP_TIME 50 // reactivity: sleep time to wait for subprocess to output some more data
CONST COORD origin = { 0, 0 };
// we should have been spawned using SW_HIDE, so our console window is not visible
int main(int argc, char* argv[])
{
// get pipe/console to output to
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwDummy;
// parse command line : skip to RTconsole's arguments
LPTSTR commandLine = GetCommandLine();
if (*commandLine == '"')
commandLine = _tcschr(commandLine+1, _T('"'));
else
commandLine = _tcspbrk(commandLine, _T(" \t"));
if (!commandLine) return -1;
commandLine += _tcsspn(commandLine+1, _T(" \t"))+1;
if (commandLine[0] == '\0') return -1;
// prepare the console window & inherited screen buffer
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,&sa,CONSOLE_TEXTMODE_BUFFER,NULL);
FillConsoleOutputCharacter(hConsole, '\0', MAXLONG, origin, &dwDummy); // fill screen buffer with zeroes
SetStdHandle(STD_OUTPUT_HANDLE, hConsole); // to be inherited by child process
// start the subprocess
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_FORCEOFFFEEDBACK; // we don't want the "app starting" cursor
// all other default options are already good : we want subprocess to share the same console and to inherit our STD handles
if (!CreateProcess( NULL, commandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
CloseHandle(hConsole);
return -2;
}
CloseHandle(pi.hThread); // always close the hThread after a CreateProcess
COORD lastpos = { 0, 0 };
CONSOLE_SCREEN_BUFFER_INFO csbi;
bool exitNow = false;
do
{
if (WaitForSingleObject(pi.hProcess, 0) != WAIT_TIMEOUT)
exitNow = true; // exit after this last iteration
// get screen buffer state
GetConsoleScreenBufferInfo(hConsole, &csbi);
int lineWidth = csbi.dwSize.X;
if ((csbi.dwCursorPosition.X == lastpos.X) && (csbi.dwCursorPosition.Y == lastpos.Y))
Sleep(SLEEP_TIME); // text cursor did not move, sleep a while
else
{
DWORD count = (csbi.dwCursorPosition.Y-lastpos.Y)*lineWidth+csbi.dwCursorPosition.X-lastpos.X;
// read newly output characters starting from last cursor position
LPTSTR buffer = (LPTSTR) LocalAlloc(0, count*sizeof(TCHAR));
ReadConsoleOutputCharacter(hConsole, buffer, count, lastpos, &count);
// fill screen buffer with zeroes
FillConsoleOutputCharacter(hConsole, '\0', count, lastpos, &dwDummy);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
lastpos = csbi.dwCursorPosition;
GetConsoleScreenBufferInfo(hConsole, &csbi);
if ((csbi.dwCursorPosition.X == lastpos.X) && (csbi.dwCursorPosition.Y == lastpos.Y))
{ // text cursor did not move since this treatment, hurry to reset it to home
SetConsoleCursorPosition(hConsole, origin);
lastpos = origin;
}
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
// scan screen buffer and transmit character to real output handle
LPTSTR scan = buffer;
do
{
if (*scan)
{
DWORD len = 1;
while (scan[len] && (len < count))
len++;
WriteFile(hOutput, scan, len, &dwDummy, NULL);
scan += len;
count -= len;
}
else
{
DWORD len = 1;
while (!scan[len] && (len < count))
len++;
scan += len;
count -= len;
len = (len+lineWidth-1)/lineWidth;
for (;len;len--)
WriteFile(hOutput, "\r\n", 2, &dwDummy, NULL);
}
} while (count);
//FlushFileBuffers(hOutput); // seems unnecessary
LocalFree(buffer);
}
// loop until end of subprocess
} while (!exitNow);
CloseHandle(hConsole);
// release subprocess handle
DWORD exitCode;
if (!GetExitCodeProcess(pi.hProcess, &exitCode))
exitCode = -3;
CloseHandle(pi.hProcess);
return exitCode;
}