| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972 | 
							- //---------------------------------------------------------------------------
 
- #include <stdexcept>
 
- #include <stdio.h>
 
- #include <stdlib.h>
 
- #include <windows.h>
 
- #include "Console.h"
 
- #define MAX_ATTEMPTS 10
 
- //---------------------------------------------------------------------------
 
- #define LENOF(x) ( (sizeof((x))) / (sizeof(*(x))))
 
- //---------------------------------------------------------------------------
 
- using namespace std;
 
- HANDLE ConsoleInput = NULL;
 
- HANDLE ConsoleOutput = NULL;
 
- HANDLE Child = NULL;
 
- HANDLE CancelEvent = NULL;
 
- HANDLE InputTimerEvent = NULL;
 
- unsigned int OutputType = FILE_TYPE_UNKNOWN;
 
- unsigned int InputType = FILE_TYPE_UNKNOWN;
 
- enum { RESULT_GLOBAL_ERROR = 1, RESULT_INIT_ERROR = 2, RESULT_PROCESSING_ERROR = 3,
 
-   RESULT_UNKNOWN_ERROR = 4 };
 
- const wchar_t* CONSOLE_CHILD_PARAM = L"consolechild";
 
- //---------------------------------------------------------------------------
 
- inline TConsoleCommStruct* GetCommStruct(HANDLE FileMapping)
 
- {
 
-   TConsoleCommStruct* Result;
 
-   Result = static_cast<TConsoleCommStruct*>(MapViewOfFile(FileMapping,
 
-     FILE_MAP_ALL_ACCESS, 0, 0, 0));
 
-   if (Result == NULL)
 
-   {
 
-     throw runtime_error("Cannot open mapping object.");
 
-   }
 
-   return Result;
 
- }
 
- //---------------------------------------------------------------------------
 
- inline void FreeCommStruct(TConsoleCommStruct* CommStruct)
 
- {
 
-   UnmapViewOfFile(CommStruct);
 
- }
 
- //---------------------------------------------------------------------------
 
- void InitializeConsole(wchar_t* InstanceName, HANDLE& RequestEvent, HANDLE& ResponseEvent,
 
-   HANDLE& CancelEvent, HANDLE& FileMapping, HANDLE& Job)
 
