/// <summary> /// Loads letter iamge from win32 font. /// </summary> /// <param name="cache">should the iamge be cached in tga, xml files.</param> /// <returns>loader letter information.</returns> protected internal override LetterInfo Load(bool cache) { LetterInfo result = null; #if WINDOWS IntPtr bitmapHandle = IntPtr.Zero; byte[] textureData = null; try { if (null == PlatformWindows.SelectFont(this.font.fontRenderingDisplayContext, this.font.fontHandle)) { throw new Exception(); } TextMetric tm = new TextMetric(); if (false == PlatformWindows.GetTextMetrics(this.font.fontRenderingDisplayContext, out tm)) { throw new Exception(); } if (PlatformWindows.GDI_ERROR == PlatformWindows.SetTextAlign(this.font.fontRenderingDisplayContext, PlatformWindows.TA_LEFT | PlatformWindows.TA_TOP | PlatformWindows.TA_UPDATECP)) { throw new Exception(); } ABC[] abc = new ABC[1]; if (false == PlatformWindows.GetCharABCWidths(this.font.fontRenderingDisplayContext, (uint)this.character, (uint)this.character, abc)) { throw new Exception(); } this.offsetX = abc[0].abcA; this.width = (int)(abc[0].abcB + abc[0].abcC); BitmapInfo header = new BitmapInfo(); header.bmiHeader.biSize = Marshal.SizeOf(header); GlyphMetrics metrics = new GlyphMetrics(); MAT2 identity = new MAT2(); identity.eM12.value = 0; identity.eM21.value = 0; identity.eM11.value = 1; identity.eM22.value = 1; if (PlatformWindows.GDI_ERROR == PlatformWindows.GetGlyphOutline(this.font.fontRenderingDisplayContext, this.character, PlatformWindows.GGO_METRICS, out metrics, 0, IntPtr.Zero, ref identity)) { throw new Exception(); } header.bmiHeader.biWidth = metrics.gmBlackBoxX; header.bmiHeader.biHeight = -1 * metrics.gmBlackBoxY; header.bmiHeader.biPlanes = 1; header.bmiHeader.biBitCount = 32; header.bmiHeader.biCompression = 0;// BI_RGB; byte[] bitmapData = null; IntPtr bitmapDataPointer = IntPtr.Zero; bitmapHandle = PlatformWindows.CreateDIBSection(this.font.fontRenderingDisplayContext, ref header, /*DIB_RGB_COLORS*/ 0, out bitmapDataPointer, IntPtr.Zero, 0); if (IntPtr.Zero == bitmapHandle) { int err = Marshal.GetLastWin32Error(); throw new Exception(); } if (null == PlatformWindows.SelectObject(this.font.fontRenderingDisplayContext, bitmapHandle)) { throw new Exception(); } if (PlatformWindows.CLR_INVALID == PlatformWindows.SetBkColor(this.font.fontRenderingDisplayContext, new RGB(new byte[] { 0, 0, 0 }).ToInt32())) { throw new Exception(); } if (PlatformWindows.CLR_INVALID == PlatformWindows.SetTextColor(this.font.fontRenderingDisplayContext, new RGB(new byte[] { 0xff, 0xff, 0xff }).ToInt32())) { throw new Exception(); } if (0 == PlatformWindows.SetBkMode(this.font.fontRenderingDisplayContext, PlatformWindows.OPAQUE)) { throw new Exception(); } if (false == PlatformWindows.MoveToEx(this.font.fontRenderingDisplayContext, 0 - abc[0].abcA, -1 * (tm.tmAscent - metrics.gmptGlyphOrigin.y), IntPtr.Zero)) { throw new Exception(); } this.offsetY = tm.tmAscent - metrics.gmptGlyphOrigin.y - tm.tmDescent - 1; String str = "" + this.character; RECT rect = new RECT(); if (false == PlatformWindows.ExtTextOut(this.font.fontRenderingDisplayContext, 0, 0, (uint)0, ref rect, str, 1, null)) { throw new Exception(); } if (0 == PlatformWindows.SetBkMode(this.font.fontRenderingDisplayContext, PlatformWindows.TRANSPARENT)) { throw new Exception(); } int bitmapWidth = header.bmiHeader.biWidth; int bitmapHeight = -header.bmiHeader.biHeight; int textureWidth = RoundToPowerOf2(bitmapWidth); int textureHeight = RoundToPowerOf2(bitmapHeight); bitmapData = new byte[bitmapWidth * bitmapHeight * 4]; Marshal.Copy(bitmapDataPointer, bitmapData, 0, bitmapWidth * bitmapHeight * 4); textureData = new byte[4 * textureWidth * textureHeight]; for (int j = 0; j < textureHeight; j++) { for (int i = 0; i < textureWidth; i++) { textureData[4 * (i + j * textureWidth) + 0] = 0xff; textureData[4 * (i + j * textureWidth) + 1] = 0xff; textureData[4 * (i + j * textureWidth) + 2] = 0xff; textureData[4 * (i + j * textureWidth) + 3] = (byte)((i >= bitmapWidth || j >= bitmapHeight) ? 0 : bitmapData[(i + bitmapWidth * j) * 4 + 2]); } } if (true == cache) { result = new LetterInfo(); result.width = bitmapWidth; result.height = bitmapHeight; result.bytes = textureData; result.textureWidth = textureWidth; result.textureHeight = textureHeight; } else { this.image = this.engine.CreateImage("Letter [" + this.character + "]", textureWidth, textureHeight, textureData); // this.internalImage = true; } this.textureWidth = textureWidth; this.textureHeight = textureHeight; } catch (Exception) { this.engine.DeleteImage(ref this.image); } if (null != bitmapHandle) { PlatformWindows.DeleteObject(bitmapHandle); } this.loaded = true; #endif return(result); }
private void Initialize(Runspace runspace, EngineIntrinsics engineIntrinsics) { _engineIntrinsics = engineIntrinsics; _runspace = runspace; if (!_delayedOneTimeInitCompleted) { DelayedOneTimeInitialize(); _delayedOneTimeInitCompleted = true; } _buffer.Clear(); _edits = new List <EditItem>(); _undoEditIndex = 0; _editGroupStart = -1; _current = 0; _mark = 0; _emphasisStart = -1; _emphasisLength = 0; _ast = null; _tokens = null; _parseErrors = null; _inputAccepted = false; _initialX = _console.CursorLeft; _initialY = _console.CursorTop; _initialForeground = _console.ForegroundColor; _initialBackground = _console.BackgroundColor; _previousRender = _initialPrevRender; _previousRender.UpdateConsoleInfo(_console); _previousRender.initialY = _initialY; _statusIsErrorMessage = false; _initialOutputEncoding = _console.OutputEncoding; _prediction.Reset(); // Don't change the OutputEncoding if already UTF8, no console, or using raster font on Windows _skipOutputEncodingChange = _initialOutputEncoding == Encoding.UTF8 || (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && PlatformWindows.IsConsoleInput() && PlatformWindows.IsUsingRasterFont()); if (!_skipOutputEncodingChange) { _console.OutputEncoding = Encoding.UTF8; } _lastRenderTime = Stopwatch.StartNew(); _killCommandCount = 0; _yankCommandCount = 0; _yankLastArgCommandCount = 0; _tabCommandCount = 0; _recallHistoryCommandCount = 0; _anyHistoryCommandCount = 0; _visualSelectionCommandCount = 0; _hashedHistory = null; if (_getNextHistoryIndex > 0) { _currentHistoryIndex = _getNextHistoryIndex; UpdateFromHistory(HistoryMoveCursor.ToEnd); _getNextHistoryIndex = 0; if (_searchHistoryCommandCount > 0) { _searchHistoryPrefix = ""; if (Options.HistoryNoDuplicates) { _hashedHistory = new Dictionary <string, int>(); } } } else { _currentHistoryIndex = _history.Count; _searchHistoryCommandCount = 0; } if (_previousHistoryItem != null) { _previousHistoryItem.ApproximateElapsedTime = DateTime.UtcNow - _previousHistoryItem.StartTime; } }
/// <summary> /// Entry point - called by custom PSHost implementations that require the /// ability to cancel ReadLine. /// </summary> /// <returns>The complete command line.</returns> public static string ReadLine( Runspace runspace, EngineIntrinsics engineIntrinsics, CancellationToken cancellationToken, bool?lastRunStatus) { var console = _singleton._console; if (Console.IsInputRedirected || Console.IsOutputRedirected) { // System.Console doesn't handle redirected input. It matches the behavior on Windows // by throwing an "InvalidOperationException". // Therefore, if either stdin or stdout is redirected, PSReadLine doesn't really work, // so throw and let PowerShell call Console.ReadLine or do whatever else it decides to do. // // Some CI environments redirect stdin/stdout, but that doesn't affect our test runs // because the console is mocked, so we can skip the exception. if (!IsRunningCI(console)) { throw new NotSupportedException(); } } var oldControlCAsInput = false; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { PlatformWindows.Init(ref _singleton._charMap); } else { try { oldControlCAsInput = Console.TreatControlCAsInput; Console.TreatControlCAsInput = true; } catch {} } if (lastRunStatus.HasValue) { _singleton.ReportExecutionStatus(lastRunStatus.Value); } bool firstTime = true; while (true) { try { if (firstTime) { firstTime = false; _singleton.Initialize(runspace, engineIntrinsics); } _singleton._cancelReadCancellationToken = cancellationToken; return(_singleton.InputLoop()); } catch (OperationCanceledException) { // Console is either exiting or the cancellation of ReadLine has been requested // by a custom PSHost implementation. return(""); } catch (ExitException) { return("exit"); } catch (CustomHandlerException e) { var oldColor = console.ForegroundColor; console.ForegroundColor = ConsoleColor.Red; console.WriteLine( string.Format(CultureInfo.CurrentUICulture, PSReadLineResources.OopsCustomHandlerException, e.InnerException.Message)); console.ForegroundColor = oldColor; var lineBeforeCrash = _singleton._buffer.ToString(); _singleton.Initialize(runspace, _singleton._engineIntrinsics); InvokePrompt(); Insert(lineBeforeCrash); } catch (Exception e) { // If we're running tests, just throw. if (_singleton._mockableMethods != _singleton) { throw; } while (e.InnerException != null) { e = e.InnerException; } var oldColor = console.ForegroundColor; console.ForegroundColor = ConsoleColor.Red; console.WriteLine(PSReadLineResources.OopsAnErrorMessage1); console.ForegroundColor = oldColor; var sb = new StringBuilder(); for (int i = 0; i < _lastNKeys.Count; i++) { sb.Append(' '); sb.Append(_lastNKeys[i].KeyStr); if (_singleton._dispatchTable.TryGetValue(_lastNKeys[i], out var handler) && "AcceptLine".Equals(handler.BriefDescription, StringComparison.OrdinalIgnoreCase)) { // Make it a little easier to see the keys sb.Append('\n'); } } var psVersion = PSObject.AsPSObject(engineIntrinsics.Host.Version).ToString(); var ourVersion = typeof(PSConsoleReadLine).Assembly.GetCustomAttributes <AssemblyInformationalVersionAttribute>().First().InformationalVersion; var osInfo = RuntimeInformation.OSDescription; var bufferWidth = console.BufferWidth; var bufferHeight = console.BufferHeight; console.WriteLine(string.Format(CultureInfo.CurrentUICulture, PSReadLineResources.OopsAnErrorMessage2, ourVersion, psVersion, osInfo, bufferWidth, bufferHeight, _lastNKeys.Count, sb, e)); var lineBeforeCrash = _singleton._buffer.ToString(); _singleton.Initialize(runspace, _singleton._engineIntrinsics); InvokePrompt(); Insert(lineBeforeCrash); } finally { try { // If we are closing, restoring the old console settings isn't needed, // and some operating systems, it can cause a hang. if (!_singleton._closingWaitHandle.WaitOne(0)) { console.OutputEncoding = _singleton._initialOutputEncoding; bool IsValid(ConsoleColor color) { return(color >= ConsoleColor.Black && color <= ConsoleColor.White); } if (IsValid(_singleton._initialForeground)) { console.ForegroundColor = _singleton._initialForeground; } if (IsValid(_singleton._initialBackground)) { console.BackgroundColor = _singleton._initialBackground; } if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Console.TreatControlCAsInput = oldControlCAsInput; } } } catch { } if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { PlatformWindows.Complete(); } } } }
/// <summary> /// Entry point - called from the PowerShell function PSConsoleHostReadLine /// after the prompt has been displayed. /// </summary> /// <returns>The complete command line.</returns> public static string ReadLine(Runspace runspace, EngineIntrinsics engineIntrinsics) { var console = _singleton._console; var oldControlCAsInput = false; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { PlatformWindows.Init(ref _singleton._charMap); } else { if (Console.IsInputRedirected || Console.IsOutputRedirected) { // System.Console doesn't handle redirected input. It matches the behavior on Windows // by throwing an "InvalidOperationException". // Therefore, if either stdin or stdout is redirected, PSReadLine doesn't really work, // so throw and let PowerShell call Console.ReadLine or do whatever else it decides to do. throw new NotSupportedException(); } try { oldControlCAsInput = Console.TreatControlCAsInput; Console.TreatControlCAsInput = true; } catch {} } bool firstTime = true; while (true) { try { if (firstTime) { firstTime = false; _singleton.Initialize(runspace, engineIntrinsics); } return(_singleton.InputLoop()); } catch (OperationCanceledException) { // Console is exiting - return value isn't too critical - null or 'exit' could work equally well. return(""); } catch (ExitException) { return("exit"); } catch (CustomHandlerException e) { var oldColor = console.ForegroundColor; console.ForegroundColor = ConsoleColor.Red; console.WriteLine( string.Format(CultureInfo.CurrentUICulture, PSReadLineResources.OopsCustomHandlerException, e.InnerException.Message)); console.ForegroundColor = oldColor; var lineBeforeCrash = _singleton._buffer.ToString(); _singleton.Initialize(runspace, _singleton._engineIntrinsics); InvokePrompt(); Insert(lineBeforeCrash); } catch (Exception e) { // If we're running tests, just throw. if (_singleton._mockableMethods != _singleton) { throw; } while (e.InnerException != null) { e = e.InnerException; } var oldColor = console.ForegroundColor; console.ForegroundColor = ConsoleColor.Red; console.WriteLine(PSReadLineResources.OopsAnErrorMessage1); console.ForegroundColor = oldColor; var sb = new StringBuilder(); for (int i = 0; i < _lastNKeys.Count; i++) { sb.Append(' '); sb.Append(_lastNKeys[i].ToGestureString()); if (_singleton._dispatchTable.TryGetValue(_lastNKeys[i], out var handler) && "AcceptLine".Equals(handler.BriefDescription, StringComparison.OrdinalIgnoreCase)) { // Make it a little easier to see the keys sb.Append('\n'); } } console.WriteLine(string.Format(CultureInfo.CurrentUICulture, PSReadLineResources.OopsAnErrorMessage2, _lastNKeys.Count, sb, e)); var lineBeforeCrash = _singleton._buffer.ToString(); _singleton.Initialize(runspace, _singleton._engineIntrinsics); InvokePrompt(); Insert(lineBeforeCrash); } finally { try { // If we are closing, restoring the old console settings isn't needed, // and some operating systems, it can cause a hang. if (!_singleton._closingWaitHandle.WaitOne(0)) { console.OutputEncoding = _singleton._initialOutputEncoding; if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Console.TreatControlCAsInput = oldControlCAsInput; } } } catch { } if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { PlatformWindows.Complete(); } } } }
private void DelayedOneTimeInitialize() { // Delayed initialization is needed so that options can be set // after the constuctor but have an affect before the user starts // editing their first command line. For example, if the user // specifies a custom history save file, we don't want to try reading // from the default one. var historyCountVar = _engineIntrinsics?.SessionState.PSVariable.Get("MaximumHistoryCount"); if (historyCountVar?.Value is int historyCountValue) { _options.MaximumHistoryCount = historyCountValue; } if (_options.PromptText == null && _engineIntrinsics?.InvokeCommand.GetCommand("prompt", CommandTypes.Function) is FunctionInfo promptCommand) { var promptIsPure = null == promptCommand.ScriptBlock.Ast.Find(ast => ast is CommandAst || ast is InvokeMemberExpressionAst, searchNestedScriptBlocks: true); if (promptIsPure) { var res = promptCommand.ScriptBlock.InvokeReturnAsIs(Array.Empty <object>()); string evaluatedPrompt = res as string; if (evaluatedPrompt == null && res is PSObject psobject) { evaluatedPrompt = psobject.BaseObject as string; } if (evaluatedPrompt != null) { int i; for (i = evaluatedPrompt.Length - 1; i >= 0; i--) { if (!char.IsWhiteSpace(evaluatedPrompt[i])) { break; } } if (i >= 0) { _options.PromptText = evaluatedPrompt.Substring(i); } } } } _historyFileMutex = new Mutex(false, GetHistorySaveFileMutexName()); _history = new HistoryQueue <HistoryItem>(Options.MaximumHistoryCount); _currentHistoryIndex = 0; bool readHistoryFile = true; try { if (_options.HistorySaveStyle == HistorySaveStyle.SaveNothing && Runspace.DefaultRunspace != null) { using (var ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace)) { ps.AddCommand("Microsoft.PowerShell.Core\\Get-History"); foreach (var historyInfo in ps.Invoke <HistoryInfo>()) { AddToHistory(historyInfo.CommandLine); } readHistoryFile = false; } } } catch { } if (readHistoryFile) { ReadHistoryFile(); } _killIndex = -1; // So first add indexes 0. _killRing = new List <string>(Options.MaximumKillRingCount); _singleton._readKeyWaitHandle = new AutoResetEvent(false); _singleton._keyReadWaitHandle = new AutoResetEvent(false); _singleton._closingWaitHandle = new ManualResetEvent(false); _singleton._requestKeyWaitHandles = new WaitHandle[] { _singleton._keyReadWaitHandle, _singleton._closingWaitHandle }; _singleton._threadProcWaitHandles = new WaitHandle[] { _singleton._readKeyWaitHandle, _singleton._closingWaitHandle }; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { PlatformWindows.OneTimeInit(_singleton); } // This is for a "being hosted in an alternate appdomain scenario" (the // DomainUnload event is not raised for the default appdomain). It allows us // to exit cleanly when the appdomain is unloaded but the process is not going // away. if (!AppDomain.CurrentDomain.IsDefaultAppDomain()) { AppDomain.CurrentDomain.DomainUnload += (x, y) => { _singleton._closingWaitHandle.Set(); _singleton._readKeyThread.Join(); // may need to wait for history to be written }; } _singleton._readKeyThread = new Thread(_singleton.ReadKeyThreadProc) { IsBackground = true }; _singleton._readKeyThread.Start(); }
/// <summary> /// Entry point - called from the PowerShell function PSConsoleHostReadline /// after the prompt has been displayed. /// </summary> /// <returns>The complete command line.</returns> public static string ReadLine(Runspace runspace, EngineIntrinsics engineIntrinsics) { var console = _singleton._console; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { PlatformWindows.Init(ref _singleton._charMap); } bool firstTime = true; while (true) { try { if (firstTime) { firstTime = false; _singleton.Initialize(runspace, engineIntrinsics); } return(_singleton.InputLoop()); } catch (OperationCanceledException) { // Console is exiting - return value isn't too critical - null or 'exit' could work equally well. return(""); } catch (ExitException) { return("exit"); } catch (CustomHandlerException e) { var oldColor = console.ForegroundColor; console.ForegroundColor = ConsoleColor.Red; console.WriteLine( string.Format(CultureInfo.CurrentUICulture, PSReadLineResources.OopsCustomHandlerException, e.InnerException.Message)); console.ForegroundColor = oldColor; var lineBeforeCrash = _singleton._buffer.ToString(); _singleton.Initialize(runspace, _singleton._engineIntrinsics); InvokePrompt(); Insert(lineBeforeCrash); } catch (Exception e) { // If we're running tests, just throw. if (_singleton._mockableMethods != _singleton) { throw; } while (e.InnerException != null) { e = e.InnerException; } var oldColor = console.ForegroundColor; console.ForegroundColor = ConsoleColor.Red; console.WriteLine(PSReadLineResources.OopsAnErrorMessage1); console.ForegroundColor = oldColor; var sb = new StringBuilder(); for (int i = 0; i < _lastNKeys.Count; i++) { sb.Append(' '); sb.Append(_lastNKeys[i].ToGestureString()); if (_singleton._dispatchTable.TryGetValue(_lastNKeys[i], out var handler) && "AcceptLine".Equals(handler.BriefDescription, StringComparison.OrdinalIgnoreCase)) { // Make it a little easier to see the keys sb.Append('\n'); } } console.WriteLine(string.Format(CultureInfo.CurrentUICulture, PSReadLineResources.OopsAnErrorMessage2, _lastNKeys.Count, sb, e)); var lineBeforeCrash = _singleton._buffer.ToString(); _singleton.Initialize(runspace, _singleton._engineIntrinsics); InvokePrompt(); Insert(lineBeforeCrash); } finally { Console.OutputEncoding = _singleton._initialOutputEncoding; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { PlatformWindows.Complete(); } } } }