├── .gitattributes ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── RELEASES.md ├── VERSION.txt ├── appveyor.yml ├── configure ├── misc ├── .gitignore ├── BufferResizeTests.cc ├── ChangeScreenBuffer.cc ├── ClearConsole.cc ├── ConinMode.cc ├── ConinMode.ps1 ├── ConoutMode.cc ├── DebugClient.py ├── DebugServer.py ├── DumpLines.py ├── EnableExtendedFlags.txt ├── Font-Report-June2016 │ ├── CP437-Consolas.txt │ ├── CP437-Lucida.txt │ ├── CP932.txt │ ├── CP936.txt │ ├── CP949.txt │ ├── CP950.txt │ ├── MinimumWindowWidths.txt │ ├── Results.txt │ └── Windows10SetFontBugginess.txt ├── FontSurvey.cc ├── FormatChar.h ├── FreezePerfTest.cc ├── GetCh.cc ├── GetConsolePos.cc ├── GetFont.cc ├── IdentifyConsoleWindow.ps1 ├── IsNewConsole.cc ├── MouseInputNotes.txt ├── MoveConsoleWindow.cc ├── Notes.txt ├── OSVersion.cc ├── ScreenBufferFreezeInactive.cc ├── ScreenBufferTest.cc ├── ScreenBufferTest2.cc ├── SelectAllTest.cc ├── SetBufInfo.cc ├── SetBufferSize.cc ├── SetCursorPos.cc ├── SetFont.cc ├── SetWindowRect.cc ├── ShowArgv.cc ├── ShowConsoleInput.cc ├── Spew.py ├── TestUtil.cc ├── UnicodeDoubleWidthTest.cc ├── UnicodeWideTest1.cc ├── UnicodeWideTest2.cc ├── UnixEcho.cc ├── Utf16Echo.cc ├── VeryLargeRead.cc ├── VkEscapeTest.cc ├── Win10ResizeWhileFrozen.cc ├── Win10WrapTest1.cc ├── Win10WrapTest2.cc ├── Win32Echo1.cc ├── Win32Echo2.cc ├── Win32Test1.cc ├── Win32Test2.cc ├── Win32Test3.cc ├── Win32Write1.cc ├── WindowsBugCrashReader.cc ├── WriteConsole.cc ├── build32.sh ├── build64.sh ├── color-test.sh ├── font-notes.txt └── winbug-15048.cc ├── ship ├── build-pty4j-libpty.bat ├── common_ship.py ├── make_msvc_package.py └── ship.py ├── src ├── agent │ ├── Agent.cc │ ├── Agent.h │ ├── AgentCreateDesktop.cc │ ├── AgentCreateDesktop.h │ ├── ConsoleFont.cc │ ├── ConsoleFont.h │ ├── ConsoleInput.cc │ ├── ConsoleInput.h │ ├── ConsoleInputReencoding.cc │ ├── ConsoleInputReencoding.h │ ├── ConsoleLine.cc │ ├── ConsoleLine.h │ ├── Coord.h │ ├── DebugShowInput.cc │ ├── DebugShowInput.h │ ├── DefaultInputMap.cc │ ├── DefaultInputMap.h │ ├── DsrSender.h │ ├── EventLoop.cc │ ├── EventLoop.h │ ├── InputMap.cc │ ├── InputMap.h │ ├── LargeConsoleRead.cc │ ├── LargeConsoleRead.h │ ├── NamedPipe.cc │ ├── NamedPipe.h │ ├── Scraper.cc │ ├── Scraper.h │ ├── SimplePool.h │ ├── SmallRect.h │ ├── Terminal.cc │ ├── Terminal.h │ ├── UnicodeEncoding.h │ ├── UnicodeEncodingTest.cc │ ├── Win32Console.cc │ ├── Win32Console.h │ ├── Win32ConsoleBuffer.cc │ ├── Win32ConsoleBuffer.h │ ├── main.cc │ └── subdir.mk ├── configurations.gypi ├── debugserver │ ├── DebugServer.cc │ └── subdir.mk ├── include │ ├── winpty.h │ └── winpty_constants.h ├── libwinpty │ ├── AgentLocation.cc │ ├── AgentLocation.h │ ├── LibWinptyException.h │ ├── WinptyInternal.h │ ├── subdir.mk │ └── winpty.cc ├── shared │ ├── AgentMsg.h │ ├── BackgroundDesktop.cc │ ├── BackgroundDesktop.h │ ├── Buffer.cc │ ├── Buffer.h │ ├── DebugClient.cc │ ├── DebugClient.h │ ├── GenRandom.cc │ ├── GenRandom.h │ ├── GetCommitHash.bat │ ├── Mutex.h │ ├── OsModule.h │ ├── OwnedHandle.cc │ ├── OwnedHandle.h │ ├── PrecompiledHeader.h │ ├── StringBuilder.h │ ├── StringBuilderTest.cc │ ├── StringUtil.cc │ ├── StringUtil.h │ ├── TimeMeasurement.h │ ├── UnixCtrlChars.h │ ├── UpdateGenVersion.bat │ ├── WindowsSecurity.cc │ ├── WindowsSecurity.h │ ├── WindowsVersion.cc │ ├── WindowsVersion.h │ ├── WinptyAssert.cc │ ├── WinptyAssert.h │ ├── WinptyException.cc │ ├── WinptyException.h │ ├── WinptyVersion.cc │ ├── WinptyVersion.h │ └── winpty_snprintf.h ├── subdir.mk ├── tests │ ├── subdir.mk │ └── trivial_test.cc ├── unix-adapter │ ├── InputHandler.cc │ ├── InputHandler.h │ ├── OutputHandler.cc │ ├── OutputHandler.h │ ├── Util.cc │ ├── Util.h │ ├── WakeupFd.cc │ ├── WakeupFd.h │ ├── main.cc │ └── subdir.mk └── winpty.gyp └── vcbuild.bat /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.bat text eol=crlf 3 | *.c text 4 | *.cc text 5 | *.gyp text 6 | *.gypi text 7 | *.h text 8 | *.ps1 text eol=crlf 9 | *.rst text 10 | *.sh text 11 | *.txt text 12 | .gitignore text 13 | .gitattributes text 14 | Makefile text 15 | configure text 16 | 17 | *.sh eol=lf 18 | configure eol=lf 19 | VERSION.txt eol=lf 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.sln 2 | *.suo 3 | *.vcxproj 4 | *.vcxproj.filters 5 | *.pyc 6 | winpty.sdf 7 | winpty.opensdf 8 | /config.mk 9 | /build 10 | /build-gyp 11 | /build-libpty 12 | /ship/packages 13 | /ship/tmp 14 | /src/Default 15 | /src/Release 16 | /src/gen 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2016 Ryan Prichard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to 7 | deal in the Software without restriction, including without limitation the 8 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9 | sell copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /VERSION.txt: -------------------------------------------------------------------------------- 1 | 0.4.4-dev 2 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2015 2 | 3 | init: 4 | - C:\msys64\usr\bin\bash --login -c "pacman -S --needed --noconfirm --noprogressbar msys/make msys/tar msys/gcc mingw-w64-cross-toolchain" 5 | - C:\cygwin\setup-x86 -q -P mingw64-i686-gcc-g++,mingw64-x86_64-gcc-g++,make 6 | - C:\cygwin64\setup-x86_64 -q -P mingw64-i686-gcc-g++,mingw64-x86_64-gcc-g++,make 7 | 8 | build_script: 9 | - C:\Python27-x64\python.exe ship\ship.py --kind msys2 --arch x64 --syspath C:\msys64 10 | - C:\Python27-x64\python.exe ship\ship.py --kind cygwin --arch ia32 --syspath C:\cygwin 11 | - C:\Python27-x64\python.exe ship\ship.py --kind cygwin --arch x64 --syspath C:\cygwin64 12 | - C:\Python27-x64\python.exe ship\make_msvc_package.py 13 | 14 | artifacts: 15 | - path: ship\packages\*.tar.gz 16 | - path: ship\packages\*.zip 17 | -------------------------------------------------------------------------------- /misc/.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | UnixEcho -------------------------------------------------------------------------------- /misc/BufferResizeTests.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "TestUtil.cc" 5 | 6 | void dumpInfoToTrace() { 7 | CONSOLE_SCREEN_BUFFER_INFO info; 8 | assert(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info)); 9 | trace("win=(%d,%d,%d,%d)", 10 | (int)info.srWindow.Left, 11 | (int)info.srWindow.Top, 12 | (int)info.srWindow.Right, 13 | (int)info.srWindow.Bottom); 14 | trace("buf=(%d,%d)", 15 | (int)info.dwSize.X, 16 | (int)info.dwSize.Y); 17 | trace("cur=(%d,%d)", 18 | (int)info.dwCursorPosition.X, 19 | (int)info.dwCursorPosition.Y); 20 | } 21 | 22 | int main(int argc, char *argv[]) { 23 | if (argc == 1) { 24 | startChildProcess(L"CHILD"); 25 | return 0; 26 | } 27 | 28 | setWindowPos(0, 0, 1, 1); 29 | 30 | if (false) { 31 | // Reducing the buffer height can move the window up. 32 | setBufferSize(80, 25); 33 | setWindowPos(0, 20, 80, 5); 34 | Sleep(2000); 35 | setBufferSize(80, 10); 36 | } 37 | 38 | if (false) { 39 | // Reducing the buffer height moves the window up and the buffer 40 | // contents up too. 41 | setBufferSize(80, 25); 42 | setWindowPos(0, 20, 80, 5); 43 | setCursorPos(0, 20); 44 | printf("TEST1\nTEST2\nTEST3\nTEST4\n"); 45 | fflush(stdout); 46 | Sleep(2000); 47 | setBufferSize(80, 10); 48 | } 49 | 50 | if (false) { 51 | // Reducing the buffer width can move the window left. 52 | setBufferSize(80, 25); 53 | setWindowPos(40, 0, 40, 25); 54 | Sleep(2000); 55 | setBufferSize(60, 25); 56 | } 57 | 58 | if (false) { 59 | // Sometimes the buffer contents are shifted up; sometimes they're 60 | // shifted down. It seems to depend on the cursor position? 61 | 62 | // setBufferSize(80, 25); 63 | // setWindowPos(0, 20, 80, 5); 64 | // setCursorPos(0, 20); 65 | // printf("TESTa\nTESTb\nTESTc\nTESTd\nTESTe"); 66 | // fflush(stdout); 67 | // setCursorPos(0, 0); 68 | // printf("TEST1\nTEST2\nTEST3\nTEST4\nTEST5"); 69 | // fflush(stdout); 70 | // setCursorPos(0, 24); 71 | // Sleep(5000); 72 | // setBufferSize(80, 24); 73 | 74 | setBufferSize(80, 20); 75 | setWindowPos(0, 10, 80, 10); 76 | setCursorPos(0, 18); 77 | 78 | printf("TEST1\nTEST2"); 79 | fflush(stdout); 80 | setCursorPos(0, 18); 81 | 82 | Sleep(2000); 83 | setBufferSize(80, 18); 84 | } 85 | 86 | dumpInfoToTrace(); 87 | Sleep(30000); 88 | 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /misc/ChangeScreenBuffer.cc: -------------------------------------------------------------------------------- 1 | // A test program for CreateConsoleScreenBuffer / SetConsoleActiveScreenBuffer 2 | // 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "TestUtil.cc" 11 | 12 | int main() 13 | { 14 | HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE); 15 | HANDLE childBuffer = CreateConsoleScreenBuffer( 16 | GENERIC_READ | GENERIC_WRITE, 17 | FILE_SHARE_READ | FILE_SHARE_WRITE, 18 | NULL, CONSOLE_TEXTMODE_BUFFER, NULL); 19 | 20 | SetConsoleActiveScreenBuffer(childBuffer); 21 | 22 | while (true) { 23 | char buf[1024]; 24 | CONSOLE_SCREEN_BUFFER_INFO info; 25 | 26 | assert(GetConsoleScreenBufferInfo(origBuffer, &info)); 27 | trace("child.size=(%d,%d)", (int)info.dwSize.X, (int)info.dwSize.Y); 28 | trace("child.cursor=(%d,%d)", (int)info.dwCursorPosition.X, (int)info.dwCursorPosition.Y); 29 | trace("child.window=(%d,%d,%d,%d)", 30 | (int)info.srWindow.Left, (int)info.srWindow.Top, 31 | (int)info.srWindow.Right, (int)info.srWindow.Bottom); 32 | trace("child.maxSize=(%d,%d)", (int)info.dwMaximumWindowSize.X, (int)info.dwMaximumWindowSize.Y); 33 | 34 | int ch = getch(); 35 | sprintf(buf, "%02x\n", ch); 36 | DWORD actual = 0; 37 | WriteFile(childBuffer, buf, strlen(buf), &actual, NULL); 38 | if (ch == 0x1b/*ESC*/ || ch == 0x03/*CTRL-C*/) 39 | break; 40 | 41 | if (ch == 'b') { 42 | setBufferSize(origBuffer, 40, 25); 43 | } else if (ch == 'w') { 44 | setWindowPos(origBuffer, 1, 1, 38, 23); 45 | } else if (ch == 'c') { 46 | setCursorPos(origBuffer, 10, 10); 47 | } 48 | } 49 | 50 | SetConsoleActiveScreenBuffer(origBuffer); 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /misc/ClearConsole.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Demonstrates that console clearing sets each cell's character to SP, not 3 | * NUL, and it sets the attribute of each cell to the current text attribute. 4 | * 5 | * This confirms the MSDN instruction in the "Clearing the Screen" article. 6 | * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682022(v=vs.85).aspx 7 | * It advises using GetConsoleScreenBufferInfo to get the current text 8 | * attribute, then FillConsoleOutputCharacter and FillConsoleOutputAttribute to 9 | * write to the console buffer. 10 | */ 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include "TestUtil.cc" 19 | 20 | int main(int argc, char *argv[]) { 21 | if (argc == 1) { 22 | startChildProcess(L"CHILD"); 23 | return 0; 24 | } 25 | 26 | const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); 27 | 28 | SetConsoleTextAttribute(conout, 0x24); 29 | system("cls"); 30 | 31 | setWindowPos(0, 0, 1, 1); 32 | setBufferSize(80, 25); 33 | setWindowPos(0, 0, 80, 25); 34 | 35 | CHAR_INFO buf; 36 | COORD bufSize = { 1, 1 }; 37 | COORD bufCoord = { 0, 0 }; 38 | SMALL_RECT rect = { 5, 5, 5, 5 }; 39 | BOOL ret; 40 | DWORD actual; 41 | COORD writeCoord = { 5, 5 }; 42 | 43 | // After cls, each cell's character is a space, and its attributes are the 44 | // default text attributes. 45 | ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect); 46 | assert(ret && buf.Char.UnicodeChar == L' ' && buf.Attributes == 0x24); 47 | 48 | // Nevertheless, it is possible to change a cell to NUL. 49 | ret = FillConsoleOutputCharacterW(conout, L'\0', 1, writeCoord, &actual); 50 | assert(ret && actual == 1); 51 | ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect); 52 | assert(ret && buf.Char.UnicodeChar == L'\0' && buf.Attributes == 0x24); 53 | 54 | // As well as a 0 attribute. (As one would expect, the cell is 55 | // black-on-black.) 56 | ret = FillConsoleOutputAttribute(conout, 0, 1, writeCoord, &actual); 57 | assert(ret && actual == 1); 58 | ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect); 59 | assert(ret && buf.Char.UnicodeChar == L'\0' && buf.Attributes == 0); 60 | ret = FillConsoleOutputCharacterW(conout, L'X', 1, writeCoord, &actual); 61 | assert(ret && actual == 1); 62 | ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect); 63 | assert(ret && buf.Char.UnicodeChar == L'X' && buf.Attributes == 0); 64 | 65 | // The 'X' is invisible. 66 | countDown(3); 67 | 68 | ret = FillConsoleOutputAttribute(conout, 0x42, 1, writeCoord, &actual); 69 | assert(ret && actual == 1); 70 | 71 | countDown(5); 72 | } 73 | -------------------------------------------------------------------------------- /misc/ConinMode.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # PowerShell script for controlling the console QuickEdit and InsertMode flags. 3 | # 4 | # Turn QuickEdit off to interact with mouse-driven console programs. 5 | # 6 | # Usage: 7 | # 8 | # powershell .\ConinMode.ps1 [Options] 9 | # 10 | # Options: 11 | # -QuickEdit [on/off] 12 | # -InsertMode [on/off] 13 | # -Mode [integer] 14 | # 15 | 16 | param ( 17 | [ValidateSet("on", "off")][string] $QuickEdit, 18 | [ValidateSet("on", "off")][string] $InsertMode, 19 | [int] $Mode 20 | ) 21 | 22 | $signature = @' 23 | [DllImport("kernel32.dll", SetLastError = true)] 24 | public static extern IntPtr GetStdHandle(int nStdHandle); 25 | 26 | [DllImport("kernel32.dll", SetLastError = true)] 27 | public static extern uint GetConsoleMode( 28 | IntPtr hConsoleHandle, 29 | out uint lpMode); 30 | 31 | [DllImport("kernel32.dll", SetLastError = true)] 32 | public static extern uint SetConsoleMode( 33 | IntPtr hConsoleHandle, 34 | uint dwMode); 35 | 36 | public const int STD_INPUT_HANDLE = -10; 37 | public const int ENABLE_INSERT_MODE = 0x0020; 38 | public const int ENABLE_QUICK_EDIT_MODE = 0x0040; 39 | public const int ENABLE_EXTENDED_FLAGS = 0x0080; 40 | '@ 41 | 42 | $WinAPI = Add-Type -MemberDefinition $signature ` 43 | -Name WinAPI -Namespace ConinModeScript ` 44 | -PassThru 45 | 46 | function GetConIn { 47 | $ret = $WinAPI::GetStdHandle($WinAPI::STD_INPUT_HANDLE) 48 | if ($ret -eq -1) { 49 | throw "error: cannot get stdin" 50 | } 51 | return $ret 52 | } 53 | 54 | function GetConsoleMode { 55 | $conin = GetConIn 56 | $mode = 0 57 | $ret = $WinAPI::GetConsoleMode($conin, [ref]$mode) 58 | if ($ret -eq 0) { 59 | throw "GetConsoleMode failed (is stdin a console?)" 60 | } 61 | return $mode 62 | } 63 | 64 | function SetConsoleMode($mode) { 65 | $conin = GetConIn 66 | $ret = $WinAPI::SetConsoleMode($conin, $mode) 67 | if ($ret -eq 0) { 68 | throw "SetConsoleMode failed (is stdin a console?)" 69 | } 70 | } 71 | 72 | $oldMode = GetConsoleMode 73 | $newMode = $oldMode 74 | $doingSomething = $false 75 | 76 | if ($PSBoundParameters.ContainsKey("Mode")) { 77 | $newMode = $Mode 78 | $doingSomething = $true 79 | } 80 | 81 | if ($QuickEdit + $InsertMode -ne "") { 82 | if (!($newMode -band $WinAPI::ENABLE_EXTENDED_FLAGS)) { 83 | # We can't enable an extended flag without overwriting the existing 84 | # QuickEdit/InsertMode flags. AFAICT, there is no way to query their 85 | # existing values, so at least we can choose sensible defaults. 86 | $newMode = $newMode -bor $WinAPI::ENABLE_EXTENDED_FLAGS 87 | $newMode = $newMode -bor $WinAPI::ENABLE_QUICK_EDIT_MODE 88 | $newMode = $newMode -bor $WinAPI::ENABLE_INSERT_MODE 89 | $doingSomething = $true 90 | } 91 | } 92 | 93 | if ($QuickEdit -eq "on") { 94 | $newMode = $newMode -bor $WinAPI::ENABLE_QUICK_EDIT_MODE 95 | $doingSomething = $true 96 | } elseif ($QuickEdit -eq "off") { 97 | $newMode = $newMode -band (-bnot $WinAPI::ENABLE_QUICK_EDIT_MODE) 98 | $doingSomething = $true 99 | } 100 | 101 | if ($InsertMode -eq "on") { 102 | $newMode = $newMode -bor $WinAPI::ENABLE_INSERT_MODE 103 | $doingSomething = $true 104 | } elseif ($InsertMode -eq "off") { 105 | $newMode = $newMode -band (-bnot $WinAPI::ENABLE_INSERT_MODE) 106 | $doingSomething = $true 107 | } 108 | 109 | if ($doingSomething) { 110 | echo "old mode: $oldMode" 111 | SetConsoleMode $newMode 112 | $newMode = GetConsoleMode 113 | echo "new mode: $newMode" 114 | } else { 115 | echo "mode: $oldMode" 116 | } 117 | -------------------------------------------------------------------------------- /misc/ConoutMode.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | static HANDLE getConout() { 11 | HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); 12 | if (conout == INVALID_HANDLE_VALUE) { 13 | fprintf(stderr, "error: cannot get stdout\n"); 14 | exit(1); 15 | } 16 | return conout; 17 | } 18 | 19 | static DWORD getConsoleMode() { 20 | DWORD mode = 0; 21 | if (!GetConsoleMode(getConout(), &mode)) { 22 | fprintf(stderr, "error: GetConsoleMode failed (is stdout a console?)\n"); 23 | exit(1); 24 | } 25 | return mode; 26 | } 27 | 28 | static void setConsoleMode(DWORD mode) { 29 | if (!SetConsoleMode(getConout(), mode)) { 30 | fprintf(stderr, "error: SetConsoleMode failed (is stdout a console?)\n"); 31 | exit(1); 32 | } 33 | } 34 | 35 | static long parseInt(const std::string &s) { 36 | errno = 0; 37 | char *endptr = nullptr; 38 | long result = strtol(s.c_str(), &endptr, 0); 39 | if (errno != 0 || !endptr || *endptr != '\0') { 40 | fprintf(stderr, "error: could not parse integral argument '%s'\n", s.c_str()); 41 | exit(1); 42 | } 43 | return result; 44 | } 45 | 46 | static void usage() { 47 | printf("Usage: ConoutMode [verb] [options]\n"); 48 | printf("Verbs:\n"); 49 | printf(" [info] Dumps info about mode flags.\n"); 50 | printf(" get Prints the mode DWORD.\n"); 51 | printf(" set VALUE Sets the mode to VALUE, which can be decimal, hex, or octal.\n"); 52 | printf(" set VALUE MASK\n"); 53 | printf(" Same as `set VALUE`, but only alters the bits in MASK.\n"); 54 | exit(1); 55 | } 56 | 57 | struct { 58 | const char *name; 59 | DWORD value; 60 | } kOutputFlags[] = { 61 | "ENABLE_PROCESSED_OUTPUT", ENABLE_PROCESSED_OUTPUT, // 0x0001 62 | "ENABLE_WRAP_AT_EOL_OUTPUT", ENABLE_WRAP_AT_EOL_OUTPUT, // 0x0002 63 | "ENABLE_VIRTUAL_TERMINAL_PROCESSING", 0x0004/*ENABLE_VIRTUAL_TERMINAL_PROCESSING*/, // 0x0004 64 | "DISABLE_NEWLINE_AUTO_RETURN", 0x0008/*DISABLE_NEWLINE_AUTO_RETURN*/, // 0x0008 65 | "ENABLE_LVB_GRID_WORLDWIDE", 0x0010/*ENABLE_LVB_GRID_WORLDWIDE*/, //0x0010 66 | }; 67 | 68 | int main(int argc, char *argv[]) { 69 | std::vector args; 70 | for (size_t i = 1; i < argc; ++i) { 71 | args.push_back(argv[i]); 72 | } 73 | 74 | if (args.empty() || args.size() == 1 && args[0] == "info") { 75 | DWORD mode = getConsoleMode(); 76 | printf("mode: 0x%lx\n", mode); 77 | for (const auto &flag : kOutputFlags) { 78 | printf("%-34s 0x%04lx %s\n", flag.name, flag.value, flag.value & mode ? "ON" : "off"); 79 | mode &= ~flag.value; 80 | } 81 | for (int i = 0; i < 32; ++i) { 82 | if (mode & (1u << i)) { 83 | printf("Unrecognized flag: %04x\n", (1u << i)); 84 | } 85 | } 86 | return 0; 87 | } 88 | 89 | const auto verb = args[0]; 90 | 91 | if (verb == "set") { 92 | if (args.size() == 2) { 93 | const DWORD newMode = parseInt(args[1]); 94 | setConsoleMode(newMode); 95 | } else if (args.size() == 3) { 96 | const DWORD mode = parseInt(args[1]); 97 | const DWORD mask = parseInt(args[2]); 98 | const int newMode = (getConsoleMode() & ~mask) | (mode & mask); 99 | setConsoleMode(newMode); 100 | } else { 101 | usage(); 102 | } 103 | } else if (verb == "get") { 104 | if (args.size() != 1) { 105 | usage(); 106 | } 107 | printf("0x%lx\n", getConsoleMode()); 108 | } else { 109 | usage(); 110 | } 111 | 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /misc/DebugClient.py: -------------------------------------------------------------------------------- 1 | #!python 2 | # Run with native CPython. Needs pywin32 extensions. 3 | 4 | # Copyright (c) 2011-2012 Ryan Prichard 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to 8 | # deal in the Software without restriction, including without limitation the 9 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | # sell copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | # IN THE SOFTWARE. 23 | 24 | import winerror 25 | import win32pipe 26 | import win32file 27 | import win32api 28 | import sys 29 | import pywintypes 30 | import time 31 | 32 | if len(sys.argv) != 2: 33 | print("Usage: %s message" % sys.argv[0]) 34 | sys.exit(1) 35 | 36 | message = "[%05.3f %s]: %s" % (time.time() % 100000, sys.argv[0], sys.argv[1]) 37 | 38 | win32pipe.CallNamedPipe( 39 | "\\\\.\\pipe\\DebugServer", 40 | message.encode(), 41 | 16, 42 | win32pipe.NMPWAIT_WAIT_FOREVER) 43 | -------------------------------------------------------------------------------- /misc/DebugServer.py: -------------------------------------------------------------------------------- 1 | #!python 2 | # 3 | # Run with native CPython. Needs pywin32 extensions. 4 | 5 | # Copyright (c) 2011-2012 Ryan Prichard 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to 9 | # deal in the Software without restriction, including without limitation the 10 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | # sell copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | # IN THE SOFTWARE. 24 | 25 | import win32pipe 26 | import win32api 27 | import win32file 28 | import time 29 | import threading 30 | import sys 31 | 32 | # A message may not be larger than this size. 33 | MSG_SIZE=4096 34 | 35 | serverPipe = win32pipe.CreateNamedPipe( 36 | "\\\\.\\pipe\\DebugServer", 37 | win32pipe.PIPE_ACCESS_DUPLEX, 38 | win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE, 39 | win32pipe.PIPE_UNLIMITED_INSTANCES, 40 | MSG_SIZE, 41 | MSG_SIZE, 42 | 10 * 1000, 43 | None) 44 | while True: 45 | win32pipe.ConnectNamedPipe(serverPipe, None) 46 | (ret, data) = win32file.ReadFile(serverPipe, MSG_SIZE) 47 | print(data.decode()) 48 | sys.stdout.flush() 49 | 50 | # The client uses CallNamedPipe to send its message. CallNamedPipe waits 51 | # for a reply message. If I send a reply, however, using WriteFile, then 52 | # sometimes WriteFile fails with: 53 | # pywintypes.error: (232, 'WriteFile', 'The pipe is being closed.') 54 | # I can't figure out how to write a strictly correct pipe server, but if 55 | # I comment out the WriteFile line, then everything seems to work. I 56 | # think the DisconnectNamedPipe call aborts the client's CallNamedPipe 57 | # call normally. 58 | 59 | try: 60 | win32file.WriteFile(serverPipe, b'OK') 61 | except: 62 | pass 63 | win32pipe.DisconnectNamedPipe(serverPipe) 64 | -------------------------------------------------------------------------------- /misc/DumpLines.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | 4 | for i in range(1, int(sys.argv[1]) + 1): 5 | print i, "X" * 78 6 | -------------------------------------------------------------------------------- /misc/EnableExtendedFlags.txt: -------------------------------------------------------------------------------- 1 | Note regarding ENABLE_EXTENDED_FLAGS (2016-05-30) 2 | 3 | There is a complicated interaction between the ENABLE_EXTENDED_FLAGS flag 4 | and the ENABLE_QUICK_EDIT_MODE and ENABLE_INSERT_MODE flags (presumably for 5 | backwards compatibility?). I studied the behavior on Windows 7 and Windows 6 | 10, with both the old and new consoles, and I didn't see any differences 7 | between versions. Here's what I seemed to observe: 8 | 9 | - The console has three flags internally: 10 | - QuickEdit 11 | - InsertMode 12 | - ExtendedFlags 13 | 14 | - SetConsoleMode psuedocode: 15 | void SetConsoleMode(..., DWORD mode) { 16 | ExtendedFlags = (mode & (ENABLE_EXTENDED_FLAGS 17 | | ENABLE_QUICK_EDIT_MODE 18 | | ENABLE_INSERT_MODE )) != 0; 19 | if (ExtendedFlags) { 20 | QuickEdit = (mode & ENABLE_QUICK_EDIT_MODE) != 0; 21 | InsertMode = (mode & ENABLE_INSERT_MODE) != 0; 22 | } 23 | } 24 | 25 | - Setting QuickEdit or InsertMode from the properties dialog GUI does not 26 | affect the ExtendedFlags setting -- it simply toggles the one flag. 27 | 28 | - GetConsoleMode psuedocode: 29 | GetConsoleMode(..., DWORD *result) { 30 | if (ExtendedFlags) { 31 | *result |= ENABLE_EXTENDED_FLAGS; 32 | if (QuickEdit) { *result |= ENABLE_QUICK_EDIT_MODE; } 33 | if (InsertMode) { *result |= ENABLE_INSERT_MODE; } 34 | } 35 | } 36 | 37 | Effectively, the ExtendedFlags flags controls whether the other two flags 38 | are visible/controlled by the user application. If they aren't visible, 39 | though, there is no way for the user application to make them visible, 40 | except by overwriting their values! Calling SetConsoleMode with just 41 | ENABLE_EXTENDED_FLAGS would clear the extended flags we want to read. 42 | 43 | Consequently, if a program temporarily alters the QuickEdit flag (e.g. to 44 | enable mouse input), it cannot restore the original values of the QuickEdit 45 | and InsertMode flags, UNLESS every other console program cooperates by 46 | keeping the ExtendedFlags flag set. 47 | -------------------------------------------------------------------------------- /misc/Font-Report-June2016/MinimumWindowWidths.txt: -------------------------------------------------------------------------------- 1 | The narrowest allowed console window, in pixels, on a conventional (~96dpi) 2 | monitor: 3 | 4 | (mode con: cols=40 lines=40) && SetFont.exe -face "Lucida Console" -h 1 && (ping -n 4 127.0.0.1 > NUL) && cls && GetConsolePos.exe && SetFont.exe -face "Lucida Console" -h 12 5 | 6 | (mode con: cols=40 lines=40) && SetFont.exe -face "Lucida Console" -h 16 && (ping -n 4 127.0.0.1 > NUL) && cls && GetConsolePos.exe && SetFont.exe -face "Lucida Console" -h 12 7 | 8 | sz1:px sz1:col sz16:px sz16:col 9 | Vista: 124 104 137 10 10 | Windows 7: 132 112 147 11 11 | Windows 8: 140 120 147 11 12 | Windows 8.1: 140 120 147 11 13 | Windows 10 OLD: 136 116 147 11 14 | Windows 10 NEW: 136 103 136 10 15 | 16 | I used build 14342 to test Windows 10. 17 | -------------------------------------------------------------------------------- /misc/Font-Report-June2016/Results.txt: -------------------------------------------------------------------------------- 1 | As before, avoid odd sizes in favor of even sizes. 2 | 3 | It's curious that the Japanese font is handled so poorly, especially with 4 | Windows 8 and later. 5 | -------------------------------------------------------------------------------- /misc/FontSurvey.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "TestUtil.cc" 10 | 11 | #define COUNT_OF(array) (sizeof(array) / sizeof((array)[0])) 12 | 13 | // See https://en.wikipedia.org/wiki/List_of_CJK_fonts 14 | const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // Japanese 15 | const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // Simplified Chinese 16 | const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // Traditional Chinese 17 | const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // Korean 18 | 19 | std::vector condense(const std::vector &buf) { 20 | std::vector ret; 21 | size_t i = 0; 22 | while (i < buf.size()) { 23 | if (buf[i].Char.UnicodeChar == L' ' && 24 | ((buf[i].Attributes & 0x300) == 0)) { 25 | // end of line 26 | break; 27 | } else if (i + 1 < buf.size() && 28 | ((buf[i].Attributes & 0x300) == 0x100) && 29 | ((buf[i + 1].Attributes & 0x300) == 0x200) && 30 | buf[i].Char.UnicodeChar != L' ' && 31 | buf[i].Char.UnicodeChar == buf[i + 1].Char.UnicodeChar) { 32 | // double-width 33 | ret.push_back(true); 34 | i += 2; 35 | } else if ((buf[i].Attributes & 0x300) == 0) { 36 | // single-width 37 | ret.push_back(false); 38 | i++; 39 | } else { 40 | ASSERT(false && "unexpected output"); 41 | } 42 | } 43 | return ret; 44 | } 45 | 46 | int main(int argc, char *argv[]) { 47 | if (argc != 2) { 48 | printf("Usage: %s \"arguments for SetFont.exe\"\n", argv[0]); 49 | return 1; 50 | } 51 | 52 | const char *setFontArgs = argv[1]; 53 | 54 | const wchar_t testLine[] = { 0xA2, 0xA3, 0x2014, 0x3044, 0x30FC, 0x4000, 0 }; 55 | const HANDLE conout = openConout(); 56 | 57 | char setFontCmd[1024]; 58 | for (int h = 1; h <= 100; ++h) { 59 | sprintf(setFontCmd, ".\\SetFont.exe %s -h %d && cls", setFontArgs, h); 60 | system(setFontCmd); 61 | 62 | CONSOLE_FONT_INFOEX infoex = {}; 63 | infoex.cbSize = sizeof(infoex); 64 | BOOL success = GetCurrentConsoleFontEx(conout, FALSE, &infoex); 65 | ASSERT(success && "GetCurrentConsoleFontEx failed"); 66 | 67 | DWORD actual = 0; 68 | success = WriteConsoleW(conout, testLine, wcslen(testLine), &actual, nullptr); 69 | ASSERT(success && actual == wcslen(testLine)); 70 | 71 | std::vector readBuf(14); 72 | const SMALL_RECT readRegion = {0, 0, static_cast(readBuf.size() - 1), 0}; 73 | SMALL_RECT readRegion2 = readRegion; 74 | success = ReadConsoleOutputW( 75 | conout, readBuf.data(), 76 | {static_cast(readBuf.size()), 1}, 77 | {0, 0}, 78 | &readRegion2); 79 | ASSERT(success && !memcmp(&readRegion, &readRegion2, sizeof(readRegion))); 80 | 81 | const auto widths = condense(readBuf); 82 | std::string widthsStr; 83 | for (bool width : widths) { 84 | widthsStr.append(width ? "F" : "H"); 85 | } 86 | char size[16]; 87 | sprintf(size, "%d,%d", infoex.dwFontSize.X, infoex.dwFontSize.Y); 88 | const char *status = ""; 89 | if (widthsStr == "HHFFFF") { 90 | status = "GOOD"; 91 | } else if (widthsStr == "HHHFFF") { 92 | status = "OK"; 93 | } else { 94 | status = "BAD"; 95 | } 96 | trace("Size %3d: %-7s %-4s (%s)", h, size, status, widthsStr.c_str()); 97 | } 98 | sprintf(setFontCmd, ".\\SetFont.exe %s -h 14", setFontArgs); 99 | system(setFontCmd); 100 | } 101 | -------------------------------------------------------------------------------- /misc/FormatChar.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static inline void formatChar(char *str, char ch) 6 | { 7 | // Print some common control codes. 8 | switch (ch) { 9 | case '\r': strcpy(str, "CR "); break; 10 | case '\n': strcpy(str, "LF "); break; 11 | case ' ': strcpy(str, "SP "); break; 12 | case 27: strcpy(str, "^[ "); break; 13 | case 3: strcpy(str, "^C "); break; 14 | default: 15 | if (isgraph(ch)) 16 | sprintf(str, "%c ", ch); 17 | else 18 | sprintf(str, "%02x ", ch); 19 | break; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /misc/FreezePerfTest.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "TestUtil.cc" 4 | 5 | const int SC_CONSOLE_MARK = 0xFFF2; 6 | const int SC_CONSOLE_SELECT_ALL = 0xFFF5; 7 | 8 | int main(int argc, char *argv[0]) { 9 | 10 | if (argc != 2) { 11 | printf("Usage: %s (mark|selectall|read)\n", argv[0]); 12 | return 1; 13 | } 14 | 15 | enum class Test { Mark, SelectAll, Read } test; 16 | if (!strcmp(argv[1], "mark")) { 17 | test = Test::Mark; 18 | } else if (!strcmp(argv[1], "selectall")) { 19 | test = Test::SelectAll; 20 | } else if (!strcmp(argv[1], "read")) { 21 | test = Test::Read; 22 | } else { 23 | printf("Invalid test: %s\n", argv[1]); 24 | return 1; 25 | } 26 | 27 | HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); 28 | TimeMeasurement tm; 29 | HWND hwnd = GetConsoleWindow(); 30 | 31 | setWindowPos(0, 0, 1, 1); 32 | setBufferSize(100, 3000); 33 | system("cls"); 34 | setWindowPos(0, 2975, 100, 25); 35 | setCursorPos(0, 2999); 36 | 37 | ShowWindow(hwnd, SW_HIDE); 38 | 39 | for (int i = 0; i < 1000; ++i) { 40 | // CONSOLE_SCREEN_BUFFER_INFO info = {}; 41 | // GetConsoleScreenBufferInfo(conout, &info); 42 | 43 | if (test == Test::Mark) { 44 | SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0); 45 | SendMessage(hwnd, WM_CHAR, 27, 0x00010001); 46 | } else if (test == Test::SelectAll) { 47 | SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0); 48 | SendMessage(hwnd, WM_CHAR, 27, 0x00010001); 49 | } else if (test == Test::Read) { 50 | static CHAR_INFO buffer[100 * 3000]; 51 | const SMALL_RECT readRegion = {0, 0, 99, 2999}; 52 | SMALL_RECT tmp = readRegion; 53 | BOOL ret = ReadConsoleOutput(conout, buffer, {100, 3000}, {0, 0}, &tmp); 54 | ASSERT(ret && !memcmp(&tmp, &readRegion, sizeof(tmp))); 55 | } 56 | } 57 | 58 | ShowWindow(hwnd, SW_SHOW); 59 | 60 | printf("elapsed: %f\n", tm.elapsed()); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /misc/GetCh.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | printf("\nPress any keys -- Ctrl-D exits\n\n"); 7 | 8 | while (true) { 9 | const int ch = getch(); 10 | printf("0x%x", ch); 11 | if (isgraph(ch)) { 12 | printf(" '%c'", ch); 13 | } 14 | printf("\n"); 15 | if (ch == 0x4) { // Ctrl-D 16 | break; 17 | } 18 | } 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /misc/GetConsolePos.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "TestUtil.cc" 6 | 7 | int main() { 8 | const HANDLE conout = openConout(); 9 | 10 | CONSOLE_SCREEN_BUFFER_INFO info = {}; 11 | BOOL ret = GetConsoleScreenBufferInfo(conout, &info); 12 | ASSERT(ret && "GetConsoleScreenBufferInfo failed"); 13 | 14 | trace("cursor=%d,%d", info.dwCursorPosition.X, info.dwCursorPosition.Y); 15 | printf("cursor=%d,%d\n", info.dwCursorPosition.X, info.dwCursorPosition.Y); 16 | 17 | trace("srWindow={L=%d,T=%d,R=%d,B=%d}", info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom); 18 | printf("srWindow={L=%d,T=%d,R=%d,B=%d}\n", info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom); 19 | 20 | trace("dwSize=%d,%d", info.dwSize.X, info.dwSize.Y); 21 | printf("dwSize=%d,%d\n", info.dwSize.X, info.dwSize.Y); 22 | 23 | const HWND hwnd = GetConsoleWindow(); 24 | if (hwnd != NULL) { 25 | RECT r = {}; 26 | if (GetWindowRect(hwnd, &r)) { 27 | const int w = r.right - r.left; 28 | const int h = r.bottom - r.top; 29 | trace("hwnd: pos=(%d,%d) size=(%d,%d)", r.left, r.top, w, h); 30 | printf("hwnd: pos=(%d,%d) size=(%d,%d)\n", r.left, r.top, w, h); 31 | } else { 32 | trace("GetWindowRect failed"); 33 | printf("GetWindowRect failed\n"); 34 | } 35 | } else { 36 | trace("GetConsoleWindow returned NULL"); 37 | printf("GetConsoleWindow returned NULL\n"); 38 | } 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /misc/IdentifyConsoleWindow.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # Usage: powershell \IdentifyConsoleWindow.ps1 3 | # 4 | # This script determines whether the process has a console attached, whether 5 | # that console has a non-NULL window (e.g. HWND), and whether the window is on 6 | # the current window station. 7 | # 8 | 9 | $signature = @' 10 | [DllImport("kernel32.dll", SetLastError=true)] 11 | public static extern IntPtr GetConsoleWindow(); 12 | 13 | [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)] 14 | public static extern bool SetConsoleTitle(String title); 15 | 16 | [DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)] 17 | public static extern int GetWindowText(IntPtr hWnd, 18 | System.Text.StringBuilder lpString, 19 | int nMaxCount); 20 | '@ 21 | 22 | $WinAPI = Add-Type -MemberDefinition $signature ` 23 | -Name WinAPI -Namespace IdentifyConsoleWindow -PassThru 24 | 25 | if (!$WinAPI::SetConsoleTitle("ConsoleWindowScript")) { 26 | echo "error: could not change console title -- is a console attached?" 27 | exit 1 28 | } else { 29 | echo "note: successfully set console title to ""ConsoleWindowScript""." 30 | } 31 | 32 | $hwnd = $WinAPI::GetConsoleWindow() 33 | if ($hwnd -eq 0) { 34 | echo "note: GetConsoleWindow returned NULL." 35 | } else { 36 | echo "note: GetConsoleWindow returned 0x$($hwnd.ToString("X"))." 37 | $sb = New-Object System.Text.StringBuilder -ArgumentList 4096 38 | if ($WinAPI::GetWindowText($hwnd, $sb, $sb.Capacity)) { 39 | $title = $sb.ToString() 40 | echo "note: GetWindowText returned ""${title}""." 41 | if ($title -eq "ConsoleWindowScript") { 42 | echo "success!" 43 | } else { 44 | echo "error: expected to see ""ConsoleWindowScript""." 45 | echo " (Perhaps the console window is on a different window station?)" 46 | } 47 | } else { 48 | echo "error: GetWindowText could not read the window title." 49 | echo " (Perhaps the console window is on a different window station?)" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /misc/IsNewConsole.cc: -------------------------------------------------------------------------------- 1 | // Determines whether this is a new console by testing whether MARK moves the 2 | // cursor. 3 | // 4 | // WARNING: This test program may behave erratically if run under winpty. 5 | // 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include "TestUtil.cc" 13 | 14 | const int SC_CONSOLE_MARK = 0xFFF2; 15 | const int SC_CONSOLE_SELECT_ALL = 0xFFF5; 16 | 17 | static COORD getWindowPos(HANDLE conout) { 18 | CONSOLE_SCREEN_BUFFER_INFO info = {}; 19 | BOOL ret = GetConsoleScreenBufferInfo(conout, &info); 20 | ASSERT(ret && "GetConsoleScreenBufferInfo failed"); 21 | return { info.srWindow.Left, info.srWindow.Top }; 22 | } 23 | 24 | static COORD getWindowSize(HANDLE conout) { 25 | CONSOLE_SCREEN_BUFFER_INFO info = {}; 26 | BOOL ret = GetConsoleScreenBufferInfo(conout, &info); 27 | ASSERT(ret && "GetConsoleScreenBufferInfo failed"); 28 | return { 29 | static_cast(info.srWindow.Right - info.srWindow.Left + 1), 30 | static_cast(info.srWindow.Bottom - info.srWindow.Top + 1) 31 | }; 32 | } 33 | 34 | static COORD getCursorPos(HANDLE conout) { 35 | CONSOLE_SCREEN_BUFFER_INFO info = {}; 36 | BOOL ret = GetConsoleScreenBufferInfo(conout, &info); 37 | ASSERT(ret && "GetConsoleScreenBufferInfo failed"); 38 | return info.dwCursorPosition; 39 | } 40 | 41 | static void setCursorPos(HANDLE conout, COORD pos) { 42 | BOOL ret = SetConsoleCursorPosition(conout, pos); 43 | ASSERT(ret && "SetConsoleCursorPosition failed"); 44 | } 45 | 46 | int main() { 47 | const HANDLE conout = openConout(); 48 | const HWND hwnd = GetConsoleWindow(); 49 | ASSERT(hwnd != NULL && "GetConsoleWindow() returned NULL"); 50 | 51 | // With the legacy console, the Mark command moves the the cursor to the 52 | // top-left cell of the visible console window. Determine whether this 53 | // is the new console by seeing if the cursor moves. 54 | 55 | const auto windowSize = getWindowSize(conout); 56 | if (windowSize.X <= 1) { 57 | printf("Error: console window must be at least 2 columns wide\n"); 58 | trace("Error: console window must be at least 2 columns wide"); 59 | return 1; 60 | } 61 | 62 | bool cursorMoved = false; 63 | const auto initialPos = getCursorPos(conout); 64 | 65 | const auto windowPos = getWindowPos(conout); 66 | setCursorPos(conout, { static_cast(windowPos.X + 1), windowPos.Y }); 67 | 68 | { 69 | const auto posA = getCursorPos(conout); 70 | SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0); 71 | const auto posB = getCursorPos(conout); 72 | cursorMoved = memcmp(&posA, &posB, sizeof(posA)) != 0; 73 | SendMessage(hwnd, WM_CHAR, 27, 0x00010001); // Send ESCAPE 74 | } 75 | 76 | setCursorPos(conout, initialPos); 77 | 78 | if (cursorMoved) { 79 | printf("Legacy console (i.e. MARK moved cursor)\n"); 80 | trace("Legacy console (i.e. MARK moved cursor)"); 81 | } else { 82 | printf("Windows 10 new console (i.e MARK did not move cursor)\n"); 83 | trace("Windows 10 new console (i.e MARK did not move cursor)"); 84 | } 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /misc/MoveConsoleWindow.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "TestUtil.cc" 4 | 5 | int main(int argc, char *argv[]) { 6 | if (argc != 3 && argc != 5) { 7 | printf("Usage: %s x y\n", argv[0]); 8 | printf("Usage: %s x y width height\n", argv[0]); 9 | return 1; 10 | } 11 | 12 | HWND hwnd = GetConsoleWindow(); 13 | 14 | const int x = atoi(argv[1]); 15 | const int y = atoi(argv[2]); 16 | 17 | int w = 0, h = 0; 18 | if (argc == 3) { 19 | RECT r = {}; 20 | BOOL ret = GetWindowRect(hwnd, &r); 21 | ASSERT(ret && "GetWindowRect failed on console window"); 22 | w = r.right - r.left; 23 | h = r.bottom - r.top; 24 | } else { 25 | w = atoi(argv[3]); 26 | h = atoi(argv[4]); 27 | } 28 | 29 | BOOL ret = MoveWindow(hwnd, x, y, w, h, TRUE); 30 | trace("MoveWindow: ret=%d", ret); 31 | printf("MoveWindow: ret=%d\n", ret); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /misc/OSVersion.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | int main() { 10 | setlocale(LC_ALL, ""); 11 | 12 | OSVERSIONINFOEXW info = {0}; 13 | info.dwOSVersionInfoSize = sizeof(info); 14 | assert(GetVersionExW((OSVERSIONINFOW*)&info)); 15 | 16 | printf("dwMajorVersion = %d\n", (int)info.dwMajorVersion); 17 | printf("dwMinorVersion = %d\n", (int)info.dwMinorVersion); 18 | printf("dwBuildNumber = %d\n", (int)info.dwBuildNumber); 19 | printf("dwPlatformId = %d\n", (int)info.dwPlatformId); 20 | printf("szCSDVersion = %ls\n", info.szCSDVersion); 21 | printf("wServicePackMajor = %d\n", info.wServicePackMajor); 22 | printf("wServicePackMinor = %d\n", info.wServicePackMinor); 23 | printf("wSuiteMask = 0x%x\n", (unsigned int)info.wSuiteMask); 24 | printf("wProductType = 0x%x\n", (unsigned int)info.wProductType); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /misc/ScreenBufferFreezeInactive.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Verify that console selection blocks writes to an inactive console screen 3 | // buffer. Writes TEST PASSED or TEST FAILED to the popup console window. 4 | // 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "TestUtil.cc" 12 | 13 | const int SC_CONSOLE_MARK = 0xFFF2; 14 | const int SC_CONSOLE_SELECT_ALL = 0xFFF5; 15 | 16 | bool g_useMark = false; 17 | 18 | CALLBACK DWORD pausingThread(LPVOID dummy) 19 | { 20 | HWND hwnd = GetConsoleWindow(); 21 | trace("Sending selection to freeze"); 22 | SendMessage(hwnd, WM_SYSCOMMAND, 23 | g_useMark ? SC_CONSOLE_MARK : 24 | SC_CONSOLE_SELECT_ALL, 25 | 0); 26 | Sleep(1000); 27 | trace("Sending escape WM_CHAR to unfreeze"); 28 | SendMessage(hwnd, WM_CHAR, 27, 0x00010001); 29 | Sleep(1000); 30 | } 31 | 32 | static HANDLE createBuffer() { 33 | HANDLE buf = CreateConsoleScreenBuffer( 34 | GENERIC_READ | GENERIC_WRITE, 35 | FILE_SHARE_READ | FILE_SHARE_WRITE, 36 | NULL, 37 | CONSOLE_TEXTMODE_BUFFER, 38 | NULL); 39 | ASSERT(buf != INVALID_HANDLE_VALUE); 40 | return buf; 41 | } 42 | 43 | static void runTest(bool useMark, bool createEarly) { 44 | trace("======================================="); 45 | trace("useMark=%d createEarly=%d", useMark, createEarly); 46 | g_useMark = useMark; 47 | HANDLE buf = INVALID_HANDLE_VALUE; 48 | 49 | if (createEarly) { 50 | buf = createBuffer(); 51 | } 52 | 53 | CreateThread(NULL, 0, 54 | pausingThread, NULL, 55 | 0, NULL); 56 | Sleep(500); 57 | 58 | if (!createEarly) { 59 | trace("Creating buffer"); 60 | TimeMeasurement tm1; 61 | buf = createBuffer(); 62 | const double elapsed1 = tm1.elapsed(); 63 | if (elapsed1 >= 0.250) { 64 | printf("!!! TEST FAILED !!!\n"); 65 | Sleep(2000); 66 | return; 67 | } 68 | } 69 | 70 | trace("Writing to aux buffer"); 71 | TimeMeasurement tm2; 72 | DWORD actual = 0; 73 | BOOL ret = WriteConsoleW(buf, L"HI", 2, &actual, NULL); 74 | const double elapsed2 = tm2.elapsed(); 75 | trace("Writing to aux buffer: finished: ret=%d actual=%d (elapsed=%1.3f)", ret, actual, elapsed2); 76 | if (elapsed2 < 0.250) { 77 | printf("!!! TEST FAILED !!!\n"); 78 | } else { 79 | printf("TEST PASSED\n"); 80 | } 81 | Sleep(2000); 82 | } 83 | 84 | int main(int argc, char **argv) { 85 | if (argc == 1) { 86 | startChildProcess(L"child"); 87 | return 0; 88 | } 89 | 90 | std::string arg = argv[1]; 91 | if (arg == "child") { 92 | for (int useMark = 0; useMark <= 1; useMark++) { 93 | for (int createEarly = 0; createEarly <= 1; createEarly++) { 94 | runTest(useMark, createEarly); 95 | } 96 | } 97 | printf("done...\n"); 98 | Sleep(1000); 99 | } 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /misc/SelectAllTest.cc: -------------------------------------------------------------------------------- 1 | #define _WIN32_WINNT 0x0501 2 | #include 3 | #include 4 | 5 | #include "../src/shared/DebugClient.cc" 6 | 7 | const int SC_CONSOLE_MARK = 0xFFF2; 8 | const int SC_CONSOLE_SELECT_ALL = 0xFFF5; 9 | 10 | CALLBACK DWORD pausingThread(LPVOID dummy) 11 | { 12 | HWND hwnd = GetConsoleWindow(); 13 | while (true) { 14 | SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0); 15 | Sleep(1000); 16 | SendMessage(hwnd, WM_CHAR, 27, 0x00010001); 17 | Sleep(1000); 18 | } 19 | } 20 | 21 | int main() 22 | { 23 | HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); 24 | CONSOLE_SCREEN_BUFFER_INFO info; 25 | 26 | GetConsoleScreenBufferInfo(out, &info); 27 | COORD initial = info.dwCursorPosition; 28 | 29 | CreateThread(NULL, 0, 30 | pausingThread, NULL, 31 | 0, NULL); 32 | 33 | for (int i = 0; i < 30; ++i) { 34 | Sleep(100); 35 | GetConsoleScreenBufferInfo(out, &info); 36 | if (memcmp(&info.dwCursorPosition, &initial, sizeof(COORD)) != 0) { 37 | trace("cursor moved to [%d,%d]", 38 | info.dwCursorPosition.X, 39 | info.dwCursorPosition.Y); 40 | } else { 41 | trace("cursor in expected position"); 42 | } 43 | } 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /misc/SetBufInfo.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "TestUtil.cc" 8 | 9 | static void usage() { 10 | printf("usage: SetBufInfo [-set] [-buf W H] [-win W H] [-pos X Y]\n"); 11 | } 12 | 13 | int main(int argc, char *argv[]) { 14 | const HANDLE conout = CreateFileW(L"CONOUT$", 15 | GENERIC_READ | GENERIC_WRITE, 16 | FILE_SHARE_READ | FILE_SHARE_WRITE, 17 | NULL, OPEN_EXISTING, 0, NULL); 18 | ASSERT(conout != INVALID_HANDLE_VALUE); 19 | 20 | bool change = false; 21 | BOOL success; 22 | CONSOLE_SCREEN_BUFFER_INFOEX info = {}; 23 | info.cbSize = sizeof(info); 24 | 25 | success = GetConsoleScreenBufferInfoEx(conout, &info); 26 | ASSERT(success && "GetConsoleScreenBufferInfoEx failed"); 27 | 28 | for (int i = 1; i < argc; ) { 29 | std::string arg = argv[i]; 30 | if (arg == "-buf" && (i + 2) < argc) { 31 | info.dwSize.X = atoi(argv[i + 1]); 32 | info.dwSize.Y = atoi(argv[i + 2]); 33 | i += 3; 34 | change = true; 35 | } else if (arg == "-pos" && (i + 2) < argc) { 36 | int dx = info.srWindow.Right - info.srWindow.Left; 37 | int dy = info.srWindow.Bottom - info.srWindow.Top; 38 | info.srWindow.Left = atoi(argv[i + 1]); 39 | info.srWindow.Top = atoi(argv[i + 2]); 40 | i += 3; 41 | info.srWindow.Right = info.srWindow.Left + dx; 42 | info.srWindow.Bottom = info.srWindow.Top + dy; 43 | change = true; 44 | } else if (arg == "-win" && (i + 2) < argc) { 45 | info.srWindow.Right = info.srWindow.Left + atoi(argv[i + 1]) - 1; 46 | info.srWindow.Bottom = info.srWindow.Top + atoi(argv[i + 2]) - 1; 47 | i += 3; 48 | change = true; 49 | } else if (arg == "-set") { 50 | change = true; 51 | ++i; 52 | } else if (arg == "--help" || arg == "-help") { 53 | usage(); 54 | exit(0); 55 | } else { 56 | fprintf(stderr, "error: unrecognized argument: %s\n", arg.c_str()); 57 | usage(); 58 | exit(1); 59 | } 60 | } 61 | 62 | if (change) { 63 | success = SetConsoleScreenBufferInfoEx(conout, &info); 64 | if (success) { 65 | printf("success\n"); 66 | } else { 67 | printf("SetConsoleScreenBufferInfoEx call failed\n"); 68 | } 69 | success = GetConsoleScreenBufferInfoEx(conout, &info); 70 | ASSERT(success && "GetConsoleScreenBufferInfoEx failed"); 71 | } 72 | 73 | auto dump = [](const char *fmt, ...) { 74 | char msg[256]; 75 | va_list ap; 76 | va_start(ap, fmt); 77 | vsprintf(msg, fmt, ap); 78 | va_end(ap); 79 | trace("%s", msg); 80 | printf("%s\n", msg); 81 | }; 82 | 83 | dump("buffer-size: %d x %d", info.dwSize.X, info.dwSize.Y); 84 | dump("window-size: %d x %d", 85 | info.srWindow.Right - info.srWindow.Left + 1, 86 | info.srWindow.Bottom - info.srWindow.Top + 1); 87 | dump("window-pos: %d, %d", info.srWindow.Left, info.srWindow.Top); 88 | 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /misc/SetBufferSize.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "TestUtil.cc" 7 | 8 | int main(int argc, char *argv[]) { 9 | if (argc != 3) { 10 | printf("Usage: %s x y width height\n", argv[0]); 11 | return 1; 12 | } 13 | 14 | const HANDLE conout = CreateFileW(L"CONOUT$", 15 | GENERIC_READ | GENERIC_WRITE, 16 | FILE_SHARE_READ | FILE_SHARE_WRITE, 17 | NULL, OPEN_EXISTING, 0, NULL); 18 | ASSERT(conout != INVALID_HANDLE_VALUE); 19 | 20 | COORD size = { 21 | (short)atoi(argv[1]), 22 | (short)atoi(argv[2]), 23 | }; 24 | 25 | BOOL ret = SetConsoleScreenBufferSize(conout, size); 26 | const unsigned lastError = GetLastError(); 27 | const char *const retStr = ret ? "OK" : "failed"; 28 | trace("SetConsoleScreenBufferSize ret: %s (LastError=0x%x)", retStr, lastError); 29 | printf("SetConsoleScreenBufferSize ret: %s (LastError=0x%x)\n", retStr, lastError); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /misc/SetCursorPos.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "TestUtil.cc" 4 | 5 | int main(int argc, char *argv[]) { 6 | int col = atoi(argv[1]); 7 | int row = atoi(argv[2]); 8 | setCursorPos(col, row); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /misc/SetWindowRect.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "TestUtil.cc" 7 | 8 | int main(int argc, char *argv[]) { 9 | if (argc != 5) { 10 | printf("Usage: %s x y width height\n", argv[0]); 11 | return 1; 12 | } 13 | 14 | const HANDLE conout = CreateFileW(L"CONOUT$", 15 | GENERIC_READ | GENERIC_WRITE, 16 | FILE_SHARE_READ | FILE_SHARE_WRITE, 17 | NULL, OPEN_EXISTING, 0, NULL); 18 | ASSERT(conout != INVALID_HANDLE_VALUE); 19 | 20 | SMALL_RECT sr = { 21 | (short)atoi(argv[1]), 22 | (short)atoi(argv[2]), 23 | (short)(atoi(argv[1]) + atoi(argv[3]) - 1), 24 | (short)(atoi(argv[2]) + atoi(argv[4]) - 1), 25 | }; 26 | 27 | trace("Calling SetConsoleWindowInfo with {L=%d,T=%d,R=%d,B=%d}", 28 | sr.Left, sr.Top, sr.Right, sr.Bottom); 29 | BOOL ret = SetConsoleWindowInfo(conout, TRUE, &sr); 30 | const unsigned lastError = GetLastError(); 31 | const char *const retStr = ret ? "OK" : "failed"; 32 | trace("SetConsoleWindowInfo ret: %s (LastError=0x%x)", retStr, lastError); 33 | printf("SetConsoleWindowInfo ret: %s (LastError=0x%x)\n", retStr, lastError); 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /misc/ShowArgv.cc: -------------------------------------------------------------------------------- 1 | // This test program is useful for studying commandline<->argv conversion. 2 | 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv) 7 | { 8 | printf("cmdline = [%s]\n", GetCommandLine()); 9 | for (int i = 0; i < argc; ++i) 10 | printf("[%s]\n", argv[i]); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /misc/ShowConsoleInput.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | static int escCount = 0; 8 | 9 | HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); 10 | while (true) { 11 | DWORD count; 12 | INPUT_RECORD ir; 13 | if (!ReadConsoleInput(hStdin, &ir, 1, &count)) { 14 | printf("ReadConsoleInput failed\n"); 15 | return 1; 16 | } 17 | 18 | if (true) { 19 | DWORD mode; 20 | GetConsoleMode(hStdin, &mode); 21 | SetConsoleMode(hStdin, mode & ~ENABLE_PROCESSED_INPUT); 22 | } 23 | 24 | if (ir.EventType == KEY_EVENT) { 25 | const KEY_EVENT_RECORD &ker = ir.Event.KeyEvent; 26 | printf("%s", ker.bKeyDown ? "dn" : "up"); 27 | printf(" ch="); 28 | if (isprint(ker.uChar.AsciiChar)) 29 | printf("'%c'", ker.uChar.AsciiChar); 30 | printf("%d", ker.uChar.AsciiChar); 31 | printf(" vk=%#x", ker.wVirtualKeyCode); 32 | printf(" scan=%#x", ker.wVirtualScanCode); 33 | printf(" state=%#x", (int)ker.dwControlKeyState); 34 | printf(" repeat=%d", ker.wRepeatCount); 35 | printf("\n"); 36 | if (ker.uChar.AsciiChar == 27 && ++escCount == 6) 37 | break; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /misc/Spew.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | i = 0; 3 | while True: 4 | i += 1 5 | print(i) 6 | -------------------------------------------------------------------------------- /misc/UnicodeDoubleWidthTest.cc: -------------------------------------------------------------------------------- 1 | // Demonstrates how U+30FC is sometimes handled as a single-width character 2 | // when it should be handled as a double-width character. 3 | // 4 | // It only runs on computers where 932 is a valid code page. Set the system 5 | // local to "Japanese (Japan)" to ensure this. 6 | // 7 | // The problem seems to happen when U+30FC is printed in a console using the 8 | // Lucida Console font, and only when that font is at certain sizes. 9 | // 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "TestUtil.cc" 19 | 20 | #define COUNT_OF(x) (sizeof(x) / sizeof((x)[0])) 21 | 22 | static void setFont(const wchar_t *faceName, int pxSize) { 23 | CONSOLE_FONT_INFOEX infoex = {0}; 24 | infoex.cbSize = sizeof(infoex); 25 | infoex.dwFontSize.Y = pxSize; 26 | wcsncpy(infoex.FaceName, faceName, COUNT_OF(infoex.FaceName)); 27 | BOOL ret = SetCurrentConsoleFontEx( 28 | GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &infoex); 29 | assert(ret); 30 | } 31 | 32 | static bool performTest(const wchar_t testChar) { 33 | const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); 34 | 35 | SetConsoleTextAttribute(conout, 7); 36 | 37 | system("cls"); 38 | DWORD actual = 0; 39 | BOOL ret = WriteConsoleW(conout, &testChar, 1, &actual, NULL); 40 | assert(ret && actual == 1); 41 | 42 | CHAR_INFO verify[2]; 43 | COORD bufSize = {2, 1}; 44 | COORD bufCoord = {0, 0}; 45 | const SMALL_RECT readRegion = {0, 0, 1, 0}; 46 | SMALL_RECT actualRegion = readRegion; 47 | ret = ReadConsoleOutputW(conout, verify, bufSize, bufCoord, &actualRegion); 48 | assert(ret && !memcmp(&readRegion, &actualRegion, sizeof(readRegion))); 49 | assert(verify[0].Char.UnicodeChar == testChar); 50 | 51 | if (verify[1].Char.UnicodeChar == testChar) { 52 | // Typical double-width behavior with a TrueType font. Pass. 53 | assert(verify[0].Attributes == 0x107); 54 | assert(verify[1].Attributes == 0x207); 55 | return true; 56 | } else if (verify[1].Char.UnicodeChar == 0) { 57 | // Typical double-width behavior with a Raster Font. Pass. 58 | assert(verify[0].Attributes == 7); 59 | assert(verify[1].Attributes == 0); 60 | return true; 61 | } else if (verify[1].Char.UnicodeChar == L' ') { 62 | // Single-width behavior. Fail. 63 | assert(verify[0].Attributes == 7); 64 | assert(verify[1].Attributes == 7); 65 | return false; 66 | } else { 67 | // Unexpected output. 68 | assert(false); 69 | } 70 | } 71 | 72 | int main(int argc, char *argv[]) { 73 | setlocale(LC_ALL, ""); 74 | if (argc == 1) { 75 | startChildProcess(L"CHILD"); 76 | return 0; 77 | } 78 | 79 | assert(SetConsoleCP(932)); 80 | assert(SetConsoleOutputCP(932)); 81 | 82 | const wchar_t testChar = 0x30FC; 83 | const wchar_t *const faceNames[] = { 84 | L"Lucida Console", 85 | L"Consolas", 86 | L"MS ゴシック", 87 | }; 88 | 89 | trace("Test started"); 90 | 91 | for (auto faceName : faceNames) { 92 | for (int px = 1; px <= 50; ++px) { 93 | setFont(faceName, px); 94 | if (!performTest(testChar)) { 95 | trace("FAILURE: %s %dpx", narrowString(faceName).c_str(), px); 96 | } 97 | } 98 | } 99 | 100 | trace("Test complete"); 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /misc/UnixEcho.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Unix test code that puts the terminal into raw mode, then echos typed 3 | * characters to stdout. Derived from sample code in the Stevens book, posted 4 | * online at http://www.lafn.org/~dave/linux/terminalIO.html. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "FormatChar.h" 12 | 13 | static struct termios save_termios; 14 | static int term_saved; 15 | 16 | /* RAW! mode */ 17 | int tty_raw(int fd) 18 | { 19 | struct termios buf; 20 | 21 | if (tcgetattr(fd, &save_termios) < 0) /* get the original state */ 22 | return -1; 23 | 24 | buf = save_termios; 25 | 26 | /* echo off, canonical mode off, extended input 27 | processing off, signal chars off */ 28 | buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); 29 | 30 | /* no SIGINT on BREAK, CR-to-NL off, input parity 31 | check off, don't strip the 8th bit on input, 32 | ouput flow control off */ 33 | buf.c_iflag &= ~(BRKINT | ICRNL | ISTRIP | IXON); 34 | 35 | /* clear size bits, parity checking off */ 36 | buf.c_cflag &= ~(CSIZE | PARENB); 37 | 38 | /* set 8 bits/char */ 39 | buf.c_cflag |= CS8; 40 | 41 | /* output processing off */ 42 | buf.c_oflag &= ~(OPOST); 43 | 44 | buf.c_cc[VMIN] = 1; /* 1 byte at a time */ 45 | buf.c_cc[VTIME] = 0; /* no timer on input */ 46 | 47 | if (tcsetattr(fd, TCSAFLUSH, &buf) < 0) 48 | return -1; 49 | 50 | term_saved = 1; 51 | 52 | return 0; 53 | } 54 | 55 | 56 | /* set it to normal! */ 57 | int tty_reset(int fd) 58 | { 59 | if (term_saved) 60 | if (tcsetattr(fd, TCSAFLUSH, &save_termios) < 0) 61 | return -1; 62 | 63 | return 0; 64 | } 65 | 66 | 67 | int main() 68 | { 69 | tty_raw(0); 70 | 71 | int count = 0; 72 | while (true) { 73 | char ch; 74 | char buf[16]; 75 | int actual = read(0, &ch, 1); 76 | if (actual != 1) { 77 | perror("read error"); 78 | break; 79 | } 80 | formatChar(buf, ch); 81 | fputs(buf, stdout); 82 | fflush(stdout); 83 | if (ch == 3) // Ctrl-C 84 | break; 85 | } 86 | 87 | tty_reset(0); 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /misc/Utf16Echo.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | int main(int argc, char *argv[]) { 10 | system("cls"); 11 | 12 | if (argc == 1) { 13 | printf("Usage: %s hhhh\n", argv[0]); 14 | return 0; 15 | } 16 | 17 | std::wstring dataToWrite; 18 | for (int i = 1; i < argc; ++i) { 19 | wchar_t ch = strtol(argv[i], NULL, 16); 20 | dataToWrite.push_back(ch); 21 | } 22 | 23 | DWORD actual = 0; 24 | BOOL ret = WriteConsoleW( 25 | GetStdHandle(STD_OUTPUT_HANDLE), 26 | dataToWrite.data(), dataToWrite.size(), &actual, NULL); 27 | assert(ret && actual == dataToWrite.size()); 28 | 29 | // Read it back. 30 | std::vector readBuffer(dataToWrite.size() * 2); 31 | COORD bufSize = {static_cast(readBuffer.size()), 1}; 32 | COORD bufCoord = {0, 0}; 33 | SMALL_RECT topLeft = {0, 0, static_cast(readBuffer.size() - 1), 0}; 34 | ret = ReadConsoleOutputW( 35 | GetStdHandle(STD_OUTPUT_HANDLE), readBuffer.data(), 36 | bufSize, bufCoord, &topLeft); 37 | assert(ret); 38 | 39 | printf("\n"); 40 | for (int i = 0; i < readBuffer.size(); ++i) { 41 | printf("CHAR: %04x %04x\n", 42 | readBuffer[i].Char.UnicodeChar, 43 | readBuffer[i].Attributes); 44 | } 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /misc/VkEscapeTest.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Sending VK_PAUSE to the console window almost works as a mechanism for 3 | * pausing it, but it doesn't because the console could turn off the 4 | * ENABLE_LINE_INPUT console mode flag. 5 | */ 6 | 7 | #define _WIN32_WINNT 0x0501 8 | #include 9 | #include 10 | #include 11 | 12 | CALLBACK DWORD pausingThread(LPVOID dummy) 13 | { 14 | if (1) { 15 | Sleep(1000); 16 | HWND hwnd = GetConsoleWindow(); 17 | SendMessage(hwnd, WM_KEYDOWN, VK_PAUSE, 1); 18 | Sleep(1000); 19 | SendMessage(hwnd, WM_KEYDOWN, VK_ESCAPE, 1); 20 | } 21 | 22 | if (0) { 23 | INPUT_RECORD ir; 24 | memset(&ir, 0, sizeof(ir)); 25 | ir.EventType = KEY_EVENT; 26 | ir.Event.KeyEvent.bKeyDown = TRUE; 27 | ir.Event.KeyEvent.wVirtualKeyCode = VK_PAUSE; 28 | ir.Event.KeyEvent.wRepeatCount = 1; 29 | } 30 | 31 | return 0; 32 | } 33 | 34 | int main() 35 | { 36 | HANDLE hin = GetStdHandle(STD_INPUT_HANDLE); 37 | HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); 38 | COORD c = { 0, 0 }; 39 | 40 | DWORD mode; 41 | GetConsoleMode(hin, &mode); 42 | SetConsoleMode(hin, mode & 43 | ~(ENABLE_LINE_INPUT)); 44 | 45 | CreateThread(NULL, 0, 46 | pausingThread, NULL, 47 | 0, NULL); 48 | 49 | int i = 0; 50 | while (true) { 51 | Sleep(100); 52 | printf("%d\n", ++i); 53 | } 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /misc/Win10ResizeWhileFrozen.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Demonstrates a conhost hang that occurs when widening the console buffer 3 | * while selection is in progress. The problem affects the new Windows 10 4 | * console, not the "legacy" console mode that Windows 10 also includes. 5 | * 6 | * First tested with: 7 | * - Windows 10.0.10240 8 | * - conhost.exe version 10.0.10240.16384 9 | * - ConhostV1.dll version 10.0.10240.16384 10 | * - ConhostV2.dll version 10.0.10240.16391 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "TestUtil.cc" 19 | 20 | const int SC_CONSOLE_MARK = 0xFFF2; 21 | const int SC_CONSOLE_SELECT_ALL = 0xFFF5; 22 | 23 | int main(int argc, char *argv[]) { 24 | if (argc == 1) { 25 | startChildProcess(L"CHILD"); 26 | return 0; 27 | } 28 | 29 | setWindowPos(0, 0, 1, 1); 30 | setBufferSize(80, 25); 31 | setWindowPos(0, 0, 80, 25); 32 | 33 | countDown(5); 34 | 35 | SendMessage(GetConsoleWindow(), WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0); 36 | Sleep(2000); 37 | 38 | // This API call does not return. In the console window, the "Select All" 39 | // operation appears to end. The console window becomes non-responsive, 40 | // and the conhost.exe process must be killed from the Task Manager. 41 | // (Killing this test program or closing the console window is not 42 | // sufficient.) 43 | // 44 | // The same hang occurs whether line resizing is off or on. It happens 45 | // with both "Mark" and "Select All". Calling setBufferSize with the 46 | // existing buffer size does not hang, but calling it with only a changed 47 | // buffer height *does* hang. Calling setWindowPos does not hang. 48 | setBufferSize(120, 25); 49 | 50 | printf("Done...\n"); 51 | Sleep(2000); 52 | } 53 | -------------------------------------------------------------------------------- /misc/Win10WrapTest1.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Demonstrates some wrapping behaviors of the new Windows 10 console. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "TestUtil.cc" 10 | 11 | int main(int argc, char *argv[]) { 12 | if (argc == 1) { 13 | startChildProcess(L"CHILD"); 14 | return 0; 15 | } 16 | 17 | setWindowPos(0, 0, 1, 1); 18 | setBufferSize(40, 20); 19 | setWindowPos(0, 0, 40, 20); 20 | 21 | system("cls"); 22 | 23 | repeatChar(39, 'A'); repeatChar(1, ' '); 24 | repeatChar(39, 'B'); repeatChar(1, ' '); 25 | printf("\n"); 26 | 27 | repeatChar(39, 'C'); repeatChar(1, ' '); 28 | repeatChar(39, 'D'); repeatChar(1, ' '); 29 | printf("\n"); 30 | 31 | repeatChar(40, 'E'); 32 | repeatChar(40, 'F'); 33 | printf("\n"); 34 | 35 | repeatChar(39, 'G'); repeatChar(1, ' '); 36 | repeatChar(39, 'H'); repeatChar(1, ' '); 37 | printf("\n"); 38 | 39 | Sleep(2000); 40 | 41 | setChar(39, 0, '*', 0x24); 42 | setChar(39, 1, '*', 0x24); 43 | 44 | setChar(39, 3, ' ', 0x24); 45 | setChar(39, 4, ' ', 0x24); 46 | 47 | setChar(38, 6, ' ', 0x24); 48 | setChar(38, 7, ' ', 0x24); 49 | 50 | Sleep(2000); 51 | setWindowPos(0, 0, 35, 20); 52 | setBufferSize(35, 20); 53 | trace("DONE"); 54 | 55 | printf("Sleeping forever...\n"); 56 | while(true) { Sleep(1000); } 57 | } 58 | -------------------------------------------------------------------------------- /misc/Win10WrapTest2.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "TestUtil.cc" 4 | 5 | int main(int argc, char *argv[]) { 6 | if (argc == 1) { 7 | startChildProcess(L"CHILD"); 8 | return 0; 9 | } 10 | 11 | const int WIDTH = 25; 12 | 13 | setWindowPos(0, 0, 1, 1); 14 | setBufferSize(WIDTH, 40); 15 | setWindowPos(0, 0, WIDTH, 20); 16 | 17 | system("cls"); 18 | 19 | for (int i = 0; i < 100; ++i) { 20 | printf("FOO(%d)\n", i); 21 | } 22 | 23 | repeatChar(5, '\n'); 24 | repeatChar(WIDTH * 5, '.'); 25 | repeatChar(10, '\n'); 26 | setWindowPos(0, 20, WIDTH, 20); 27 | writeBox(0, 5, 1, 10, '|'); 28 | 29 | Sleep(120000); 30 | } 31 | -------------------------------------------------------------------------------- /misc/Win32Echo1.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * A Win32 program that reads raw console input with ReadFile and echos 3 | * it to stdout. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | int main() 11 | { 12 | int count = 0; 13 | HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); 14 | HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); 15 | SetConsoleMode(hStdIn, 0); 16 | 17 | while (true) { 18 | DWORD actual; 19 | char ch; 20 | ReadFile(hStdIn, &ch, 1, &actual, NULL); 21 | printf("%02x ", ch); 22 | if (++count == 50) 23 | break; 24 | } 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /misc/Win32Echo2.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * A Win32 program that reads raw console input with getch and echos 3 | * it to stdout. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | int main() 10 | { 11 | int count = 0; 12 | while (true) { 13 | int ch = getch(); 14 | printf("%02x ", ch); 15 | if (++count == 50) 16 | break; 17 | } 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /misc/Win32Test1.cc: -------------------------------------------------------------------------------- 1 | #define _WIN32_WINNT 0x0501 2 | #include "../src/shared/DebugClient.cc" 3 | #include 4 | #include 5 | 6 | const int SC_CONSOLE_MARK = 0xFFF2; 7 | 8 | CALLBACK DWORD writerThread(void*) 9 | { 10 | while (true) { 11 | Sleep(1000); 12 | trace("writing"); 13 | printf("X\n"); 14 | trace("written"); 15 | } 16 | } 17 | 18 | int main() 19 | { 20 | CreateThread(NULL, 0, writerThread, NULL, 0, NULL); 21 | trace("marking console"); 22 | HWND hwnd = GetConsoleWindow(); 23 | PostMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0); 24 | 25 | Sleep(2000); 26 | 27 | trace("reading output"); 28 | CHAR_INFO buf[1]; 29 | COORD bufSize = { 1, 1 }; 30 | COORD zeroCoord = { 0, 0 }; 31 | SMALL_RECT readRect = { 0, 0, 0, 0 }; 32 | ReadConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE), 33 | buf, 34 | bufSize, 35 | zeroCoord, 36 | &readRect); 37 | trace("done reading output"); 38 | 39 | Sleep(2000); 40 | 41 | PostMessage(hwnd, WM_CHAR, 27, 0x00010001); 42 | 43 | Sleep(1100); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /misc/Win32Test2.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This test demonstrates that putting a console into selection mode does not 3 | * block the low-level console APIs, even though it blocks WriteFile. 4 | */ 5 | 6 | #define _WIN32_WINNT 0x0501 7 | #include "../src/shared/DebugClient.cc" 8 | #include 9 | #include 10 | 11 | const int SC_CONSOLE_MARK = 0xFFF2; 12 | 13 | CALLBACK DWORD writerThread(void*) 14 | { 15 | CHAR_INFO xChar, fillChar; 16 | memset(&xChar, 0, sizeof(xChar)); 17 | xChar.Char.AsciiChar = 'X'; 18 | xChar.Attributes = 7; 19 | memset(&fillChar, 0, sizeof(fillChar)); 20 | fillChar.Char.AsciiChar = ' '; 21 | fillChar.Attributes = 7; 22 | COORD oneCoord = { 1, 1 }; 23 | COORD zeroCoord = { 0, 0 }; 24 | 25 | while (true) { 26 | SMALL_RECT writeRegion = { 5, 5, 5, 5 }; 27 | WriteConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE), 28 | &xChar, oneCoord, 29 | zeroCoord, 30 | &writeRegion); 31 | Sleep(500); 32 | SMALL_RECT scrollRect = { 1, 1, 20, 20 }; 33 | COORD destCoord = { 0, 0 }; 34 | ScrollConsoleScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE), 35 | &scrollRect, 36 | NULL, 37 | destCoord, 38 | &fillChar); 39 | } 40 | } 41 | 42 | int main() 43 | { 44 | CreateThread(NULL, 0, writerThread, NULL, 0, NULL); 45 | trace("marking console"); 46 | HWND hwnd = GetConsoleWindow(); 47 | PostMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0); 48 | 49 | Sleep(2000); 50 | 51 | trace("reading output"); 52 | CHAR_INFO buf[1]; 53 | COORD bufSize = { 1, 1 }; 54 | COORD zeroCoord = { 0, 0 }; 55 | SMALL_RECT readRect = { 0, 0, 0, 0 }; 56 | ReadConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE), 57 | buf, 58 | bufSize, 59 | zeroCoord, 60 | &readRect); 61 | trace("done reading output"); 62 | 63 | Sleep(2000); 64 | 65 | PostMessage(hwnd, WM_CHAR, 27, 0x00010001); 66 | 67 | Sleep(1100); 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /misc/Win32Test3.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Creates a window station and starts a process under it. The new process 3 | * also gets a new console. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | int main() 11 | { 12 | BOOL success; 13 | 14 | SECURITY_ATTRIBUTES sa; 15 | memset(&sa, 0, sizeof(sa)); 16 | sa.bInheritHandle = TRUE; 17 | 18 | HWINSTA originalStation = GetProcessWindowStation(); 19 | printf("originalStation == 0x%x\n", originalStation); 20 | HWINSTA station = CreateWindowStation(NULL, 21 | 0, 22 | WINSTA_ALL_ACCESS, 23 | &sa); 24 | printf("station == 0x%x\n", station); 25 | if (!SetProcessWindowStation(station)) 26 | printf("SetWindowStation failed!\n"); 27 | HDESK desktop = CreateDesktop("Default", NULL, NULL, 28 | /*dwFlags=*/0, GENERIC_ALL, 29 | &sa); 30 | printf("desktop = 0x%x\n", desktop); 31 | 32 | char stationName[256]; 33 | stationName[0] = '\0'; 34 | success = GetUserObjectInformation(station, UOI_NAME, 35 | stationName, sizeof(stationName), 36 | NULL); 37 | printf("stationName = [%s]\n", stationName); 38 | 39 | char startupDesktop[256]; 40 | sprintf(startupDesktop, "%s\\Default", stationName); 41 | 42 | STARTUPINFO sui; 43 | PROCESS_INFORMATION pi; 44 | memset(&sui, 0, sizeof(sui)); 45 | memset(&pi, 0, sizeof(pi)); 46 | sui.cb = sizeof(STARTUPINFO); 47 | sui.lpDesktop = startupDesktop; 48 | 49 | // Start a cmd subprocess, and have it start its own cmd subprocess. 50 | // Both subprocesses will connect to the same non-interactive window 51 | // station. 52 | 53 | const char program[] = "c:\\windows\\system32\\cmd.exe"; 54 | char cmdline[256]; 55 | sprintf(cmdline, "%s /c cmd", program); 56 | success = CreateProcess(program, 57 | cmdline, 58 | NULL, 59 | NULL, 60 | /*bInheritHandles=*/FALSE, 61 | /*dwCreationFlags=*/CREATE_NEW_CONSOLE, 62 | NULL, NULL, 63 | &sui, 64 | &pi); 65 | 66 | printf("pid == %d\n", pi.dwProcessId); 67 | 68 | // This sleep is necessary. We must give the child enough time to 69 | // connect to the specified window station. 70 | Sleep(5000); 71 | 72 | SetProcessWindowStation(originalStation); 73 | CloseWindowStation(station); 74 | CloseDesktop(desktop); 75 | Sleep(5000); 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /misc/Win32Write1.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * A Win32 program that scrolls and writes to the console using the ioctl-like 3 | * interface. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | int main() 10 | { 11 | HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); 12 | 13 | for (int i = 0; i < 80; ++i) { 14 | 15 | CONSOLE_SCREEN_BUFFER_INFO info; 16 | GetConsoleScreenBufferInfo(conout, &info); 17 | 18 | SMALL_RECT src = { 0, 1, info.dwSize.X - 1, info.dwSize.Y - 1 }; 19 | COORD destOrigin = { 0, 0 }; 20 | CHAR_INFO fillCharInfo = { 0 }; 21 | fillCharInfo.Char.AsciiChar = ' '; 22 | fillCharInfo.Attributes = 7; 23 | ScrollConsoleScreenBuffer(conout, 24 | &src, 25 | NULL, 26 | destOrigin, 27 | &fillCharInfo); 28 | 29 | CHAR_INFO buffer = { 0 }; 30 | buffer.Char.AsciiChar = 'X'; 31 | buffer.Attributes = 7; 32 | COORD bufferSize = { 1, 1 }; 33 | COORD bufferCoord = { 0, 0 }; 34 | SMALL_RECT writeRegion = { 0, 0, 0, 0 }; 35 | writeRegion.Left = writeRegion.Right = i; 36 | writeRegion.Top = writeRegion.Bottom = 5; 37 | WriteConsoleOutput(conout, 38 | &buffer, bufferSize, bufferCoord, 39 | &writeRegion); 40 | 41 | Sleep(250); 42 | } 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /misc/WindowsBugCrashReader.cc: -------------------------------------------------------------------------------- 1 | // I noticed this on the ConEmu web site: 2 | // 3 | // https://social.msdn.microsoft.com/Forums/en-US/40c8e395-cca9-45c8-b9b8-2fbe6782ac2b/readconsoleoutput-cause-access-violation-writing-location-exception 4 | // https://conemu.github.io/en/MicrosoftBugs.html 5 | // 6 | // In Windows 7, 8, and 8.1, a ReadConsoleOutputW with an out-of-bounds read 7 | // region crashes the application. I have reproduced the problem on Windows 8 8 | // and 8.1, but not on Windows 7. 9 | // 10 | 11 | #include 12 | 13 | #include "TestUtil.cc" 14 | 15 | int main() { 16 | setWindowPos(0, 0, 1, 1); 17 | setBufferSize(80, 25); 18 | setWindowPos(0, 0, 80, 25); 19 | 20 | const HANDLE conout = openConout(); 21 | static CHAR_INFO lineBuf[80]; 22 | SMALL_RECT readRegion = { 0, 999, 79, 999 }; 23 | const BOOL ret = ReadConsoleOutputW(conout, lineBuf, {80, 1}, {0, 0}, &readRegion); 24 | ASSERT(!ret && "ReadConsoleOutputW should have failed"); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /misc/build32.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | name=$1 4 | name=${name%.} 5 | name=${name%.cc} 6 | name=${name%.exe} 7 | echo Compiling $name.cc to $name.exe 8 | i686-w64-mingw32-g++.exe -static -std=c++11 $name.cc -o $name.exe 9 | i686-w64-mingw32-strip $name.exe 10 | -------------------------------------------------------------------------------- /misc/build64.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | name=$1 4 | name=${name%.} 5 | name=${name%.cc} 6 | name=${name%.exe} 7 | echo Compiling $name.cc to $name.exe 8 | x86_64-w64-mingw32-g++.exe -static -std=c++11 $name.cc -o $name.exe 9 | x86_64-w64-mingw32-strip $name.exe 10 | -------------------------------------------------------------------------------- /ship/build-pty4j-libpty.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | setlocal 4 | cd %~dp0.. 5 | set Path=C:\Python27;C:\Program Files\Git\cmd;%Path% 6 | 7 | call "%VS140COMNTOOLS%\VsDevCmd.bat" || goto :fail 8 | 9 | rmdir /s/q build-libpty 2>NUL 10 | mkdir build-libpty\win 11 | mkdir build-libpty\win\x86 12 | mkdir build-libpty\win\x86_64 13 | mkdir build-libpty\win\xp 14 | 15 | rmdir /s/q src\Release 2>NUL 16 | rmdir /s/q src\.vs 2>NUL 17 | del src\*.vcxproj src\*.vcxproj.filters src\*.sln src\*.sdf 2>NUL 18 | 19 | call vcbuild.bat --msvc-platform Win32 --gyp-msvs-version 2015 --toolset v140_xp || goto :fail 20 | copy src\Release\Win32\winpty.dll build-libpty\win\xp || goto :fail 21 | copy src\Release\Win32\winpty-agent.exe build-libpty\win\xp || goto :fail 22 | 23 | call vcbuild.bat --msvc-platform Win32 --gyp-msvs-version 2015 || goto :fail 24 | copy src\Release\Win32\winpty.dll build-libpty\win\x86 || goto :fail 25 | copy src\Release\Win32\winpty-agent.exe build-libpty\win\x86 || goto :fail 26 | 27 | call vcbuild.bat --msvc-platform x64 --gyp-msvs-version 2015 || goto :fail 28 | copy src\Release\x64\winpty.dll build-libpty\win\x86_64 || goto :fail 29 | copy src\Release\x64\winpty-agent.exe build-libpty\win\x86_64 || goto :fail 30 | 31 | echo success 32 | goto :EOF 33 | 34 | :fail 35 | echo error: build failed 36 | exit /b 1 37 | -------------------------------------------------------------------------------- /ship/common_ship.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | # These scripts need to continue using Python 2 rather than 3, because 5 | # make_msvc_package.py puts the current Python interpreter on the PATH for the 6 | # sake of gyp, and gyp doesn't work with Python 3 yet. 7 | # https://bugs.chromium.org/p/gyp/issues/detail?id=36 8 | if os.name != "nt": 9 | sys.exit("Error: ship scripts require native Python 2.7. (wrong os.name)") 10 | if sys.version_info[0:2] != (2,7): 11 | sys.exit("Error: ship scripts require native Python 2.7. (wrong version)") 12 | 13 | import glob 14 | import hashlib 15 | import shutil 16 | import subprocess 17 | from distutils.spawn import find_executable 18 | 19 | topDir = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) 20 | 21 | with open(topDir + "/VERSION.txt", "rt") as f: 22 | winptyVersion = f.read().strip() 23 | 24 | def rmrf(patterns): 25 | for pattern in patterns: 26 | for path in glob.glob(pattern): 27 | if os.path.isdir(path) and not os.path.islink(path): 28 | print("+ rm -r " + path) 29 | sys.stdout.flush() 30 | shutil.rmtree(path) 31 | elif os.path.isfile(path): 32 | print("+ rm " + path) 33 | sys.stdout.flush() 34 | os.remove(path) 35 | 36 | def mkdir(path): 37 | if not os.path.isdir(path): 38 | os.makedirs(path) 39 | 40 | def requireExe(name, guesses): 41 | if find_executable(name) is None: 42 | for guess in guesses: 43 | if os.path.exists(guess): 44 | newDir = os.path.dirname(guess) 45 | print("Adding " + newDir + " to Path to provide " + name) 46 | os.environ["Path"] = newDir + ";" + os.environ["Path"] 47 | ret = find_executable(name) 48 | if ret is None: 49 | sys.exit("Error: required EXE is missing from Path: " + name) 50 | return ret 51 | 52 | class ModifyEnv: 53 | def __init__(self, **kwargs): 54 | self._changes = dict(kwargs) 55 | self._original = dict() 56 | 57 | def __enter__(self): 58 | for var, val in self._changes.items(): 59 | self._original[var] = os.environ[var] 60 | os.environ[var] = val 61 | 62 | def __exit__(self, type, value, traceback): 63 | for var, val in self._original.items(): 64 | os.environ[var] = val 65 | 66 | def sha256(path): 67 | with open(path, "rb") as fp: 68 | return hashlib.sha256(fp.read()).hexdigest() 69 | 70 | def checkSha256(path, expected): 71 | actual = sha256(path) 72 | if actual != expected: 73 | sys.exit("error: sha256 hash mismatch on {}: expected {}, found {}".format( 74 | path, expected, actual)) 75 | 76 | requireExe("git.exe", [ 77 | "C:\\Program Files\\Git\\cmd\\git.exe", 78 | "C:\\Program Files (x86)\\Git\\cmd\\git.exe" 79 | ]) 80 | 81 | commitHash = subprocess.check_output(["git.exe", "rev-parse", "HEAD"]).strip() 82 | defaultPathEnviron = "C:\\Windows\\System32;C:\\Windows" 83 | 84 | ZIP_TOOL = requireExe("7z.exe", [ 85 | "C:\\Program Files\\7-Zip\\7z.exe", 86 | "C:\\Program Files (x86)\\7-Zip\\7z.exe", 87 | ]) 88 | 89 | requireExe("curl.exe", []) 90 | -------------------------------------------------------------------------------- /src/agent/AgentCreateDesktop.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #include "AgentCreateDesktop.h" 22 | 23 | #include "../shared/BackgroundDesktop.h" 24 | #include "../shared/Buffer.h" 25 | #include "../shared/DebugClient.h" 26 | #include "../shared/StringUtil.h" 27 | 28 | #include "EventLoop.h" 29 | #include "NamedPipe.h" 30 | 31 | namespace { 32 | 33 | static inline WriteBuffer newPacket() { 34 | WriteBuffer packet; 35 | packet.putRawValue(0); // Reserve space for size. 36 | return packet; 37 | } 38 | 39 | class CreateDesktopLoop : public EventLoop { 40 | public: 41 | CreateDesktopLoop(LPCWSTR controlPipeName); 42 | 43 | protected: 44 | virtual void onPipeIo(NamedPipe &namedPipe) override; 45 | 46 | private: 47 | void writePacket(WriteBuffer &packet); 48 | 49 | BackgroundDesktop m_desktop; 50 | NamedPipe &m_pipe; 51 | }; 52 | 53 | CreateDesktopLoop::CreateDesktopLoop(LPCWSTR controlPipeName) : 54 | m_pipe(createNamedPipe()) { 55 | m_pipe.connectToServer(controlPipeName, NamedPipe::OpenMode::Duplex); 56 | auto packet = newPacket(); 57 | packet.putWString(m_desktop.desktopName()); 58 | writePacket(packet); 59 | } 60 | 61 | void CreateDesktopLoop::writePacket(WriteBuffer &packet) { 62 | const auto &bytes = packet.buf(); 63 | packet.replaceRawValue(0, bytes.size()); 64 | m_pipe.write(bytes.data(), bytes.size()); 65 | } 66 | 67 | void CreateDesktopLoop::onPipeIo(NamedPipe &namedPipe) { 68 | if (m_pipe.isClosed()) { 69 | shutdown(); 70 | } 71 | } 72 | 73 | } // anonymous namespace 74 | 75 | void handleCreateDesktop(LPCWSTR controlPipeName) { 76 | try { 77 | CreateDesktopLoop loop(controlPipeName); 78 | loop.run(); 79 | trace("Agent exiting..."); 80 | } catch (const WinptyException &e) { 81 | trace("handleCreateDesktop: internal error: %s", 82 | utf8FromWide(e.what()).c_str()); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/agent/AgentCreateDesktop.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef AGENT_CREATE_DESKTOP_H 22 | #define AGENT_CREATE_DESKTOP_H 23 | 24 | #include 25 | 26 | void handleCreateDesktop(LPCWSTR controlPipeName); 27 | 28 | #endif // AGENT_CREATE_DESKTOP_H 29 | -------------------------------------------------------------------------------- /src/agent/ConsoleFont.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef CONSOLEFONT_H 22 | #define CONSOLEFONT_H 23 | 24 | #include 25 | 26 | void setSmallFont(HANDLE conout, int columns, bool isNewW10); 27 | 28 | #endif // CONSOLEFONT_H 29 | -------------------------------------------------------------------------------- /src/agent/ConsoleInputReencoding.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef AGENT_CONSOLE_INPUT_REENCODING_H 22 | #define AGENT_CONSOLE_INPUT_REENCODING_H 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | 30 | void reencodeEscapedKeyPress( 31 | std::vector &records, 32 | uint16_t virtualKey, 33 | uint32_t codePoint, 34 | uint16_t keyState); 35 | 36 | #endif // AGENT_CONSOLE_INPUT_REENCODING_H 37 | -------------------------------------------------------------------------------- /src/agent/ConsoleLine.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef CONSOLE_LINE_H 22 | #define CONSOLE_LINE_H 23 | 24 | #include 25 | 26 | #include 27 | 28 | class ConsoleLine 29 | { 30 | public: 31 | ConsoleLine(); 32 | void reset(); 33 | bool detectChangeAndSetLine(const CHAR_INFO *line, int newLength); 34 | void setLine(const CHAR_INFO *line, int newLength); 35 | void blank(WORD attributes); 36 | private: 37 | int m_prevLength; 38 | std::vector m_prevData; 39 | }; 40 | 41 | #endif // CONSOLE_LINE_H 42 | -------------------------------------------------------------------------------- /src/agent/Coord.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef COORD_H 22 | #define COORD_H 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include "../shared/winpty_snprintf.h" 29 | 30 | struct Coord : COORD { 31 | Coord() 32 | { 33 | X = 0; 34 | Y = 0; 35 | } 36 | 37 | Coord(SHORT x, SHORT y) 38 | { 39 | X = x; 40 | Y = y; 41 | } 42 | 43 | Coord(COORD other) 44 | { 45 | *(COORD*)this = other; 46 | } 47 | 48 | Coord(const Coord &other) 49 | { 50 | *(COORD*)this = *(const COORD*)&other; 51 | } 52 | 53 | Coord &operator=(const Coord &other) 54 | { 55 | *(COORD*)this = *(const COORD*)&other; 56 | return *this; 57 | } 58 | 59 | bool operator==(const Coord &other) const 60 | { 61 | return X == other.X && Y == other.Y; 62 | } 63 | 64 | bool operator!=(const Coord &other) const 65 | { 66 | return !(*this == other); 67 | } 68 | 69 | Coord operator+(const Coord &other) const 70 | { 71 | return Coord(X + other.X, Y + other.Y); 72 | } 73 | 74 | bool isEmpty() const 75 | { 76 | return X <= 0 || Y <= 0; 77 | } 78 | 79 | std::string toString() const 80 | { 81 | char ret[32]; 82 | winpty_snprintf(ret, "(%d,%d)", X, Y); 83 | return std::string(ret); 84 | } 85 | }; 86 | 87 | #endif // COORD_H 88 | -------------------------------------------------------------------------------- /src/agent/DebugShowInput.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef AGENT_DEBUG_SHOW_INPUT_H 22 | #define AGENT_DEBUG_SHOW_INPUT_H 23 | 24 | #include 25 | 26 | #include 27 | 28 | std::string controlKeyStatePrefix(DWORD controlKeyState); 29 | std::string mouseEventToString(const MOUSE_EVENT_RECORD &mer); 30 | void debugShowInput(bool enableMouse, bool escapeInput); 31 | 32 | #endif // AGENT_DEBUG_SHOW_INPUT_H 33 | -------------------------------------------------------------------------------- /src/agent/DefaultInputMap.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef DEFAULT_INPUT_MAP_H 22 | #define DEFAULT_INPUT_MAP_H 23 | 24 | class InputMap; 25 | 26 | void addDefaultEntriesToInputMap(InputMap &inputMap); 27 | 28 | #endif // DEFAULT_INPUT_MAP_H 29 | -------------------------------------------------------------------------------- /src/agent/DsrSender.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef DSRSENDER_H 22 | #define DSRSENDER_H 23 | 24 | class DsrSender 25 | { 26 | public: 27 | virtual void sendDsr() = 0; 28 | }; 29 | 30 | #endif // DSRSENDER_H 31 | -------------------------------------------------------------------------------- /src/agent/EventLoop.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #include "EventLoop.h" 22 | 23 | #include 24 | 25 | #include "NamedPipe.h" 26 | #include "../shared/DebugClient.h" 27 | #include "../shared/WinptyAssert.h" 28 | 29 | EventLoop::~EventLoop() { 30 | for (NamedPipe *pipe : m_pipes) { 31 | delete pipe; 32 | } 33 | m_pipes.clear(); 34 | } 35 | 36 | // Enter the event loop. Runs until the I/O or timeout handler calls exit(). 37 | void EventLoop::run() 38 | { 39 | std::vector waitHandles; 40 | DWORD lastTime = GetTickCount(); 41 | while (!m_exiting) { 42 | bool didSomething = false; 43 | 44 | // Attempt to make progress with the pipes. 45 | waitHandles.clear(); 46 | for (size_t i = 0; i < m_pipes.size(); ++i) { 47 | if (m_pipes[i]->serviceIo(&waitHandles)) { 48 | onPipeIo(*m_pipes[i]); 49 | didSomething = true; 50 | } 51 | } 52 | 53 | // Call the timeout if enough time has elapsed. 54 | if (m_pollInterval > 0) { 55 | int elapsed = GetTickCount() - lastTime; 56 | if (elapsed >= m_pollInterval) { 57 | onPollTimeout(); 58 | lastTime = GetTickCount(); 59 | didSomething = true; 60 | } 61 | } 62 | 63 | if (didSomething) 64 | continue; 65 | 66 | // If there's nothing to do, wait. 67 | DWORD timeout = INFINITE; 68 | if (m_pollInterval > 0) 69 | timeout = std::max(0, (int)(lastTime + m_pollInterval - GetTickCount())); 70 | if (waitHandles.size() == 0) { 71 | ASSERT(timeout != INFINITE); 72 | if (timeout > 0) 73 | Sleep(timeout); 74 | } else { 75 | DWORD result = WaitForMultipleObjects(waitHandles.size(), 76 | waitHandles.data(), 77 | FALSE, 78 | timeout); 79 | ASSERT(result != WAIT_FAILED); 80 | } 81 | } 82 | } 83 | 84 | NamedPipe &EventLoop::createNamedPipe() 85 | { 86 | NamedPipe *ret = new NamedPipe(); 87 | m_pipes.push_back(ret); 88 | return *ret; 89 | } 90 | 91 | void EventLoop::setPollInterval(int ms) 92 | { 93 | m_pollInterval = ms; 94 | } 95 | 96 | void EventLoop::shutdown() 97 | { 98 | m_exiting = true; 99 | } 100 | -------------------------------------------------------------------------------- /src/agent/EventLoop.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef EVENTLOOP_H 22 | #define EVENTLOOP_H 23 | 24 | #include 25 | 26 | class NamedPipe; 27 | 28 | class EventLoop 29 | { 30 | public: 31 | virtual ~EventLoop(); 32 | void run(); 33 | 34 | protected: 35 | NamedPipe &createNamedPipe(); 36 | void setPollInterval(int ms); 37 | void shutdown(); 38 | virtual void onPollTimeout() {} 39 | virtual void onPipeIo(NamedPipe &namedPipe) {} 40 | 41 | private: 42 | bool m_exiting = false; 43 | std::vector m_pipes; 44 | int m_pollInterval = 0; 45 | }; 46 | 47 | #endif // EVENTLOOP_H 48 | -------------------------------------------------------------------------------- /src/agent/InputMap.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef INPUT_MAP_H 22 | #define INPUT_MAP_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include "SimplePool.h" 31 | #include "../shared/WinptyAssert.h" 32 | 33 | class InputMap { 34 | public: 35 | struct Key { 36 | uint16_t virtualKey; 37 | uint32_t unicodeChar; 38 | uint16_t keyState; 39 | 40 | std::string toString() const; 41 | }; 42 | 43 | private: 44 | struct Node; 45 | 46 | struct Branch { 47 | Branch() { 48 | memset(&children, 0, sizeof(children)); 49 | } 50 | 51 | Node *children[256]; 52 | }; 53 | 54 | struct Node { 55 | Node() : childCount(0) { 56 | Key zeroKey = { 0, 0, 0 }; 57 | key = zeroKey; 58 | } 59 | 60 | Key key; 61 | int childCount; 62 | enum { kTinyCount = 8 }; 63 | union { 64 | Branch *branch; 65 | struct { 66 | unsigned char values[kTinyCount]; 67 | Node *children[kTinyCount]; 68 | } tiny; 69 | } u; 70 | 71 | bool hasKey() const { 72 | return key.virtualKey != 0 || key.unicodeChar != 0; 73 | } 74 | }; 75 | 76 | private: 77 | SimplePool m_nodePool; 78 | SimplePool m_branchPool; 79 | Node m_root; 80 | 81 | public: 82 | void set(const char *encoding, int encodingLen, const Key &key); 83 | int lookupKey(const char *input, int inputSize, 84 | Key &keyOut, bool &incompleteOut) const; 85 | void dumpInputMap() const; 86 | 87 | private: 88 | Node *getChild(Node &node, unsigned char ch) { 89 | return const_cast(getChild(static_cast(node), ch)); 90 | } 91 | 92 | const Node *getChild(const Node &node, unsigned char ch) const { 93 | if (node.childCount <= Node::kTinyCount) { 94 | for (int i = 0; i < node.childCount; ++i) { 95 | if (node.u.tiny.values[i] == ch) { 96 | return node.u.tiny.children[i]; 97 | } 98 | } 99 | return NULL; 100 | } else { 101 | return node.u.branch->children[ch]; 102 | } 103 | } 104 | 105 | void setHelper(Node &node, const char *encoding, int encodingLen, const Key &key); 106 | Node &getOrCreateChild(Node &node, unsigned char ch); 107 | void dumpInputMapHelper(const Node &node, std::string &encoding) const; 108 | }; 109 | 110 | const InputMap::Key kKeyZero = { 0, 0, 0 }; 111 | 112 | void dumpInputMap(InputMap &inputMap); 113 | 114 | #endif // INPUT_MAP_H 115 | -------------------------------------------------------------------------------- /src/agent/LargeConsoleRead.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #include "LargeConsoleRead.h" 22 | 23 | #include 24 | 25 | #include "../shared/WindowsVersion.h" 26 | #include "Scraper.h" 27 | #include "Win32ConsoleBuffer.h" 28 | 29 | LargeConsoleReadBuffer::LargeConsoleReadBuffer() : 30 | m_rect(0, 0, 0, 0), m_rectWidth(0) 31 | { 32 | } 33 | 34 | void largeConsoleRead(LargeConsoleReadBuffer &out, 35 | Win32ConsoleBuffer &buffer, 36 | const SmallRect &readArea, 37 | WORD attributesMask) { 38 | ASSERT(readArea.Left >= 0 && 39 | readArea.Top >= 0 && 40 | readArea.Right >= readArea.Left && 41 | readArea.Bottom >= readArea.Top && 42 | readArea.width() <= MAX_CONSOLE_WIDTH); 43 | const size_t count = readArea.width() * readArea.height(); 44 | if (out.m_data.size() < count) { 45 | out.m_data.resize(count); 46 | } 47 | out.m_rect = readArea; 48 | out.m_rectWidth = readArea.width(); 49 | 50 | static const bool useLargeReads = isAtLeastWindows8(); 51 | if (useLargeReads) { 52 | buffer.read(readArea, out.m_data.data()); 53 | } else { 54 | const int maxReadLines = std::max(1, MAX_CONSOLE_WIDTH / readArea.width()); 55 | int curLine = readArea.Top; 56 | while (curLine <= readArea.Bottom) { 57 | const SmallRect subReadArea( 58 | readArea.Left, 59 | curLine, 60 | readArea.width(), 61 | std::min(maxReadLines, readArea.Bottom + 1 - curLine)); 62 | buffer.read(subReadArea, out.lineDataMut(curLine)); 63 | curLine = subReadArea.Bottom + 1; 64 | } 65 | } 66 | if (attributesMask != static_cast(~0)) { 67 | for (size_t i = 0; i < count; ++i) { 68 | out.m_data[i].Attributes &= attributesMask; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/agent/LargeConsoleRead.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef LARGE_CONSOLE_READ_H 22 | #define LARGE_CONSOLE_READ_H 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include "SmallRect.h" 30 | #include "../shared/DebugClient.h" 31 | #include "../shared/WinptyAssert.h" 32 | 33 | class Win32ConsoleBuffer; 34 | 35 | class LargeConsoleReadBuffer { 36 | public: 37 | LargeConsoleReadBuffer(); 38 | const SmallRect &rect() const { return m_rect; } 39 | const CHAR_INFO *lineData(int line) const { 40 | validateLineNumber(line); 41 | return &m_data[(line - m_rect.Top) * m_rectWidth]; 42 | } 43 | 44 | private: 45 | CHAR_INFO *lineDataMut(int line) { 46 | validateLineNumber(line); 47 | return &m_data[(line - m_rect.Top) * m_rectWidth]; 48 | } 49 | 50 | void validateLineNumber(int line) const { 51 | if (line < m_rect.Top || line > m_rect.Bottom) { 52 | trace("Fatal error: LargeConsoleReadBuffer: invalid line %d for " 53 | "read rect %s", line, m_rect.toString().c_str()); 54 | abort(); 55 | } 56 | } 57 | 58 | SmallRect m_rect; 59 | int m_rectWidth; 60 | std::vector m_data; 61 | 62 | friend void largeConsoleRead(LargeConsoleReadBuffer &out, 63 | Win32ConsoleBuffer &buffer, 64 | const SmallRect &readArea, 65 | WORD attributesMask); 66 | }; 67 | 68 | #endif // LARGE_CONSOLE_READ_H 69 | -------------------------------------------------------------------------------- /src/agent/SimplePool.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef SIMPLE_POOL_H 22 | #define SIMPLE_POOL_H 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include "../shared/WinptyAssert.h" 29 | 30 | template 31 | class SimplePool { 32 | public: 33 | ~SimplePool(); 34 | T *alloc(); 35 | void clear(); 36 | private: 37 | struct Chunk { 38 | size_t count; 39 | T *data; 40 | }; 41 | std::vector m_chunks; 42 | }; 43 | 44 | template 45 | SimplePool::~SimplePool() { 46 | clear(); 47 | } 48 | 49 | template 50 | void SimplePool::clear() { 51 | for (size_t ci = 0; ci < m_chunks.size(); ++ci) { 52 | Chunk &chunk = m_chunks[ci]; 53 | for (size_t ti = 0; ti < chunk.count; ++ti) { 54 | chunk.data[ti].~T(); 55 | } 56 | free(chunk.data); 57 | } 58 | m_chunks.clear(); 59 | } 60 | 61 | template 62 | T *SimplePool::alloc() { 63 | if (m_chunks.empty() || m_chunks.back().count == chunkSize) { 64 | T *newData = reinterpret_cast(malloc(sizeof(T) * chunkSize)); 65 | ASSERT(newData != NULL); 66 | Chunk newChunk = { 0, newData }; 67 | m_chunks.push_back(newChunk); 68 | } 69 | Chunk &chunk = m_chunks.back(); 70 | T *ret = &chunk.data[chunk.count++]; 71 | new (ret) T(); 72 | return ret; 73 | } 74 | 75 | #endif // SIMPLE_POOL_H 76 | -------------------------------------------------------------------------------- /src/agent/Terminal.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef TERMINAL_H 22 | #define TERMINAL_H 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include "Coord.h" 31 | 32 | class NamedPipe; 33 | 34 | class Terminal 35 | { 36 | public: 37 | explicit Terminal(NamedPipe &output, bool plainMode, bool outputColor) 38 | : m_output(output), m_plainMode(plainMode), m_outputColor(outputColor) 39 | { 40 | } 41 | 42 | enum SendClearFlag { OmitClear, SendClear }; 43 | void reset(SendClearFlag sendClearFirst, int64_t newLine); 44 | void sendLine(int64_t line, const CHAR_INFO *lineData, int width, 45 | int cursorColumn); 46 | void showTerminalCursor(int column, int64_t line); 47 | void hideTerminalCursor(); 48 | 49 | private: 50 | void moveTerminalToLine(int64_t line); 51 | 52 | public: 53 | void enableMouseMode(bool enabled); 54 | 55 | private: 56 | NamedPipe &m_output; 57 | int64_t m_remoteLine = 0; 58 | int m_remoteColumn = 0; 59 | bool m_lineDataValid = true; 60 | std::vector m_lineData; 61 | bool m_cursorHidden = false; 62 | int m_remoteColor = -1; 63 | std::string m_termLineWorkingBuffer; 64 | bool m_plainMode = false; 65 | bool m_outputColor = true; 66 | bool m_mouseModeEnabled = false; 67 | }; 68 | 69 | #endif // TERMINAL_H 70 | -------------------------------------------------------------------------------- /src/agent/Win32Console.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef AGENT_WIN32_CONSOLE_H 22 | #define AGENT_WIN32_CONSOLE_H 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | class Win32Console 30 | { 31 | public: 32 | class FreezeGuard { 33 | public: 34 | FreezeGuard(Win32Console &console, bool frozen) : 35 | m_console(console), m_previous(console.frozen()) { 36 | m_console.setFrozen(frozen); 37 | } 38 | ~FreezeGuard() { 39 | m_console.setFrozen(m_previous); 40 | } 41 | FreezeGuard(const FreezeGuard &other) = delete; 42 | FreezeGuard &operator=(const FreezeGuard &other) = delete; 43 | private: 44 | Win32Console &m_console; 45 | bool m_previous; 46 | }; 47 | 48 | Win32Console(); 49 | 50 | HWND hwnd() { return m_hwnd; } 51 | std::wstring title(); 52 | void setTitle(const std::wstring &title); 53 | void setFreezeUsesMark(bool useMark) { m_freezeUsesMark = useMark; } 54 | void setNewW10(bool isNewW10) { m_isNewW10 = isNewW10; } 55 | bool isNewW10() { return m_isNewW10; } 56 | void setFrozen(bool frozen=true); 57 | bool frozen() { return m_frozen; } 58 | 59 | private: 60 | HWND m_hwnd = nullptr; 61 | bool m_frozen = false; 62 | bool m_freezeUsesMark = false; 63 | bool m_isNewW10 = false; 64 | std::vector m_titleWorkBuf; 65 | }; 66 | 67 | #endif // AGENT_WIN32_CONSOLE_H 68 | -------------------------------------------------------------------------------- /src/agent/Win32ConsoleBuffer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef AGENT_WIN32_CONSOLE_BUFFER_H 22 | #define AGENT_WIN32_CONSOLE_BUFFER_H 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | 30 | #include "Coord.h" 31 | #include "SmallRect.h" 32 | 33 | class ConsoleScreenBufferInfo : public CONSOLE_SCREEN_BUFFER_INFO { 34 | public: 35 | ConsoleScreenBufferInfo() 36 | { 37 | memset(this, 0, sizeof(*this)); 38 | } 39 | 40 | Coord bufferSize() const { return dwSize; } 41 | SmallRect windowRect() const { return srWindow; } 42 | Coord cursorPosition() const { return dwCursorPosition; } 43 | }; 44 | 45 | class Win32ConsoleBuffer { 46 | private: 47 | Win32ConsoleBuffer(HANDLE conout, bool owned) : 48 | m_conout(conout), m_owned(owned) 49 | { 50 | } 51 | 52 | public: 53 | static const int kDefaultAttributes = 7; 54 | 55 | ~Win32ConsoleBuffer() { 56 | if (m_owned) { 57 | CloseHandle(m_conout); 58 | } 59 | } 60 | 61 | static std::unique_ptr openStdout(); 62 | static std::unique_ptr openConout(); 63 | static std::unique_ptr createErrorBuffer(); 64 | 65 | Win32ConsoleBuffer(const Win32ConsoleBuffer &other) = delete; 66 | Win32ConsoleBuffer &operator=(const Win32ConsoleBuffer &other) = delete; 67 | 68 | HANDLE conout(); 69 | void clearLines(int row, int count, const ConsoleScreenBufferInfo &info); 70 | void clearAllLines(const ConsoleScreenBufferInfo &info); 71 | 72 | // Buffer and window sizes. 73 | ConsoleScreenBufferInfo bufferInfo(); 74 | Coord bufferSize(); 75 | SmallRect windowRect(); 76 | void resizeBuffer(const Coord &size); 77 | bool resizeBufferRange(const Coord &initialSize, Coord &finalSize); 78 | bool resizeBufferRange(const Coord &initialSize) { 79 | Coord dummy; 80 | return resizeBufferRange(initialSize, dummy); 81 | } 82 | void moveWindow(const SmallRect &rect); 83 | 84 | // Cursor. 85 | Coord cursorPosition(); 86 | void setCursorPosition(const Coord &point); 87 | 88 | // Screen content. 89 | void read(const SmallRect &rect, CHAR_INFO *data); 90 | void write(const SmallRect &rect, const CHAR_INFO *data); 91 | 92 | void setTextAttribute(WORD attributes); 93 | 94 | private: 95 | HANDLE m_conout = nullptr; 96 | bool m_owned = false; 97 | }; 98 | 99 | #endif // AGENT_WIN32_CONSOLE_BUFFER_H 100 | -------------------------------------------------------------------------------- /src/agent/subdir.mk: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011-2015 Ryan Prichard 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to 5 | # deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | # IN THE SOFTWARE. 20 | 21 | ALL_TARGETS += build/winpty-agent.exe 22 | 23 | $(eval $(call def_mingw_target,agent,-DWINPTY_AGENT_ASSERT)) 24 | 25 | AGENT_OBJECTS = \ 26 | build/agent/agent/Agent.o \ 27 | build/agent/agent/AgentCreateDesktop.o \ 28 | build/agent/agent/ConsoleFont.o \ 29 | build/agent/agent/ConsoleInput.o \ 30 | build/agent/agent/ConsoleInputReencoding.o \ 31 | build/agent/agent/ConsoleLine.o \ 32 | build/agent/agent/DebugShowInput.o \ 33 | build/agent/agent/DefaultInputMap.o \ 34 | build/agent/agent/EventLoop.o \ 35 | build/agent/agent/InputMap.o \ 36 | build/agent/agent/LargeConsoleRead.o \ 37 | build/agent/agent/NamedPipe.o \ 38 | build/agent/agent/Scraper.o \ 39 | build/agent/agent/Terminal.o \ 40 | build/agent/agent/Win32Console.o \ 41 | build/agent/agent/Win32ConsoleBuffer.o \ 42 | build/agent/agent/main.o \ 43 | build/agent/shared/BackgroundDesktop.o \ 44 | build/agent/shared/Buffer.o \ 45 | build/agent/shared/DebugClient.o \ 46 | build/agent/shared/GenRandom.o \ 47 | build/agent/shared/OwnedHandle.o \ 48 | build/agent/shared/StringUtil.o \ 49 | build/agent/shared/WindowsSecurity.o \ 50 | build/agent/shared/WindowsVersion.o \ 51 | build/agent/shared/WinptyAssert.o \ 52 | build/agent/shared/WinptyException.o \ 53 | build/agent/shared/WinptyVersion.o 54 | 55 | build/agent/shared/WinptyVersion.o : build/gen/GenVersion.h 56 | 57 | build/winpty-agent.exe : $(AGENT_OBJECTS) 58 | $(info Linking $@) 59 | @$(MINGW_CXX) $(MINGW_LDFLAGS) -o $@ $^ 60 | 61 | -include $(AGENT_OBJECTS:.o=.d) 62 | -------------------------------------------------------------------------------- /src/configurations.gypi: -------------------------------------------------------------------------------- 1 | # By default gyp/msbuild build for 32-bit Windows. This gyp include file 2 | # defines configurations for both 32-bit and 64-bit Windows. To use it, run: 3 | # 4 | # C:\...\winpty\src>gyp -I configurations.gypi 5 | # 6 | # This command generates Visual Studio project files with a Release 7 | # configuration and two Platforms--Win32 and x64. Both can be built: 8 | # 9 | # C:\...\winpty\src>msbuild winpty.sln /p:Platform=Win32 10 | # C:\...\winpty\src>msbuild winpty.sln /p:Platform=x64 11 | # 12 | # The output is placed in: 13 | # 14 | # C:\...\winpty\src\Release\Win32 15 | # C:\...\winpty\src\Release\x64 16 | # 17 | # Windows XP note: By default, the project files will use the default "toolset" 18 | # for the given MSVC version. For MSVC 2013 and MSVC 2015, the default toolset 19 | # generates binaries that do not run on Windows XP. To target Windows XP, 20 | # select the XP-specific toolset by passing 21 | # -D WINPTY_MSBUILD_TOOLSET={v120_xp,v140_xp} to gyp (v120_xp == MSVC 2013, 22 | # v140_xp == MSVC 2015). Unfortunately, it isn't possible to have a single 23 | # project file with configurations for both XP and post-XP. This seems to be a 24 | # limitation of the MSVC project file format. 25 | # 26 | # This file is not included by default, because I suspect it would interfere 27 | # with node-gyp, which has a different system for building 32-vs-64-bit 28 | # binaries. It uses a common.gypi, and the project files it generates can only 29 | # build a single architecture, the output paths are not differentiated by 30 | # architecture. 31 | 32 | { 33 | 'variables': { 34 | 'WINPTY_MSBUILD_TOOLSET%': '', 35 | }, 36 | 'target_defaults': { 37 | 'default_configuration': 'Release_Win32', 38 | 'configurations': { 39 | 'Release_Win32': { 40 | 'msvs_configuration_platform': 'Win32', 41 | }, 42 | 'Release_x64': { 43 | 'msvs_configuration_platform': 'x64', 44 | }, 45 | }, 46 | 'msvs_configuration_attributes': { 47 | 'OutputDirectory': '$(SolutionDir)$(ConfigurationName)\\$(Platform)', 48 | 'IntermediateDirectory': '$(ConfigurationName)\\$(Platform)\\obj\\$(ProjectName)', 49 | }, 50 | 'msvs_settings': { 51 | 'VCLinkerTool': { 52 | 'SubSystem': '1', # /SUBSYSTEM:CONSOLE 53 | }, 54 | 'VCCLCompilerTool': { 55 | 'RuntimeLibrary': '0', # MultiThreaded (/MT) 56 | }, 57 | }, 58 | 'msbuild_toolset' : '<(WINPTY_MSBUILD_TOOLSET)', 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/debugserver/subdir.mk: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015 Ryan Prichard 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to 5 | # deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | # IN THE SOFTWARE. 20 | 21 | ALL_TARGETS += build/winpty-debugserver.exe 22 | 23 | $(eval $(call def_mingw_target,debugserver,)) 24 | 25 | DEBUGSERVER_OBJECTS = \ 26 | build/debugserver/debugserver/DebugServer.o \ 27 | build/debugserver/shared/DebugClient.o \ 28 | build/debugserver/shared/OwnedHandle.o \ 29 | build/debugserver/shared/StringUtil.o \ 30 | build/debugserver/shared/WindowsSecurity.o \ 31 | build/debugserver/shared/WindowsVersion.o \ 32 | build/debugserver/shared/WinptyAssert.o \ 33 | build/debugserver/shared/WinptyException.o 34 | 35 | build/debugserver/shared/WindowsVersion.o : build/gen/GenVersion.h 36 | 37 | build/winpty-debugserver.exe : $(DEBUGSERVER_OBJECTS) 38 | $(info Linking $@) 39 | @$(MINGW_CXX) $(MINGW_LDFLAGS) -o $@ $^ 40 | 41 | -include $(DEBUGSERVER_OBJECTS:.o=.d) 42 | -------------------------------------------------------------------------------- /src/libwinpty/AgentLocation.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #include "AgentLocation.h" 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include "../shared/WinptyAssert.h" 28 | 29 | #include "LibWinptyException.h" 30 | 31 | #define AGENT_EXE L"winpty-agent.exe" 32 | 33 | static HMODULE getCurrentModule() { 34 | HMODULE module; 35 | if (!GetModuleHandleExW( 36 | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | 37 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 38 | reinterpret_cast(getCurrentModule), 39 | &module)) { 40 | ASSERT(false && "GetModuleHandleEx failed"); 41 | } 42 | return module; 43 | } 44 | 45 | static std::wstring getModuleFileName(HMODULE module) { 46 | const int bufsize = 4096; 47 | wchar_t path[bufsize]; 48 | int size = GetModuleFileNameW(module, path, bufsize); 49 | ASSERT(size != 0 && size != bufsize); 50 | return std::wstring(path); 51 | } 52 | 53 | static std::wstring dirname(const std::wstring &path) { 54 | std::wstring::size_type pos = path.find_last_of(L"\\/"); 55 | if (pos == std::wstring::npos) { 56 | return L""; 57 | } else { 58 | return path.substr(0, pos); 59 | } 60 | } 61 | 62 | static bool pathExists(const std::wstring &path) { 63 | return GetFileAttributesW(path.c_str()) != 0xFFFFFFFF; 64 | } 65 | 66 | std::wstring findAgentProgram() { 67 | std::wstring progDir = dirname(getModuleFileName(getCurrentModule())); 68 | std::wstring ret = progDir + (L"\\" AGENT_EXE); 69 | if (!pathExists(ret)) { 70 | throw LibWinptyException( 71 | WINPTY_ERROR_AGENT_EXE_MISSING, 72 | (L"agent executable does not exist: '" + ret + L"'").c_str()); 73 | } 74 | return ret; 75 | } 76 | -------------------------------------------------------------------------------- /src/libwinpty/AgentLocation.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef LIBWINPTY_AGENT_LOCATION_H 22 | #define LIBWINPTY_AGENT_LOCATION_H 23 | 24 | #include 25 | 26 | std::wstring findAgentProgram(); 27 | 28 | #endif // LIBWINPTY_AGENT_LOCATION_H 29 | -------------------------------------------------------------------------------- /src/libwinpty/LibWinptyException.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef LIB_WINPTY_EXCEPTION_H 22 | #define LIB_WINPTY_EXCEPTION_H 23 | 24 | #include "../include/winpty.h" 25 | 26 | #include "../shared/WinptyException.h" 27 | 28 | #include 29 | #include 30 | 31 | class LibWinptyException : public WinptyException { 32 | public: 33 | LibWinptyException(winpty_result_t code, const wchar_t *what) : 34 | m_code(code), m_what(std::make_shared(what)) {} 35 | 36 | winpty_result_t code() const WINPTY_NOEXCEPT { 37 | return m_code; 38 | } 39 | 40 | const wchar_t *what() const WINPTY_NOEXCEPT override { 41 | return m_what->c_str(); 42 | } 43 | 44 | std::shared_ptr whatSharedStr() const WINPTY_NOEXCEPT { 45 | return m_what; 46 | } 47 | 48 | private: 49 | winpty_result_t m_code; 50 | // Using a shared_ptr ensures that copying the object raises no exception. 51 | std::shared_ptr m_what; 52 | }; 53 | 54 | #endif // LIB_WINPTY_EXCEPTION_H 55 | -------------------------------------------------------------------------------- /src/libwinpty/WinptyInternal.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef LIBWINPTY_WINPTY_INTERNAL_H 22 | #define LIBWINPTY_WINPTY_INTERNAL_H 23 | 24 | #include 25 | #include 26 | 27 | #include "../include/winpty.h" 28 | 29 | #include "../shared/Mutex.h" 30 | #include "../shared/OwnedHandle.h" 31 | 32 | // The structures in this header are not intended to be accessed directly by 33 | // client programs. 34 | 35 | struct winpty_error_s { 36 | winpty_result_t code; 37 | const wchar_t *msgStatic; 38 | // Use a pointer to a std::shared_ptr so that the struct remains simple 39 | // enough to statically initialize, for the benefit of static error 40 | // objects like kOutOfMemory. 41 | std::shared_ptr *msgDynamic; 42 | }; 43 | 44 | struct winpty_config_s { 45 | uint64_t flags = 0; 46 | int cols = 80; 47 | int rows = 25; 48 | int mouseMode = WINPTY_MOUSE_MODE_AUTO; 49 | DWORD timeoutMs = 30000; 50 | }; 51 | 52 | struct winpty_s { 53 | Mutex mutex; 54 | OwnedHandle agentProcess; 55 | OwnedHandle controlPipe; 56 | DWORD agentTimeoutMs = 0; 57 | OwnedHandle ioEvent; 58 | std::wstring spawnDesktopName; 59 | std::wstring coninPipeName; 60 | std::wstring conoutPipeName; 61 | std::wstring conerrPipeName; 62 | }; 63 | 64 | struct winpty_spawn_config_s { 65 | uint64_t winptyFlags = 0; 66 | std::wstring appname; 67 | std::wstring cmdline; 68 | std::wstring cwd; 69 | std::wstring env; 70 | }; 71 | 72 | #endif // LIBWINPTY_WINPTY_INTERNAL_H 73 | -------------------------------------------------------------------------------- /src/libwinpty/subdir.mk: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011-2015 Ryan Prichard 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to 5 | # deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | # IN THE SOFTWARE. 20 | 21 | ALL_TARGETS += build/winpty.dll 22 | 23 | $(eval $(call def_mingw_target,libwinpty,-DCOMPILING_WINPTY_DLL)) 24 | 25 | LIBWINPTY_OBJECTS = \ 26 | build/libwinpty/libwinpty/AgentLocation.o \ 27 | build/libwinpty/libwinpty/winpty.o \ 28 | build/libwinpty/shared/BackgroundDesktop.o \ 29 | build/libwinpty/shared/Buffer.o \ 30 | build/libwinpty/shared/DebugClient.o \ 31 | build/libwinpty/shared/GenRandom.o \ 32 | build/libwinpty/shared/OwnedHandle.o \ 33 | build/libwinpty/shared/StringUtil.o \ 34 | build/libwinpty/shared/WindowsSecurity.o \ 35 | build/libwinpty/shared/WindowsVersion.o \ 36 | build/libwinpty/shared/WinptyAssert.o \ 37 | build/libwinpty/shared/WinptyException.o \ 38 | build/libwinpty/shared/WinptyVersion.o 39 | 40 | build/libwinpty/shared/WinptyVersion.o : build/gen/GenVersion.h 41 | 42 | build/winpty.dll : $(LIBWINPTY_OBJECTS) 43 | $(info Linking $@) 44 | @$(MINGW_CXX) $(MINGW_LDFLAGS) -shared -o $@ $^ -Wl,--out-implib,build/winpty.lib 45 | 46 | -include $(LIBWINPTY_OBJECTS:.o=.d) 47 | -------------------------------------------------------------------------------- /src/shared/AgentMsg.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_SHARED_AGENT_MSG_H 22 | #define WINPTY_SHARED_AGENT_MSG_H 23 | 24 | struct AgentMsg 25 | { 26 | enum Type { 27 | StartProcess, 28 | SetSize, 29 | GetConsoleProcessList, 30 | }; 31 | }; 32 | 33 | enum class StartProcessResult { 34 | CreateProcessFailed, 35 | ProcessCreated, 36 | }; 37 | 38 | #endif // WINPTY_SHARED_AGENT_MSG_H 39 | -------------------------------------------------------------------------------- /src/shared/BackgroundDesktop.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_SHARED_BACKGROUND_DESKTOP_H 22 | #define WINPTY_SHARED_BACKGROUND_DESKTOP_H 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include "WinptyException.h" 29 | 30 | class BackgroundDesktop { 31 | public: 32 | BackgroundDesktop(); 33 | ~BackgroundDesktop() { dispose(); } 34 | void dispose() WINPTY_NOEXCEPT; 35 | const std::wstring &desktopName() const { return m_newDesktopName; } 36 | 37 | BackgroundDesktop(const BackgroundDesktop &other) = delete; 38 | BackgroundDesktop &operator=(const BackgroundDesktop &other) = delete; 39 | 40 | // We can't default the move constructor and assignment operator with 41 | // MSVC 2013. We *could* if we required at least MSVC 2015 to build. 42 | 43 | BackgroundDesktop(BackgroundDesktop &&other) : 44 | m_originalStation(other.m_originalStation), 45 | m_newStation(other.m_newStation), 46 | m_newDesktop(other.m_newDesktop), 47 | m_newDesktopName(std::move(other.m_newDesktopName)) { 48 | other.m_originalStation = nullptr; 49 | other.m_newStation = nullptr; 50 | other.m_newDesktop = nullptr; 51 | } 52 | BackgroundDesktop &operator=(BackgroundDesktop &&other) { 53 | dispose(); 54 | m_originalStation = other.m_originalStation; 55 | m_newStation = other.m_newStation; 56 | m_newDesktop = other.m_newDesktop; 57 | m_newDesktopName = std::move(other.m_newDesktopName); 58 | other.m_originalStation = nullptr; 59 | other.m_newStation = nullptr; 60 | other.m_newDesktop = nullptr; 61 | return *this; 62 | } 63 | 64 | private: 65 | HWINSTA m_originalStation = nullptr; 66 | HWINSTA m_newStation = nullptr; 67 | HDESK m_newDesktop = nullptr; 68 | std::wstring m_newDesktopName; 69 | }; 70 | 71 | std::wstring getCurrentDesktopName(); 72 | 73 | #endif // WINPTY_SHARED_BACKGROUND_DESKTOP_H 74 | -------------------------------------------------------------------------------- /src/shared/Buffer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_SHARED_BUFFER_H 22 | #define WINPTY_SHARED_BUFFER_H 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "WinptyException.h" 33 | 34 | class WriteBuffer { 35 | private: 36 | std::vector m_buf; 37 | 38 | public: 39 | WriteBuffer() {} 40 | 41 | template void putRawValue(const T &t) { 42 | putRawData(&t, sizeof(t)); 43 | } 44 | template void replaceRawValue(size_t pos, const T &t) { 45 | replaceRawData(pos, &t, sizeof(t)); 46 | } 47 | 48 | void putRawData(const void *data, size_t len); 49 | void replaceRawData(size_t pos, const void *data, size_t len); 50 | void putInt32(int32_t i); 51 | void putInt64(int64_t i); 52 | void putWString(const wchar_t *str, size_t len); 53 | void putWString(const wchar_t *str) { putWString(str, wcslen(str)); } 54 | void putWString(const std::wstring &str) { putWString(str.data(), str.size()); } 55 | std::vector &buf() { return m_buf; } 56 | 57 | // MSVC 2013 does not generate these automatically, so help it out. 58 | WriteBuffer(WriteBuffer &&other) : m_buf(std::move(other.m_buf)) {} 59 | WriteBuffer &operator=(WriteBuffer &&other) { 60 | m_buf = std::move(other.m_buf); 61 | return *this; 62 | } 63 | }; 64 | 65 | class ReadBuffer { 66 | public: 67 | class DecodeError : public WinptyException { 68 | virtual const wchar_t *what() const WINPTY_NOEXCEPT override { 69 | return L"DecodeError: RPC message decoding error"; 70 | } 71 | }; 72 | 73 | private: 74 | std::vector m_buf; 75 | size_t m_off = 0; 76 | 77 | public: 78 | explicit ReadBuffer(std::vector &&buf) : m_buf(std::move(buf)) {} 79 | 80 | template T getRawValue() { 81 | T ret = {}; 82 | getRawData(&ret, sizeof(ret)); 83 | return ret; 84 | } 85 | 86 | void getRawData(void *data, size_t len); 87 | int32_t getInt32(); 88 | int64_t getInt64(); 89 | std::wstring getWString(); 90 | void assertEof(); 91 | 92 | // MSVC 2013 does not generate these automatically, so help it out. 93 | ReadBuffer(ReadBuffer &&other) : 94 | m_buf(std::move(other.m_buf)), m_off(other.m_off) {} 95 | ReadBuffer &operator=(ReadBuffer &&other) { 96 | m_buf = std::move(other.m_buf); 97 | m_off = other.m_off; 98 | return *this; 99 | } 100 | }; 101 | 102 | #endif // WINPTY_SHARED_BUFFER_H 103 | -------------------------------------------------------------------------------- /src/shared/DebugClient.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef DEBUGCLIENT_H 22 | #define DEBUGCLIENT_H 23 | 24 | #include "winpty_snprintf.h" 25 | 26 | bool isTracingEnabled(); 27 | bool hasDebugFlag(const char *flag); 28 | void trace(const char *format, ...) WINPTY_SNPRINTF_FORMAT(1, 2); 29 | 30 | // This macro calls trace without evaluating the arguments. 31 | #define TRACE(format, ...) \ 32 | do { \ 33 | if (isTracingEnabled()) { \ 34 | trace((format), ## __VA_ARGS__); \ 35 | } \ 36 | } while (false) 37 | 38 | #endif // DEBUGCLIENT_H 39 | -------------------------------------------------------------------------------- /src/shared/GenRandom.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_GEN_RANDOM_H 22 | #define WINPTY_GEN_RANDOM_H 23 | 24 | // The original MinGW requires that we include wincrypt.h. With MinGW-w64 and 25 | // MSVC, including windows.h is sufficient. 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include "OsModule.h" 32 | 33 | class GenRandom { 34 | typedef BOOLEAN WINAPI RtlGenRandom_t(PVOID, ULONG); 35 | 36 | OsModule m_advapi32; 37 | RtlGenRandom_t *m_rtlGenRandom = nullptr; 38 | bool m_cryptProvIsValid = false; 39 | HCRYPTPROV m_cryptProv = 0; 40 | 41 | public: 42 | GenRandom(); 43 | ~GenRandom(); 44 | bool fillBuffer(void *buffer, size_t size); 45 | std::string randomBytes(size_t numBytes); 46 | std::wstring randomHexString(size_t numBytes); 47 | std::wstring uniqueName(); 48 | 49 | // Return true if the crypto context was successfully initialized. 50 | bool valid() const { 51 | return m_rtlGenRandom != nullptr || m_cryptProvIsValid; 52 | } 53 | }; 54 | 55 | #endif // WINPTY_GEN_RANDOM_H 56 | -------------------------------------------------------------------------------- /src/shared/GetCommitHash.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM -- Echo the git commit hash. If git isn't available for some reason, 4 | REM -- output nothing instead. 5 | 6 | git rev-parse HEAD >NUL 2>NUL && ( 7 | git rev-parse HEAD 8 | ) || ( 9 | echo none 10 | ) 11 | 12 | REM -- Set ERRORLEVEL to 0 using this cryptic syntax. 13 | (call ) 14 | -------------------------------------------------------------------------------- /src/shared/Mutex.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | // Recent 4.x MinGW and MinGW-w64 gcc compilers lack std::mutex and 22 | // std::lock_guard. I have a 5.2.0 MinGW-w64 compiler packaged through MSYS2 23 | // that *is* new enough, but that's one compiler against several deficient 24 | // ones. Wrap CRITICAL_SECTION instead. 25 | 26 | #ifndef WINPTY_SHARED_MUTEX_H 27 | #define WINPTY_SHARED_MUTEX_H 28 | 29 | #include 30 | 31 | class Mutex { 32 | CRITICAL_SECTION m_mutex; 33 | public: 34 | Mutex() { InitializeCriticalSection(&m_mutex); } 35 | ~Mutex() { DeleteCriticalSection(&m_mutex); } 36 | void lock() { EnterCriticalSection(&m_mutex); } 37 | void unlock() { LeaveCriticalSection(&m_mutex); } 38 | 39 | Mutex(const Mutex &other) = delete; 40 | Mutex &operator=(const Mutex &other) = delete; 41 | }; 42 | 43 | template 44 | class LockGuard { 45 | T &m_lock; 46 | public: 47 | LockGuard(T &lock) : m_lock(lock) { m_lock.lock(); } 48 | ~LockGuard() { m_lock.unlock(); } 49 | 50 | LockGuard(const LockGuard &other) = delete; 51 | LockGuard &operator=(const LockGuard &other) = delete; 52 | }; 53 | 54 | #endif // WINPTY_SHARED_MUTEX_H 55 | -------------------------------------------------------------------------------- /src/shared/OsModule.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_SHARED_OS_MODULE_H 22 | #define WINPTY_SHARED_OS_MODULE_H 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include "DebugClient.h" 29 | #include "WinptyAssert.h" 30 | #include "WinptyException.h" 31 | 32 | class OsModule { 33 | HMODULE m_module; 34 | public: 35 | enum class LoadErrorBehavior { Abort, Throw }; 36 | OsModule(const wchar_t *fileName, 37 | LoadErrorBehavior behavior=LoadErrorBehavior::Abort) { 38 | m_module = LoadLibraryW(fileName); 39 | if (behavior == LoadErrorBehavior::Abort) { 40 | ASSERT(m_module != NULL); 41 | } else { 42 | if (m_module == nullptr) { 43 | const auto err = GetLastError(); 44 | throwWindowsError( 45 | (L"LoadLibraryW error: " + std::wstring(fileName)).c_str(), 46 | err); 47 | } 48 | } 49 | } 50 | ~OsModule() { 51 | FreeLibrary(m_module); 52 | } 53 | HMODULE handle() const { return m_module; } 54 | FARPROC proc(const char *funcName) { 55 | FARPROC ret = GetProcAddress(m_module, funcName); 56 | if (ret == NULL) { 57 | trace("GetProcAddress: %s is missing", funcName); 58 | } 59 | return ret; 60 | } 61 | }; 62 | 63 | #endif // WINPTY_SHARED_OS_MODULE_H 64 | -------------------------------------------------------------------------------- /src/shared/OwnedHandle.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #include "OwnedHandle.h" 22 | 23 | #include "DebugClient.h" 24 | #include "WinptyException.h" 25 | 26 | void OwnedHandle::dispose(bool nothrow) { 27 | if (m_h != nullptr && m_h != INVALID_HANDLE_VALUE) { 28 | if (!CloseHandle(m_h)) { 29 | trace("CloseHandle(%p) failed", m_h); 30 | if (!nothrow) { 31 | throwWindowsError(L"CloseHandle failed"); 32 | } 33 | } 34 | } 35 | m_h = nullptr; 36 | } 37 | -------------------------------------------------------------------------------- /src/shared/OwnedHandle.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_SHARED_OWNED_HANDLE_H 22 | #define WINPTY_SHARED_OWNED_HANDLE_H 23 | 24 | #include 25 | 26 | class OwnedHandle { 27 | HANDLE m_h; 28 | public: 29 | OwnedHandle() : m_h(nullptr) {} 30 | explicit OwnedHandle(HANDLE h) : m_h(h) {} 31 | ~OwnedHandle() { dispose(true); } 32 | void dispose(bool nothrow=false); 33 | HANDLE get() const { return m_h; } 34 | HANDLE release() { HANDLE ret = m_h; m_h = nullptr; return ret; } 35 | OwnedHandle(const OwnedHandle &other) = delete; 36 | OwnedHandle(OwnedHandle &&other) : m_h(other.release()) {} 37 | OwnedHandle &operator=(const OwnedHandle &other) = delete; 38 | OwnedHandle &operator=(OwnedHandle &&other) { 39 | dispose(); 40 | m_h = other.release(); 41 | return *this; 42 | } 43 | }; 44 | 45 | #endif // WINPTY_SHARED_OWNED_HANDLE_H 46 | -------------------------------------------------------------------------------- /src/shared/PrecompiledHeader.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_PRECOMPILED_HEADER_H 22 | #define WINPTY_PRECOMPILED_HEADER_H 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #endif // WINPTY_PRECOMPILED_HEADER_H 44 | -------------------------------------------------------------------------------- /src/shared/StringUtil.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #include "StringUtil.h" 22 | 23 | #include 24 | 25 | #include "WinptyAssert.h" 26 | 27 | // Workaround. MinGW (from mingw.org) does not have wcsnlen. MinGW-w64 *does* 28 | // have wcsnlen, but use this function for consistency. 29 | size_t winpty_wcsnlen(const wchar_t *s, size_t maxlen) { 30 | ASSERT(s != NULL); 31 | for (size_t i = 0; i < maxlen; ++i) { 32 | if (s[i] == L'\0') { 33 | return i; 34 | } 35 | } 36 | return maxlen; 37 | } 38 | 39 | std::string utf8FromWide(const std::wstring &input) { 40 | int mblen = WideCharToMultiByte( 41 | CP_UTF8, 0, 42 | input.data(), input.size(), 43 | NULL, 0, NULL, NULL); 44 | if (mblen <= 0) { 45 | return std::string(); 46 | } 47 | std::vector tmp(mblen); 48 | int mblen2 = WideCharToMultiByte( 49 | CP_UTF8, 0, 50 | input.data(), input.size(), 51 | tmp.data(), tmp.size(), 52 | NULL, NULL); 53 | ASSERT(mblen2 == mblen); 54 | return std::string(tmp.data(), tmp.size()); 55 | } 56 | -------------------------------------------------------------------------------- /src/shared/StringUtil.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_SHARED_STRING_UTIL_H 22 | #define WINPTY_SHARED_STRING_UTIL_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "WinptyAssert.h" 33 | 34 | size_t winpty_wcsnlen(const wchar_t *s, size_t maxlen); 35 | std::string utf8FromWide(const std::wstring &input); 36 | 37 | // Return a vector containing each character in the string. 38 | template 39 | std::vector vectorFromString(const std::basic_string &str) { 40 | return std::vector(str.begin(), str.end()); 41 | } 42 | 43 | // Return a vector containing each character in the string, followed by a 44 | // NUL terminator. 45 | template 46 | std::vector vectorWithNulFromString(const std::basic_string &str) { 47 | std::vector ret; 48 | ret.reserve(str.size() + 1); 49 | ret.insert(ret.begin(), str.begin(), str.end()); 50 | ret.push_back('\0'); 51 | return ret; 52 | } 53 | 54 | // A safer(?) version of wcsncpy that is accepted by MSVC's /SDL mode. 55 | template 56 | wchar_t *winpty_wcsncpy(wchar_t (&d)[N], const wchar_t *s) { 57 | ASSERT(s != nullptr); 58 | size_t i = 0; 59 | for (; i < N; ++i) { 60 | if (s[i] == L'\0') { 61 | break; 62 | } 63 | d[i] = s[i]; 64 | } 65 | for (; i < N; ++i) { 66 | d[i] = L'\0'; 67 | } 68 | return d; 69 | } 70 | 71 | // Like wcsncpy, but ensure that the destination buffer is NUL-terminated. 72 | template 73 | wchar_t *winpty_wcsncpy_nul(wchar_t (&d)[N], const wchar_t *s) { 74 | static_assert(N > 0, "array cannot be 0-size"); 75 | winpty_wcsncpy(d, s); 76 | d[N - 1] = L'\0'; 77 | return d; 78 | } 79 | 80 | #endif // WINPTY_SHARED_STRING_UTIL_H 81 | -------------------------------------------------------------------------------- /src/shared/TimeMeasurement.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | // Convenience header library for using the high-resolution performance counter 22 | // to measure how long some process takes. 23 | 24 | #ifndef TIME_MEASUREMENT_H 25 | #define TIME_MEASUREMENT_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | class TimeMeasurement { 32 | public: 33 | TimeMeasurement() { 34 | static double freq = static_cast(getFrequency()); 35 | m_freq = freq; 36 | m_start = value(); 37 | } 38 | 39 | double elapsed() { 40 | uint64_t elapsedTicks = value() - m_start; 41 | return static_cast(elapsedTicks) / m_freq; 42 | } 43 | 44 | private: 45 | uint64_t getFrequency() { 46 | LARGE_INTEGER freq; 47 | BOOL success = QueryPerformanceFrequency(&freq); 48 | assert(success && "QueryPerformanceFrequency failed"); 49 | return freq.QuadPart; 50 | } 51 | 52 | uint64_t value() { 53 | LARGE_INTEGER ret; 54 | BOOL success = QueryPerformanceCounter(&ret); 55 | assert(success && "QueryPerformanceCounter failed"); 56 | return ret.QuadPart; 57 | } 58 | 59 | uint64_t m_start; 60 | double m_freq; 61 | }; 62 | 63 | #endif // TIME_MEASUREMENT_H 64 | -------------------------------------------------------------------------------- /src/shared/UnixCtrlChars.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef UNIX_CTRL_CHARS_H 22 | #define UNIX_CTRL_CHARS_H 23 | 24 | inline char decodeUnixCtrlChar(char ch) { 25 | const char ctrlKeys[] = { 26 | /* 0x00 */ '@', /* 0x01 */ 'A', /* 0x02 */ 'B', /* 0x03 */ 'C', 27 | /* 0x04 */ 'D', /* 0x05 */ 'E', /* 0x06 */ 'F', /* 0x07 */ 'G', 28 | /* 0x08 */ 'H', /* 0x09 */ 'I', /* 0x0A */ 'J', /* 0x0B */ 'K', 29 | /* 0x0C */ 'L', /* 0x0D */ 'M', /* 0x0E */ 'N', /* 0x0F */ 'O', 30 | /* 0x10 */ 'P', /* 0x11 */ 'Q', /* 0x12 */ 'R', /* 0x13 */ 'S', 31 | /* 0x14 */ 'T', /* 0x15 */ 'U', /* 0x16 */ 'V', /* 0x17 */ 'W', 32 | /* 0x18 */ 'X', /* 0x19 */ 'Y', /* 0x1A */ 'Z', /* 0x1B */ '[', 33 | /* 0x1C */ '\\', /* 0x1D */ ']', /* 0x1E */ '^', /* 0x1F */ '_', 34 | }; 35 | unsigned char uch = ch; 36 | if (uch < 32) { 37 | return ctrlKeys[uch]; 38 | } else if (uch == 127) { 39 | return '?'; 40 | } else { 41 | return '\0'; 42 | } 43 | } 44 | 45 | #endif // UNIX_CTRL_CHARS_H 46 | -------------------------------------------------------------------------------- /src/shared/UpdateGenVersion.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem -- Echo the git commit hash. If git isn't available for some reason, 4 | rem -- output nothing instead. 5 | 6 | mkdir ..\gen 2>nul 7 | 8 | set /p VERSION=<..\..\VERSION.txt 9 | set COMMIT=%1 10 | 11 | echo // AUTO-GENERATED BY %0 %*>..\gen\GenVersion.h 12 | echo const char GenVersion_Version[] = "%VERSION%";>>..\gen\GenVersion.h 13 | echo const char GenVersion_Commit[] = "%COMMIT%";>>..\gen\GenVersion.h 14 | 15 | rem -- The winpty.gyp file expects the script to output the include directory, 16 | rem -- relative to src. 17 | echo gen 18 | 19 | rem -- Set ERRORLEVEL to 0 using this cryptic syntax. 20 | (call ) 21 | -------------------------------------------------------------------------------- /src/shared/WindowsSecurity.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_WINDOWS_SECURITY_H 22 | #define WINPTY_WINDOWS_SECURITY_H 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | // PSID and PSECURITY_DESCRIPTOR are both pointers to void, but we want 33 | // Sid and SecurityDescriptor to be different types. 34 | struct SidTag { typedef PSID type; }; 35 | struct AclTag { typedef PACL type; }; 36 | struct SecurityDescriptorTag { typedef PSECURITY_DESCRIPTOR type; }; 37 | 38 | template 39 | class SecurityItem { 40 | public: 41 | struct Impl { 42 | virtual ~Impl() {} 43 | }; 44 | 45 | private: 46 | typedef typename T::type P; 47 | P m_v; 48 | std::unique_ptr m_pimpl; 49 | 50 | public: 51 | P get() const { return m_v; } 52 | operator bool() const { return m_v != nullptr; } 53 | 54 | SecurityItem() : m_v(nullptr) {} 55 | SecurityItem(P v, std::unique_ptr &&pimpl) : 56 | m_v(v), m_pimpl(std::move(pimpl)) {} 57 | SecurityItem(SecurityItem &&other) : 58 | m_v(other.m_v), m_pimpl(std::move(other.m_pimpl)) { 59 | other.m_v = nullptr; 60 | } 61 | SecurityItem &operator=(SecurityItem &&other) { 62 | m_v = other.m_v; 63 | other.m_v = nullptr; 64 | m_pimpl = std::move(other.m_pimpl); 65 | return *this; 66 | } 67 | }; 68 | 69 | typedef SecurityItem Sid; 70 | typedef SecurityItem Acl; 71 | typedef SecurityItem SecurityDescriptor; 72 | 73 | Sid getOwnerSid(); 74 | Sid wellKnownSid( 75 | const wchar_t *debuggingName, 76 | SID_IDENTIFIER_AUTHORITY authority, 77 | BYTE authorityCount, 78 | DWORD subAuthority0=0, 79 | DWORD subAuthority1=0); 80 | Sid builtinAdminsSid(); 81 | Sid localSystemSid(); 82 | Sid everyoneSid(); 83 | 84 | SecurityDescriptor createPipeSecurityDescriptorOwnerFullControl(); 85 | SecurityDescriptor createPipeSecurityDescriptorOwnerFullControlEveryoneWrite(); 86 | SecurityDescriptor getObjectSecurityDescriptor(HANDLE handle); 87 | 88 | std::wstring sidToString(PSID sid); 89 | Sid stringToSid(const std::wstring &str); 90 | SecurityDescriptor stringToSd(const std::wstring &str); 91 | std::wstring sdToString(PSECURITY_DESCRIPTOR sd); 92 | 93 | DWORD rejectRemoteClientsPipeFlag(); 94 | 95 | enum class GetNamedPipeClientProcessId_Result { 96 | Success, 97 | Failure, 98 | UnsupportedOs, 99 | }; 100 | 101 | std::tuple 102 | getNamedPipeClientProcessId(HANDLE serverPipe); 103 | 104 | #endif // WINPTY_WINDOWS_SECURITY_H 105 | -------------------------------------------------------------------------------- /src/shared/WindowsVersion.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_SHARED_WINDOWS_VERSION_H 22 | #define WINPTY_SHARED_WINDOWS_VERSION_H 23 | 24 | bool isAtLeastWindowsVista(); 25 | bool isAtLeastWindows7(); 26 | bool isAtLeastWindows8(); 27 | void dumpWindowsVersion(); 28 | 29 | #endif // WINPTY_SHARED_WINDOWS_VERSION_H 30 | -------------------------------------------------------------------------------- /src/shared/WinptyAssert.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #include "WinptyAssert.h" 22 | 23 | #include 24 | #include 25 | 26 | #include "DebugClient.h" 27 | 28 | void assertTrace(const char *file, int line, const char *cond) { 29 | trace("Assertion failed: %s, file %s, line %d", 30 | cond, file, line); 31 | } 32 | 33 | #ifdef WINPTY_AGENT_ASSERT 34 | 35 | void agentShutdown() { 36 | HWND hwnd = GetConsoleWindow(); 37 | if (hwnd != NULL) { 38 | PostMessage(hwnd, WM_CLOSE, 0, 0); 39 | Sleep(30000); 40 | trace("Agent shutdown: WM_CLOSE did not end agent process"); 41 | } else { 42 | trace("Agent shutdown: GetConsoleWindow() is NULL"); 43 | } 44 | // abort() prints a message to the console, and if it is frozen, then the 45 | // process would hang, so instead use exit(). (We shouldn't ever get here, 46 | // though, because the WM_CLOSE message should have ended this process.) 47 | exit(1); 48 | } 49 | 50 | void agentAssertFail(const char *file, int line, const char *cond) { 51 | assertTrace(file, line, cond); 52 | agentShutdown(); 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/shared/WinptyAssert.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_ASSERT_H 22 | #define WINPTY_ASSERT_H 23 | 24 | #ifdef WINPTY_AGENT_ASSERT 25 | 26 | void agentShutdown(); 27 | void agentAssertFail(const char *file, int line, const char *cond); 28 | 29 | // Calling the standard assert() function does not work in the agent because 30 | // the error message would be printed to the console, and the only way the 31 | // user can see the console is via a working agent! Moreover, the console may 32 | // be frozen, so attempting to write to it would block forever. This custom 33 | // assert function instead sends the message to the DebugServer, then attempts 34 | // to close the console, then quietly exits. 35 | #define ASSERT(cond) \ 36 | do { \ 37 | if (!(cond)) { \ 38 | agentAssertFail(__FILE__, __LINE__, #cond); \ 39 | } \ 40 | } while(0) 41 | 42 | #else 43 | 44 | void assertTrace(const char *file, int line, const char *cond); 45 | 46 | // In the other targets, log the assert failure to the debugserver, then fail 47 | // using the ordinary assert mechanism. In case assert is compiled out, fail 48 | // using abort. The amount of code inlined is unfortunate, but asserts aren't 49 | // used much outside the agent. 50 | #include 51 | #include 52 | #define ASSERT_CONDITION(cond) (false && (cond)) 53 | #define ASSERT(cond) \ 54 | do { \ 55 | if (!(cond)) { \ 56 | assertTrace(__FILE__, __LINE__, #cond); \ 57 | assert(ASSERT_CONDITION(#cond)); \ 58 | abort(); \ 59 | } \ 60 | } while(0) 61 | 62 | #endif 63 | 64 | #endif // WINPTY_ASSERT_H 65 | -------------------------------------------------------------------------------- /src/shared/WinptyException.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #include "WinptyException.h" 22 | 23 | #include 24 | #include 25 | 26 | #include "StringBuilder.h" 27 | 28 | namespace { 29 | 30 | class ExceptionImpl : public WinptyException { 31 | public: 32 | ExceptionImpl(const wchar_t *what) : 33 | m_what(std::make_shared(what)) {} 34 | virtual const wchar_t *what() const WINPTY_NOEXCEPT override { 35 | return m_what->c_str(); 36 | } 37 | private: 38 | // Using a shared_ptr ensures that copying the object raises no exception. 39 | std::shared_ptr m_what; 40 | }; 41 | 42 | } // anonymous namespace 43 | 44 | void throwWinptyException(const wchar_t *what) { 45 | throw ExceptionImpl(what); 46 | } 47 | 48 | void throwWindowsError(const wchar_t *prefix, DWORD errorCode) { 49 | WStringBuilder sb(64); 50 | if (prefix != nullptr) { 51 | sb << prefix << L": "; 52 | } 53 | // It might make sense to use FormatMessage here, but IIRC, its API is hard 54 | // to figure out. 55 | sb << L"Windows error " << errorCode; 56 | throwWinptyException(sb.c_str()); 57 | } 58 | -------------------------------------------------------------------------------- /src/shared/WinptyException.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_EXCEPTION_H 22 | #define WINPTY_EXCEPTION_H 23 | 24 | #include 25 | 26 | #if defined(__GNUC__) 27 | #define WINPTY_NOEXCEPT noexcept 28 | #elif defined(_MSC_VER) && _MSC_VER >= 1900 29 | #define WINPTY_NOEXCEPT noexcept 30 | #else 31 | #define WINPTY_NOEXCEPT 32 | #endif 33 | 34 | class WinptyException { 35 | public: 36 | virtual const wchar_t *what() const WINPTY_NOEXCEPT = 0; 37 | virtual ~WinptyException() {} 38 | }; 39 | 40 | void throwWinptyException(const wchar_t *what); 41 | void throwWindowsError(const wchar_t *prefix, DWORD error=GetLastError()); 42 | 43 | #endif // WINPTY_EXCEPTION_H 44 | -------------------------------------------------------------------------------- /src/shared/WinptyVersion.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #include "WinptyVersion.h" 22 | 23 | #include 24 | #include 25 | 26 | #include "DebugClient.h" 27 | 28 | // This header is auto-generated by either the Makefile (Unix) or 29 | // UpdateGenVersion.bat (gyp). It is placed in a 'gen' directory, which is 30 | // added to the search path. 31 | #include "GenVersion.h" 32 | 33 | void dumpVersionToStdout() { 34 | printf("winpty version %s\n", GenVersion_Version); 35 | printf("commit %s\n", GenVersion_Commit); 36 | } 37 | 38 | void dumpVersionToTrace() { 39 | trace("winpty version %s (commit %s)", 40 | GenVersion_Version, 41 | GenVersion_Commit); 42 | } 43 | -------------------------------------------------------------------------------- /src/shared/WinptyVersion.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef WINPTY_VERSION_H 22 | #define WINPTY_VERSION_H 23 | 24 | void dumpVersionToStdout(); 25 | void dumpVersionToTrace(); 26 | 27 | #endif // WINPTY_VERSION_H 28 | -------------------------------------------------------------------------------- /src/subdir.mk: -------------------------------------------------------------------------------- 1 | include src/agent/subdir.mk 2 | include src/debugserver/subdir.mk 3 | include src/libwinpty/subdir.mk 4 | include src/tests/subdir.mk 5 | include src/unix-adapter/subdir.mk 6 | -------------------------------------------------------------------------------- /src/tests/subdir.mk: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015 Ryan Prichard 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to 5 | # deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | # IN THE SOFTWARE. 20 | 21 | build/%.exe : src/tests/%.cc build/winpty.dll 22 | $(info Building $@) 23 | @$(MINGW_CXX) $(MINGW_CXXFLAGS) $(MINGW_LDFLAGS) -o $@ $^ 24 | 25 | TEST_PROGRAMS = \ 26 | build/trivial_test.exe 27 | 28 | -include $(TEST_PROGRAMS:.exe=.d) 29 | -------------------------------------------------------------------------------- /src/unix-adapter/InputHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef UNIX_ADAPTER_INPUT_HANDLER_H 22 | #define UNIX_ADAPTER_INPUT_HANDLER_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "WakeupFd.h" 29 | 30 | // Connect a Cygwin blocking fd to winpty CONIN. 31 | class InputHandler { 32 | public: 33 | InputHandler(HANDLE conin, int inputfd, WakeupFd &completionWakeup); 34 | ~InputHandler() { shutdown(); } 35 | bool isComplete() { return m_threadCompleted; } 36 | void startShutdown() { m_shouldShutdown = 1; m_wakeup.set(); } 37 | void shutdown(); 38 | 39 | private: 40 | static void *threadProcS(void *pvthis) { 41 | reinterpret_cast(pvthis)->threadProc(); 42 | return NULL; 43 | } 44 | void threadProc(); 45 | 46 | HANDLE m_conin; 47 | int m_inputfd; 48 | pthread_t m_thread; 49 | WakeupFd &m_completionWakeup; 50 | WakeupFd m_wakeup; 51 | bool m_threadHasBeenJoined; 52 | volatile sig_atomic_t m_shouldShutdown; 53 | volatile sig_atomic_t m_threadCompleted; 54 | }; 55 | 56 | #endif // UNIX_ADAPTER_INPUT_HANDLER_H 57 | -------------------------------------------------------------------------------- /src/unix-adapter/OutputHandler.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #include "OutputHandler.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include "../shared/DebugClient.h" 32 | #include "Util.h" 33 | #include "WakeupFd.h" 34 | 35 | OutputHandler::OutputHandler( 36 | HANDLE conout, int outputfd, WakeupFd &completionWakeup) : 37 | m_conout(conout), 38 | m_outputfd(outputfd), 39 | m_completionWakeup(completionWakeup), 40 | m_threadHasBeenJoined(false), 41 | m_threadCompleted(0) 42 | { 43 | pthread_create(&m_thread, NULL, OutputHandler::threadProcS, this); 44 | } 45 | 46 | void OutputHandler::shutdown() { 47 | if (!m_threadHasBeenJoined) { 48 | int ret = pthread_join(m_thread, NULL); 49 | assert(ret == 0 && "pthread_join failed"); 50 | m_threadHasBeenJoined = true; 51 | } 52 | } 53 | 54 | void OutputHandler::threadProc() { 55 | std::vector buffer(4096); 56 | while (true) { 57 | DWORD numRead = 0; 58 | BOOL ret = ReadFile(m_conout, 59 | &buffer[0], buffer.size(), 60 | &numRead, NULL); 61 | if (!ret || numRead == 0) { 62 | if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { 63 | trace("OutputHandler: pipe closed: numRead=%u", 64 | static_cast(numRead)); 65 | } else { 66 | trace("OutputHandler: read failed: " 67 | "ret=%d lastError=0x%x numRead=%u", 68 | ret, 69 | static_cast(GetLastError()), 70 | static_cast(numRead)); 71 | } 72 | break; 73 | } 74 | if (!writeAll(m_outputfd, &buffer[0], numRead)) { 75 | break; 76 | } 77 | } 78 | m_threadCompleted = 1; 79 | m_completionWakeup.set(); 80 | } 81 | -------------------------------------------------------------------------------- /src/unix-adapter/OutputHandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef UNIX_ADAPTER_OUTPUT_HANDLER_H 22 | #define UNIX_ADAPTER_OUTPUT_HANDLER_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "WakeupFd.h" 29 | 30 | // Connect winpty CONOUT/CONERR to a Cygwin blocking fd. 31 | class OutputHandler { 32 | public: 33 | OutputHandler(HANDLE conout, int outputfd, WakeupFd &completionWakeup); 34 | ~OutputHandler() { shutdown(); } 35 | bool isComplete() { return m_threadCompleted; } 36 | void shutdown(); 37 | 38 | private: 39 | static void *threadProcS(void *pvthis) { 40 | reinterpret_cast(pvthis)->threadProc(); 41 | return NULL; 42 | } 43 | void threadProc(); 44 | 45 | HANDLE m_conout; 46 | int m_outputfd; 47 | pthread_t m_thread; 48 | WakeupFd &m_completionWakeup; 49 | bool m_threadHasBeenJoined; 50 | volatile sig_atomic_t m_threadCompleted; 51 | }; 52 | 53 | #endif // UNIX_ADAPTER_OUTPUT_HANDLER_H 54 | -------------------------------------------------------------------------------- /src/unix-adapter/Util.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #include "Util.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "../shared/DebugClient.h" 30 | 31 | // Write the entire buffer, restarting it as necessary. 32 | bool writeAll(int fd, const void *buffer, size_t size) { 33 | size_t written = 0; 34 | while (written < size) { 35 | int ret = write(fd, 36 | reinterpret_cast(buffer) + written, 37 | size - written); 38 | if (ret == -1 && errno == EINTR) { 39 | continue; 40 | } 41 | if (ret <= 0) { 42 | trace("write failed: " 43 | "fd=%d errno=%d size=%u written=%d ret=%d", 44 | fd, 45 | errno, 46 | static_cast(size), 47 | static_cast(written), 48 | ret); 49 | return false; 50 | } 51 | assert(static_cast(ret) <= size - written); 52 | written += ret; 53 | } 54 | assert(written == size); 55 | return true; 56 | } 57 | 58 | bool writeStr(int fd, const char *str) { 59 | return writeAll(fd, str, strlen(str)); 60 | } 61 | 62 | void selectWrapper(const char *diagName, int nfds, fd_set *readfds) { 63 | int ret = select(nfds, readfds, NULL, NULL, NULL); 64 | if (ret < 0) { 65 | if (errno == EINTR) { 66 | FD_ZERO(readfds); 67 | return; 68 | } 69 | #ifdef WINPTY_TARGET_MSYS1 70 | // The select system call sometimes fails with EAGAIN instead of EINTR. 71 | // This apparantly only happens with the old Cygwin fork "MSYS" used in 72 | // the mingw.org project. select is not supposed to fail with EAGAIN, 73 | // and EAGAIN does not make much sense as an error code. (The whole 74 | // point of select is to block.) 75 | if (errno == EAGAIN) { 76 | trace("%s select returned EAGAIN: interpreting like EINTR", 77 | diagName); 78 | FD_ZERO(readfds); 79 | return; 80 | } 81 | #endif 82 | fprintf(stderr, "Internal error: %s select failed: " 83 | "error %d", diagName, errno); 84 | abort(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/unix-adapter/Util.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef UNIX_ADAPTER_UTIL_H 22 | #define UNIX_ADAPTER_UTIL_H 23 | 24 | #include 25 | #include 26 | 27 | bool writeAll(int fd, const void *buffer, size_t size); 28 | bool writeStr(int fd, const char *str); 29 | void selectWrapper(const char *diagName, int nfds, fd_set *readfds); 30 | 31 | #endif // UNIX_ADAPTER_UTIL_H 32 | -------------------------------------------------------------------------------- /src/unix-adapter/WakeupFd.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #include "WakeupFd.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | static void setFdNonBlock(int fd) { 30 | int status = fcntl(fd, F_GETFL); 31 | fcntl(fd, F_SETFL, status | O_NONBLOCK); 32 | } 33 | 34 | WakeupFd::WakeupFd() { 35 | int pipeFd[2]; 36 | if (pipe(pipeFd) != 0) { 37 | perror("Could not create internal wakeup pipe"); 38 | abort(); 39 | } 40 | m_pipeReadFd = pipeFd[0]; 41 | m_pipeWriteFd = pipeFd[1]; 42 | setFdNonBlock(m_pipeReadFd); 43 | setFdNonBlock(m_pipeWriteFd); 44 | } 45 | 46 | WakeupFd::~WakeupFd() { 47 | close(m_pipeReadFd); 48 | close(m_pipeWriteFd); 49 | } 50 | 51 | void WakeupFd::set() { 52 | char dummy = 0; 53 | int ret; 54 | do { 55 | ret = write(m_pipeWriteFd, &dummy, 1); 56 | } while (ret < 0 && errno == EINTR); 57 | } 58 | 59 | void WakeupFd::reset() { 60 | char tmpBuf[256]; 61 | while (true) { 62 | int amount = read(m_pipeReadFd, tmpBuf, sizeof(tmpBuf)); 63 | if (amount < 0 && errno == EAGAIN) { 64 | break; 65 | } else if (amount <= 0) { 66 | perror("error reading from internal wakeup pipe"); 67 | abort(); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/unix-adapter/WakeupFd.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Ryan Prichard 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to 5 | // deal in the Software without restriction, including without limitation the 6 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | // sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | 21 | #ifndef UNIX_ADAPTER_WAKEUP_FD_H 22 | #define UNIX_ADAPTER_WAKEUP_FD_H 23 | 24 | class WakeupFd { 25 | public: 26 | WakeupFd(); 27 | ~WakeupFd(); 28 | int fd() { return m_pipeReadFd; } 29 | void set(); 30 | void reset(); 31 | 32 | private: 33 | // Do not allow copying the WakeupFd object. 34 | WakeupFd(const WakeupFd &other); 35 | WakeupFd &operator=(const WakeupFd &other); 36 | 37 | private: 38 | int m_pipeReadFd; 39 | int m_pipeWriteFd; 40 | }; 41 | 42 | #endif // UNIX_ADAPTER_WAKEUP_FD_H 43 | -------------------------------------------------------------------------------- /src/unix-adapter/subdir.mk: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011-2015 Ryan Prichard 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy 4 | # of this software and associated documentation files (the "Software"), to 5 | # deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | # IN THE SOFTWARE. 20 | 21 | ALL_TARGETS += build/$(UNIX_ADAPTER_EXE) 22 | 23 | $(eval $(call def_unix_target,unix-adapter,)) 24 | 25 | UNIX_ADAPTER_OBJECTS = \ 26 | build/unix-adapter/unix-adapter/InputHandler.o \ 27 | build/unix-adapter/unix-adapter/OutputHandler.o \ 28 | build/unix-adapter/unix-adapter/Util.o \ 29 | build/unix-adapter/unix-adapter/WakeupFd.o \ 30 | build/unix-adapter/unix-adapter/main.o \ 31 | build/unix-adapter/shared/DebugClient.o \ 32 | build/unix-adapter/shared/WinptyAssert.o \ 33 | build/unix-adapter/shared/WinptyVersion.o 34 | 35 | build/unix-adapter/shared/WinptyVersion.o : build/gen/GenVersion.h 36 | 37 | build/$(UNIX_ADAPTER_EXE) : $(UNIX_ADAPTER_OBJECTS) build/winpty.dll 38 | $(info Linking $@) 39 | @$(UNIX_CXX) $(UNIX_LDFLAGS) -o $@ $^ 40 | 41 | -include $(UNIX_ADAPTER_OBJECTS:.o=.d) 42 | -------------------------------------------------------------------------------- /vcbuild.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM -- Script requirements: 4 | REM -- 5 | REM -- * git This program must be in the Path to check out 6 | REM -- build-gyp. If that directory already exists, then 7 | REM -- git isn't necessary, but if it is missing, no 8 | REM -- commit hash will be embedded into binaries. 9 | REM -- 10 | REM -- * python A non-Cygwin Python 2 python.exe must be in the 11 | REM -- Path to run gyp. 12 | REM -- 13 | REM -- * msbuild msbuild must be in the Path. It is probably 14 | REM -- important to have msbuild from the correct MSVC 15 | REM -- release. 16 | REM -- 17 | REM -- The script's output binaries are in the src/Release/{Win32,x64} 18 | REM -- directory. 19 | 20 | REM ------------------------------------------------------------------------- 21 | REM -- Parse arguments 22 | 23 | setlocal 24 | cd %~dp0 25 | set GYP_ARGS= 26 | set MSVC_PLATFORM=x64 27 | 28 | :ParamLoop 29 | if "%1" == "" goto :ParamDone 30 | if "%1" == "--msvc-platform" ( 31 | REM -- One of Win32 or x64. 32 | set MSVC_PLATFORM=%2 33 | shift && shift 34 | goto :ParamLoop 35 | ) 36 | if "%1" == "--gyp-msvs-version" ( 37 | set GYP_ARGS=%GYP_ARGS% -G msvs_version=%2 38 | shift && shift 39 | goto :ParamLoop 40 | ) 41 | if "%1" == "--toolset" ( 42 | set GYP_ARGS=%GYP_ARGS% -D WINPTY_MSBUILD_TOOLSET=%2 43 | shift && shift 44 | goto :ParamLoop 45 | ) 46 | if "%1" == "--commit-hash" ( 47 | set GYP_ARGS=%GYP_ARGS% -D WINPTY_COMMIT_HASH=%2 48 | shift && shift 49 | goto :ParamLoop 50 | ) 51 | echo error: Unrecognized argument: %1 52 | exit /b 1 53 | :ParamDone 54 | 55 | REM ------------------------------------------------------------------------- 56 | REM -- Check out GYP. GYP doesn't seem to have releases, so just use the 57 | REM -- current master commit. 58 | 59 | if not exist build-gyp ( 60 | git clone https://chromium.googlesource.com/external/gyp build-gyp || ( 61 | echo error: GYP clone failed 62 | exit /b 1 63 | ) 64 | ) 65 | 66 | REM ------------------------------------------------------------------------- 67 | REM -- Run gyp to generate MSVC project files. 68 | 69 | cd src 70 | 71 | call ..\build-gyp\gyp.bat winpty.gyp -I configurations.gypi %GYP_ARGS% 72 | if errorlevel 1 ( 73 | echo error: GYP failed 74 | exit /b 1 75 | ) 76 | 77 | REM ------------------------------------------------------------------------- 78 | REM -- Compile the project. 79 | 80 | msbuild winpty.sln /m /p:Platform=%MSVC_PLATFORM% || ( 81 | echo error: msbuild failed 82 | exit /b 1 83 | ) 84 | --------------------------------------------------------------------------------