- {
 
-   unsigned int Process = GetCurrentProcessId();
 
-   int Attempts = 0;
 
-   wchar_t Name[MAX_PATH];
 
-   bool UniqEvent;
 
-   do
 
-   {
 
-     if (Attempts > MAX_ATTEMPTS)
 
-     {
 
-       throw runtime_error("Cannot find unique name for event object.");
 
-     }
 
-     int InstanceNumber;
 
-     #ifdef CONSOLE_TEST
 
-     InstanceNumber = 1;
 
-     #else
 
-     InstanceNumber = random(1000);
 
-     #endif
 
-     swprintf(InstanceName, L"_%u_%d", Process, InstanceNumber);
 
-     swprintf(Name, L"%s%s", CONSOLE_EVENT_REQUEST, InstanceName);
 
-     HANDLE EventHandle = OpenEvent(EVENT_ALL_ACCESS, false, Name);
 
-     UniqEvent = (EventHandle == NULL);
 
-     if (!UniqEvent)
 
-     {
 
-       CloseHandle(EventHandle);
 
-     }
 
-     Attempts++;
 
-   }
 
-   while (!UniqEvent);
 
-   RequestEvent = CreateEvent(NULL, false, false, Name);
 
-   if (RequestEvent == NULL)
 
-   {
 
-     throw runtime_error("Cannot create request event object.");
 
-   }
 
-   swprintf(Name, L"%s%s", CONSOLE_EVENT_RESPONSE, InstanceName);
 
-   ResponseEvent = CreateEvent(NULL, false, false, Name);
 
-   if (ResponseEvent == NULL)
 
-   {
 
-     throw runtime_error("Cannot create response event object.");
 
-   }
 
-   swprintf(Name, L"%s%s", CONSOLE_EVENT_CANCEL, InstanceName);
 
-   CancelEvent = CreateEvent(NULL, false, false, Name);
 
-   if (CancelEvent == NULL)
 
-   {
 
-     throw runtime_error("Cannot create cancel event object.");
 
-   }
 
-   swprintf(Name, L"%s%s", CONSOLE_MAPPING, InstanceName);
 
-   FileMapping = CreateFileMapping((HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE,
 
-     0, sizeof(TConsoleCommStruct), Name);
 
-   if (FileMapping == NULL)
 
-   {
 
-     throw runtime_error("Cannot create mapping object.");
 
-   }
 
-   swprintf(Name, L"%s%s", CONSOLE_JOB, InstanceName);
 
-   Job = CreateJobObject(NULL, Name);
 
-   if (Job == NULL)
 
-   {
 
-     throw runtime_error("Cannot create job object.");
 
-   }
 
-   JOBOBJECT_EXTENDED_LIMIT_INFORMATION ExtendedLimitInformation;
 
-   memset(&ExtendedLimitInformation, 0, sizeof(ExtendedLimitInformation));
 
-   ExtendedLimitInformation.BasicLimitInformation.LimitFlags =
 
-     JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
 
-   if (SetInformationJobObject(Job, JobObjectExtendedLimitInformation,
 
-         &ExtendedLimitInformation, sizeof(ExtendedLimitInformation)) == 0)
 
-   {
 
-     CloseHandle(Job);
 
-     Job = NULL;
 
-   }
 
-   TConsoleCommStruct* CommStruct = GetCommStruct(FileMapping);
 
-   CommStruct->Size = sizeof(TConsoleCommStruct);
 
-   CommStruct->Version = TConsoleCommStruct::CurrentVersion;
 
-   CommStruct->Event = TConsoleCommStruct::NONE;
 
-   FreeCommStruct(CommStruct);
 
- }
 
- //---------------------------------------------------------------------------
 
- // duplicated in Common.cpp
 
- bool __fastcall CutToken(const wchar_t*& Str, wchar_t* Token)
 
- {
 
-   bool Result;
 
-   // inspired by Putty's sftp_getcmd() from PSFTP.C
 
-   int Length = wcslen(Str);
 
-   int Index = 0;
 
-   while ((Index < Length) &&
 
-     ((Str[Index] == L' ') || (Str[Index] == L'\t')))
 
-   {
 
-     Index++;
 
-   }
 
-   if (Index < Length)
 
-   {
 
-     bool Quoting = false;
 
-     while (Index < Length)
 
-     {
 
-       if (!Quoting && ((Str[Index] == L' ') || (Str[Index] == L'\t')))
 
-       {
 
-         break;
 
-       }
 
-       else if ((Str[Index] == L'"') && (Index + 1 < Length) &&
 
-         (Str[Index + 1] == L'"'))
 
-       {
 
-         Index += 2;
 
-         *Token = L'"';
 
-         Token++;
 
-       }
 
-       else if (Str[Index] == L'"')
 
-       {
 
-         Index++;
 
-         Quoting = !Quoting;
 
-       }
 
-       else
 
-       {
 
-         *Token = Str[Index];
 
-         Token++;
 
-         Index++;
 
-       }
 
-     }
 
-     if (Index < Length)
 
-     {
 
-       Index++;
 
-     }
 
-     Str += Index;
 
-     Result = true;
 
-   }
 
-   else
 
-   {
 
-     Result = false;
 
-     Str += Length;
 
-   }
 
-   *Token = L'\0';
 
-   return Result;
 
- }
 
- //---------------------------------------------------------------------------
 
- char* WideStringToString(const wchar_t* Message)
 
- {
 
-   char* Buffer;
 
-   int Size = WideCharToMultiByte(CP_UTF8, 0, Message, -1, 0, 0, 0, 0);
 
-   if (Size > 0)
 
-   {
 
-     Buffer = new char[(Size * 2) + 1];
 
-     if (WideCharToMultiByte(CP_UTF8, 0, Message, -1, Buffer, Size, 0, 0) > 0)
 
-     {
 
-       Buffer[Size] = '\0';
 
-     }
 
-     else
 
-     {
 
-       delete[] Buffer;
 
-       Buffer = NULL;
 
-     }
 
-   }
 
-   return Buffer;
 
- }
 
- //---------------------------------------------------------------------------
 
- void GetProductVersion(wchar_t* ProductVersion)
 
- {
 
-   wchar_t Buffer[MAX_PATH];
 
-   DWORD ModuleNameLen = GetModuleFileName(NULL, Buffer, MAX_PATH);
 
-   if ((ModuleNameLen == 0) || (ModuleNameLen == MAX_PATH))
 
-   {
 
-     throw runtime_error("Error retrieving executable name.");
 
-   }
 
-   ProductVersion[0] = '\0';
 
-   unsigned long Handle;
 
-   unsigned int Size = GetFileVersionInfoSize(Buffer, &Handle);
 
-   if (Size > 0)
 
-   {
 
-     void * VersionInfo = new char[Size];
 
-     VS_FIXEDFILEINFO* FixedFileInfo;
 
-     unsigned int Length;
 
-     if (GetFileVersionInfo(Buffer, Handle, Size, VersionInfo))
 
-     {
 
-       if (VerQueryValue(VersionInfo, L"\\", (void**)&FixedFileInfo, &Length))
 
-       {
 
-         int ProductMajor = HIWORD(FixedFileInfo->dwProductVersionMS);
 
-         int ProductMinor = LOWORD(FixedFileInfo->dwProductVersionMS);
 
-         int ProductBuild = HIWORD(FixedFileInfo->dwProductVersionLS);
 
-         if ((ProductMajor >= 1) && (ProductMajor <= 99) &&
 
-             (ProductMinor >= 0) && (ProductMinor <= 99) &&
 
-             (ProductBuild >= 0) && (ProductBuild <= 99))
 
-         {
 
-           wsprintf(ProductVersion, L"%d.%d.%d", ProductMajor, ProductMinor, ProductBuild);
 
-         }
 
-       }
 
-     }
 
-     delete[] VersionInfo;
 
-   }
 
-   if (ProductVersion[0] == L'\0')
 
-   {
 
-     throw runtime_error("Error retrieving product version.");
 
-   }
 
- }
 
- //---------------------------------------------------------------------------
 
- void InitializeChild(const wchar_t* CommandLine, const wchar_t* InstanceName, HANDLE& Child)
 
- {
 
-   int SkipParam = 0;
 
-   wchar_t ChildPath[MAX_PATH] = L"";
 
-   size_t CommandLineLen = wcslen(CommandLine);
 
-   wchar_t* Buffer = new wchar_t[(CommandLineLen > MAX_PATH ? CommandLineLen : MAX_PATH) + 1];
 
-   int Count = 0;
 
-   const wchar_t* P = CommandLine;
 
-   while (CutToken(P, Buffer))
 
-   {
 
-     if ((wcschr(L"-/", Buffer[0]) != NULL) &&
 
-         (wcsncmpi(Buffer + 1, CONSOLE_CHILD_PARAM, wcslen(CONSOLE_CHILD_PARAM)) == 0) &&
 
-         (Buffer[wcslen(CONSOLE_CHILD_PARAM) + 1] == L'='))
 
-     {
 
-       SkipParam = Count;
 
-       wcscpy(ChildPath, Buffer + 1 + wcslen(CONSOLE_CHILD_PARAM) + 1);
 
-     }
 
-     ++Count;
 
-   }
 
-   if (wcslen(ChildPath) == 0)
 
-   {
 
-     DWORD ModuleNameLen = GetModuleFileName(NULL, Buffer, MAX_PATH);
 
-     if ((ModuleNameLen == 0) || (ModuleNameLen == MAX_PATH))
 
-     {
 
-       throw runtime_error("Error retrieving executable name.");
 
-     }
 
-     const wchar_t* LastDelimiter = wcsrchr(Buffer, L'\\');
 
-     const wchar_t* AppFileName;
 
-     if (LastDelimiter != NULL)
 
-     {
 
-       wcsncpy(ChildPath, Buffer, LastDelimiter - Buffer + 1);
 
-       ChildPath[LastDelimiter - Buffer + 1] = L'\0';
 
-       AppFileName = LastDelimiter + 1;
 
-     }
 
-     else
 
-     {
 
-       ChildPath[0] = L'\0';
 
-       AppFileName = Buffer;
 
-     }
 
-     const wchar_t* ExtensionStart = wcsrchr(AppFileName, L'.');
 
-     if (ExtensionStart != NULL)
 
-     {
 
-       wchar_t* End = ChildPath + wcslen(ChildPath);
 
-       wcsncpy(End, AppFileName, ExtensionStart - AppFileName);
 
-       *(End + (ExtensionStart - AppFileName)) = L'\0';
 
-     }
 
-     else
 
-     {
 
-       wcscat(ChildPath, AppFileName);
 
-     }
 
-     wcscat(ChildPath, L".exe");
 
-   }
 
-   wchar_t ProductVersion[32];
 
-   GetProductVersion(ProductVersion);
 
-   wchar_t* Parameters = new wchar_t[(CommandLineLen * 2) + 100 + (Count * 3) + 1];
 
-   wsprintf(Parameters, L"\"%s\" /console=%s /consoleinstance=%s ", ChildPath, ProductVersion, InstanceName);
 
-   P = CommandLine;
 
-   // skip executable path
 
-   CutToken(P, Buffer);
 
-   int i = 1;
 
-   while (CutToken(P, Buffer))
 
-   {
 
-     if (i != SkipParam)
 
-     {
 
-       wcscat(Parameters, L"\"");
 
-       wchar_t* P2 = Parameters + wcslen(Parameters);
 
-       const wchar_t* P3 = Buffer;
 
-       const wchar_t* BufferEnd = Buffer + wcslen(Buffer) + 1;
 
-       while (P3 != BufferEnd)
 
-       {
 
-         *P2 = *P3;
 
-         ++P2;
 
-         if (*P3 == L'"')
 
-         {
 
-           *P2 = L'"';
 
-           ++P2;
 
-         }
 
-         ++P3;
 
-       }
 
-       wcscat(Parameters, L"\" ");
 
-     }
 
-     ++i;
 
-   }
 
-   delete[] Buffer;
 
-   STARTUPINFO StartupInfo = { sizeof(STARTUPINFO) };
 
-   PROCESS_INFORMATION ProcessInfomation;
 
-   BOOL Result =
 
-     CreateProcess(ChildPath, Parameters, NULL, NULL, false, 0, NULL, NULL,
 
-       &StartupInfo, &ProcessInfomation);
 
-   delete[] Parameters;
 
-   if (Result)
 
-   {
 
-     Child = ProcessInfomation.hProcess;
 
-   }
 
-   else
 
-   {
 
-     size_t Len = MAX_PATH + 1024;
 
-     DWORD Error = GetLastError();
 
-     wchar_t * Buffer = NULL;
 
-     Len += FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, Error, 0, (LPTSTR)&Buffer, 0, NULL);
 
-     wchar_t* Message = new wchar_t[Len];
 
-     wsprintf(Message, L"Cannot start WinSCP application \"%s\".", ChildPath);
 
-     if (Buffer != NULL)
 
-     {
 
-       wcscat(Message, L"\n");
 
-       wcscat(Message, Buffer);
 
-       LocalFree(Buffer);
 
-     }
 
-     char* MessageString = WideStringToString(Message);
 
-     delete[] Message;
 
-     std::string ErrorString(MessageString);
 
-     delete[] MessageString;
 
-     throw runtime_error(ErrorString);
 
-   }
 
- }
 
- //---------------------------------------------------------------------------
 
- void FinalizeChild(HANDLE Child)
 
- {
 
-   if (Child != NULL)
 
-   {
 
-     TerminateProcess(Child, 0);
 
-     CloseHandle(Child);
 
-   }
 
- }
 
- //---------------------------------------------------------------------------
 
- void FinalizeConsole(const wchar_t* /*InstanceName*/, HANDLE RequestEvent,
 
-   HANDLE ResponseEvent, HANDLE CancelEvent, HANDLE FileMapping, HANDLE Job)
 
- {
 
-   CloseHandle(RequestEvent);
 
-   CloseHandle(ResponseEvent);
 
-   CloseHandle(CancelEvent);
 
-   CloseHandle(FileMapping);
 
-   if (Job != NULL)
 
-   {
 
-     CloseHandle(Job);
 
-   }
 
- }
 
- //---------------------------------------------------------------------------
 
- static wchar_t LastFromBeginning[sizeof(TConsoleCommStruct::TPrintEvent)] = L""; //???
 
- //---------------------------------------------------------------------------
 
- inline void Flush()
 
- {
 
-   if ((OutputType == FILE_TYPE_DISK) || (OutputType == FILE_TYPE_PIPE))
 
-   {
 
-     fflush(stdout);
 
-   }
 
- }
 
- //---------------------------------------------------------------------------
 
- void Print(const wchar_t* Message)
 
- {
 
-   char* Buffer = WideStringToString(Message);
 
-   if (Buffer != NULL)
 
-   {
 
-     char* Ptr = Buffer;
 
-     while ((Ptr = strchr(Ptr, '\n')) != NULL)
 
-     {
 
-       memmove(Ptr + 1, Ptr, strlen(Ptr) + 1);
 
-       *Ptr = '\r';
 
-       Ptr += 2;
 
-     }
 
-     unsigned long Written;
 
-     WriteFile(ConsoleOutput, Buffer, strlen(Buffer), &Written, NULL);
 
-     delete[] Buffer;
 
-   }
 
- }
 
- //---------------------------------------------------------------------------
 
- void Print(bool FromBeginning, const wchar_t* Message)
 
- {
 
-   size_t Len = wcslen(Message);
 
-   if ((OutputType == FILE_TYPE_DISK) || (OutputType == FILE_TYPE_PIPE))
 
-   {
 
-     if (FromBeginning && (Message[0] != L'\n'))
 
-     {
 
-       wcscpy(LastFromBeginning, Message);
 
-     }
 
-     else
 
-     {
 
-       if (LastFromBeginning[0] != L'\0')
 
-       {
 
-         Print(LastFromBeginning);
 
-         LastFromBeginning[0] = L'\0';
 
-       }
 
-       if (FromBeginning && (Message[0] == L'\n'))
 
-       {
 
-         Print(L"\n");
 
-         wcscpy(LastFromBeginning, Message + 1);
 
-       }
 
-       else
 
-       {
 
-         Print(Message);
 
-       }
 
-       Flush();
 
-     }
 
-   }
 
-   else
 
-   {
 
-     unsigned long Written;
 
-     if (FromBeginning)
 
-     {
 
-       WriteConsole(ConsoleOutput, L"\r", 1, &Written, NULL);
 
-     }
 
-     bool WriteResult =
 
-       WriteConsole(ConsoleOutput, Message, Len, &Written, NULL);
 
-     int Error = GetLastError();
 
-     // The current console font does not support some characters in the message,
 
-     // fall back to ansi-writting
 
-     if (!WriteResult && (Error == ERROR_GEN_FAILURE))
 
-     {
 
-       int Size = WideCharToMultiByte(CP_ACP, 0, Message, -1, 0, 0, 0, 0);
 
-       if (Size > 0)
 
-       {
 
-         char* Buffer = new char[Size];
 
-         if (WideCharToMultiByte(CP_ACP, 0, Message, -1, Buffer, Size, 0, 0) > 0)
 
-         {
 
-           WriteConsoleA(ConsoleOutput, Buffer, strlen(Buffer), &Written, NULL);
 
-         }
 
-         delete[] Buffer;
 
-       }
 
-     }
 
-   }
 
- }
 
- //---------------------------------------------------------------------------
 
- inline void ProcessPrintEvent(TConsoleCommStruct::TPrintEvent& Event)
 
- {
 
-   Print(Event.FromBeginning, Event.Message);
 
- }
 
- //---------------------------------------------------------------------------
 
- void CancelInput()
 
- {
 
-   SetEvent(CancelEvent);
 
- }
 
- //---------------------------------------------------------------------------
 
- void BreakInput()
 
- {
 
-   FlushConsoleInputBuffer(ConsoleInput);
 
-   INPUT_RECORD InputRecord;
 
-   memset(&InputRecord, 0, sizeof(InputRecord));
 
-   InputRecord.EventType = KEY_EVENT;
 
-   InputRecord.Event.KeyEvent.bKeyDown = true;
 
-   InputRecord.Event.KeyEvent.wRepeatCount = 1;
 
-   InputRecord.Event.KeyEvent.uChar.UnicodeChar = L'\r';
 
-   unsigned long Written;
 
-   WriteConsoleInput(ConsoleInput, &InputRecord, 1, &Written);
 
-   CancelInput();
 
- }
 
- //---------------------------------------------------------------------------
 
- DWORD WINAPI InputTimerThreadProc(void* Parameter)
 
- {
 
-   unsigned int Timer = reinterpret_cast<unsigned int>(Parameter);
 
-   unsigned int Remaining = Timer;
 
-   const unsigned int Step = 1000;
 
-   const int FirstKey = VK_LBUTTON; // 0x01
 
-   const int LastKey = VK_OEM_CLEAR; // 0xFE
 
-   // reset key state
 
-   for (int Key = FirstKey; Key <= LastKey; Key++)
 
-   {
 
-     GetAsyncKeyState(Key);
 
-   }
 
-   while (Remaining > 0)
 
-   {
 
-     unsigned long WaitResult = WaitForSingleObject(InputTimerEvent, Step);
 
-     if (WaitResult == WAIT_OBJECT_0)
 
-     {
 
-       // input entered
 
-       Remaining = 0;
 
-     }
 
-     else if (WaitResult == WAIT_TIMEOUT)
 
-     {
 
-       bool Input = false;
 
-       for (int Key = FirstKey; Key <= LastKey; Key++)
 
-       {
 
-         if ((GetAsyncKeyState(Key) & 0x01) != 0)
 
-         {
 
-           Input = true;
 
-           // Finishing the loop nevertheless to reset state of all keys
 
-         }
 
-       }
 
-       if (Input)
 
-       {
 
-         // If we have new input, reset timer
 
-         Remaining = Timer;
 
-       }
 
-       else if (Remaining > Step)
 
-       {
 
-         Remaining -= Step;
 
-       }
 
-       else
 
-       {
 
-         BreakInput();
 
-         Remaining = 0;
 
-       }
 
-     }
 
-     else
 
-     {
 
-       // abort input on (unlikely) error
 
-       BreakInput();
 
-       Remaining = 0;
 
-     }
 
-   }
 
-   return 0;
 
- }
 
- //---------------------------------------------------------------------------
 
- void ProcessInputEvent(TConsoleCommStruct::TInputEvent& Event)
 
- {
 
-   if ((InputType == FILE_TYPE_DISK) || (InputType == FILE_TYPE_PIPE))
 
-   {
 
-     unsigned long Bytes = 0;
 
-     unsigned long Read;
 
-     bool Result;
 
-     char Ch;
 
-     char Buf[LENOF(Event.Str) * 3];
 
-     while (((Result = (ReadFile(ConsoleInput, &Ch, 1, &Read, NULL) != 0)) != false) &&
 
-            (Read > 0) && (Bytes < LENOF(Buf) - 1) && (Ch != '\n'))
 
-     {
 
-       if (Ch != '\r')
 
-       {
 
-         Buf[Bytes] = Ch;
 
-         Bytes++;
 
-       }
 
-     }
 
-     Buf[Bytes] = L'\0';
 
-     MultiByteToWideChar(CP_UTF8, 0, Buf, -1, Event.Str, LENOF(Event.Str) - 1);
 
-     Event.Str[LENOF(Event.Str) - 1] = L'\0';
 
-     Print(false, Event.Str);
 
-     Print(false, L"\n");
 
-     Event.Result = ((Result && (Read > 0)) || (Bytes > 0));
 
-   }
 
-   else
 
-   {
 
-     unsigned long PrevMode, NewMode;
 
-     GetConsoleMode(ConsoleInput, &PrevMode);
 
-     NewMode = PrevMode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
 
-     if (Event.Echo)
 
-     {
 
-       NewMode |= ENABLE_ECHO_INPUT;
 
-     }
 
-     else
 
-     {
 
-       NewMode &= ~ENABLE_ECHO_INPUT;
 
-     }
 
-     SetConsoleMode(ConsoleInput, NewMode);
 
-     HANDLE InputTimerThread = NULL;
 
-     try
 
-     {
 
-       if (Event.Timer > 0)
 
-       {
 
-         unsigned long ThreadId;
 
-         InputTimerEvent = CreateEvent(NULL, false, false, NULL);
 
-         InputTimerThread = CreateThread(NULL, 0, InputTimerThreadProc,
 
-           reinterpret_cast<void *>(Event.Timer), 0, &ThreadId);
 
-       }
 
-       unsigned long Read;
 
-       Event.Result = ReadConsole(ConsoleInput, Event.Str, LENOF(Event.Str) - 1, &Read, NULL);
 
-       Event.Str[Read] = L'\0';
 
-       bool PendingCancel = (WaitForSingleObject(CancelEvent, 0) == WAIT_OBJECT_0);
 
-       if (PendingCancel || !Event.Echo)
 
-       {
 
-         WriteFile(ConsoleOutput, "\n", 1, NULL, NULL);
 
-         Flush();
 
-       }
 
-       if (PendingCancel || (Read == 0))
 
-       {
 
-         Event.Result = false;
 
-       }
 
-     }
 
-     __finally
 
-     {
 
-       if (InputTimerThread != NULL)
 
-       {
 
-         SetEvent(InputTimerEvent);
 
-         WaitForSingleObject(InputTimerThread, 100);
 
-         CloseHandle(InputTimerEvent);
 
-         InputTimerEvent = NULL;
 
-         CloseHandle(InputTimerThread);
 
-       }
 
-       SetConsoleMode(ConsoleInput, PrevMode);
 
-     }
 
-   }
 
- }
 
- //---------------------------------------------------------------------------
 
- void ProcessChoiceEvent(TConsoleCommStruct::TChoiceEvent& Event)
 
- {
 
-   // note that if output is redirected to file, input is still FILE_TYPE_CHAR
 
-   if ((InputType == FILE_TYPE_DISK) || (InputType == FILE_TYPE_PIPE))
 
-   {
 
-     if (Event.Timeouting)
 
-     {
 
-       Sleep(Event.Timer);
 
-       Event.Result = Event.Timeouted;
 
-     }
 
-     else
 
-     {
 
-       Event.Result = Event.Break;
 
-     }
 
-   }
 
-   else
 
-   {
 
-     Event.Result = 0;
 
-     unsigned long PrevMode, NewMode;
 
-     GetConsoleMode(ConsoleInput, &PrevMode);
 
-     NewMode = (PrevMode | ENABLE_PROCESSED_INPUT) & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
 
-     SetConsoleMode(ConsoleInput, NewMode);
 
-     unsigned int ATimer = Event.Timer;
 
-     try
 
-     {
 
-       do
 
-       {
 
-         unsigned long Read;
 
-         INPUT_RECORD Record;
 
-         if ((PeekConsoleInput(ConsoleInput, &Record, 1, &Read) != 0) &&
 
-             (Read == 1))
 
-         {
 
-           if ((ReadConsoleInput(ConsoleInput, &Record, 1, &Read) != 0) &&
 
-               (Read == 1))
 
-           {
 
-             bool PendingCancel = (WaitForSingleObject(CancelEvent, 0) == WAIT_OBJECT_0);
 
-             if (PendingCancel)
 
-             {
 
-               Event.Result = Event.Break;
 
-             }
 
-             else if ((Record.EventType == KEY_EVENT) &&
 
-                      Record.Event.KeyEvent.bKeyDown)
 
-             {
 
-               // This happens when Shift key is pressed
 
-               if (Record.Event.KeyEvent.uChar.UnicodeChar != 0)
 
-               {
 
-                 wchar_t CStr[2];
 
-                 CStr[0] = Record.Event.KeyEvent.uChar.UnicodeChar;
 
-                 CStr[1] = L'\0';
 
-                 CharUpperBuff(CStr, 1);
 
-                 wchar_t C = CStr[0];
 
-                 if (C == 27)
 
-                 {
 
-                   Event.Result = Event.Cancel;
 
-                 }
 
-                 else if ((wcschr(Event.Options, C) != NULL) &&
 
-                          ((Record.Event.KeyEvent.dwControlKeyState &
 
-                            (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED | LEFT_ALT_PRESSED |
 
-                            RIGHT_ALT_PRESSED)) == 0))
 
-                 {
 
-                   Event.Result = wcschr(Event.Options, C) - Event.Options + 1;
 
-                 }
 
-               }
 
-             }
 
-           }
 
-         }
 
-         if (Event.Result == 0)
 
-         {
 
-           unsigned int TimerSlice = 50;
 
-           Sleep(TimerSlice);
 
-           if (Event.Timer > 0)
 
-           {
 
-             if (ATimer > TimerSlice)
 
-             {
 
-               ATimer -= TimerSlice;
 
-             }
 
-             else
 
-             {
 
-               Event.Result = Event.Timeouted;
 
-             }
 
-           }
 
-         }
 
-       }
 
-       while (Event.Result == 0);
 
-       SetConsoleMode(ConsoleInput, PrevMode);
 
-     }
 
-     catch(...)
 
-     {
 
-       SetConsoleMode(ConsoleInput, PrevMode);
 
-       throw;
 
-     }
 
-   }
 
- }
 
- //---------------------------------------------------------------------------
 
- inline void ProcessTitleEvent(TConsoleCommStruct::TTitleEvent& Event)
 
- {
 
-   SetConsoleTitle(Event.Title);
 
- }
 
- //---------------------------------------------------------------------------
 
- inline void ProcessInitEvent(TConsoleCommStruct::TInitEvent& Event)
 
- {
 
-   Event.InputType = InputType;
 
-   Event.OutputType = OutputType;
 
-   // default anyway
 
-   Event.WantsProgress = false;
 
- }
 
- //---------------------------------------------------------------------------
 
- void ProcessEvent(HANDLE ResponseEvent, HANDLE FileMapping)
 
- {
 
-   TConsoleCommStruct* CommStruct = GetCommStruct(FileMapping);
 
-   try
 
-   {
 
-     if (CommStruct->Version != TConsoleCommStruct::CurrentVersionConfirmed)
 
-     {
 
-       throw runtime_error("Incompatible console protocol version");
 
-     }
 
-     switch (CommStruct->Event)
 
-     {
 
-       case TConsoleCommStruct::PRINT:
 
-         ProcessPrintEvent(CommStruct->PrintEvent);
 
-         break;
 
-       case TConsoleCommStruct::INPUT:
 
-         ProcessInputEvent(CommStruct->InputEvent);
 
-         break;
 
-       case TConsoleCommStruct::CHOICE:
 
-         ProcessChoiceEvent(CommStruct->ChoiceEvent);
 
-         break;
 
-       case TConsoleCommStruct::TITLE:
 
-         ProcessTitleEvent(CommStruct->TitleEvent);
 
-         break;
 
-       case TConsoleCommStruct::INIT:
 
-         ProcessInitEvent(CommStruct->InitEvent);
 
-         break;
 
-       default:
 
-         throw runtime_error("Unknown event");
 
-     }
 
-     FreeCommStruct(CommStruct);
 
-     SetEvent(ResponseEvent);
 
-   }
 
-   catch(...)
 
-   {
 
-     FreeCommStruct(CommStruct);
 
-     throw;
 
-   }
 
- }
 
- //---------------------------------------------------------------------------
 
- BOOL WINAPI HandlerRoutine(DWORD CtrlType)
 
- {
 
-   if ((CtrlType == CTRL_C_EVENT) || (CtrlType == CTRL_BREAK_EVENT))
 
-   {
 
-     CancelInput();
 
-     return true;
 
-   }
 
-   else
 
-   {
 
-     FinalizeChild(Child);
 
-     return false;
 
-   }
 
- }
 
- //---------------------------------------------------------------------------
 
- #pragma argsused
 
- int wmain(int /*argc*/, wchar_t* /*argv*/[])
 
- {
 
-   unsigned long Result = RESULT_UNKNOWN_ERROR;
 
-   try
 
-   {
 
-     randomize();
 
-     OSVERSIONINFO VersionInfo;
 
-     VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
 
-     GetVersionEx(&VersionInfo);
 
-     ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
 
-     InputType = GetFileType(ConsoleInput);
 
-     SetConsoleCtrlHandler(HandlerRoutine, true);
 
-     unsigned int SavedConsoleCP = GetConsoleCP();
 
-     unsigned int SavedConsoleOutputCP = GetConsoleOutputCP();
 
-     ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 
-     OutputType = GetFileType(ConsoleOutput);
 
-     bool SupportsUtf8ConsoleOutput =
 
-       ((VersionInfo.dwMajorVersion == 6) && (VersionInfo.dwMinorVersion >= 1)) ||
 
-       (VersionInfo.dwMajorVersion > 6);
 
-     if ((InputType == FILE_TYPE_DISK) || (InputType == FILE_TYPE_PIPE) ||
 
-         SupportsUtf8ConsoleOutput)
 
-     {
 
-       SetConsoleCP(CP_UTF8);
 
-     }
 
-     else
 
-     {
 
-       SetConsoleCP(CP_ACP);
 
-     }
 
-     if ((OutputType == FILE_TYPE_DISK) || (OutputType == FILE_TYPE_PIPE) ||
 
-         SupportsUtf8ConsoleOutput)
 
-     {
 
-       SetConsoleOutputCP(CP_UTF8);
 
-     }
 
-     else
 
-     {
 
-       SetConsoleOutputCP(CP_ACP);
 
-     }
 
-     wchar_t InstanceName[MAX_PATH];
 
-     HANDLE RequestEvent, ResponseEvent, FileMapping, Job;
 
-     InitializeConsole(InstanceName, RequestEvent, ResponseEvent,
 
-       CancelEvent, FileMapping, Job);
 
-     wchar_t SavedTitle[512];
 
-     GetConsoleTitle(SavedTitle, LENOF(SavedTitle));
 
-     try
 
-     {
 
-       #ifndef CONSOLE_TEST
 
-       InitializeChild(GetCommandLine(), InstanceName, Child);
 
-       #endif
 
-       try
 
-       {
 
-         bool Continue = true;
 
-         do
 
-         {
 
-           HANDLE Handles[2];
 
-           Handles[0] = RequestEvent;
 
-           Handles[1] = Child;
 
-           unsigned int HandleCount;
 
-           #ifndef CONSOLE_TEST
 
-           HandleCount = 2;
 
-           #else
 
-           HandleCount = 1;
 
-           #endif
 
-           unsigned long WaitResult =
 
-             WaitForMultipleObjects(HandleCount, Handles, false, INFINITE);
 
-           switch (WaitResult)
 
-           {
 
-             case WAIT_OBJECT_0:
 
-               ProcessEvent(ResponseEvent, FileMapping);
 
-               break;
 
-             case WAIT_OBJECT_0 + 1:
 
-               GetExitCodeProcess(Child, &Result);
 
-               CloseHandle(Child);
 
-               Child = NULL;
 
-               Continue = false;
 
-               break;
 
-             default:
 
-               throw runtime_error("Error waiting for communication from child process.");
 
-           }
 
-         }
 
-         while (Continue);
 
-         // flush pending progress message
 
-         Print(false, L"");
 
-       }
 
-       catch(const exception& e)
 
-       {
 
-         puts(e.what());
 
-         Result = RESULT_PROCESSING_ERROR;
 
-       }
 
-       #ifndef CONSOLE_TEST
 
-       FinalizeChild(Child);
 
-       #endif
 
-       SetConsoleTitle(SavedTitle);
 
-       SetConsoleCP(SavedConsoleCP);
 
-       SetConsoleOutputCP(SavedConsoleOutputCP);
 
-     }
 
-     catch(const exception& e)
 
-     {
 
-       puts(e.what());
 
-       Result = RESULT_INIT_ERROR;
 
-     }
 
-     FinalizeConsole(InstanceName, RequestEvent, ResponseEvent,
 
-       CancelEvent, FileMapping, Job);
 
-   }
 
-   catch(const exception& e)
 
-   {
 
-     puts(e.what());
 
-     Result = RESULT_GLOBAL_ERROR;
 
-   }
 
-   return Result;
 
- }
 
- //---------------------------------------------------------------------------
 
 
  |