private void Init_WireEvents([NotNull] ConEmuStartInfo startinfo) { if (startinfo == null) { throw new ArgumentNullException(nameof(startinfo)); } // Advise events before they got chance to fire, use event sinks from startinfo for guaranteed delivery if (startinfo.ConsoleProcessExitedEventSink != null) { ConsoleProcessExited += startinfo.ConsoleProcessExitedEventSink; } if (startinfo.ConsoleProcessPreExitedEventSink != null) { ConsoleProcessPreExited += startinfo.ConsoleProcessPreExitedEventSink; } if (startinfo.ConsoleEmulatorClosedEventSink != null) { ConsoleEmulatorClosed += startinfo.ConsoleEmulatorClosedEventSink; } // Re-issue events as async tasks // As we advise events before they even fire, the task is guaranteed to get its state ConsoleProcessExited += (sender, args) => _taskConsoleProcessExit.SetResult(args); ConsoleEmulatorClosed += delegate { _taskConsoleEmulatorClosed.SetResult(Missing.Value); }; }
public ConEmuSession Start([NotNull] ConEmuStartInfo startinfo) { if (startinfo == null) { throw new ArgumentNullException(nameof(startinfo)); } // Close prev session if there is one _running?.CloseConsoleEmulator(); if (_running != null) { throw new InvalidOperationException("Cannot start a new console process because another console emulator session has failed to close in due time."); } _autostartinfo = null; // As we're starting, no more chance for an autostart if (!IsHandleCreated) { CreateHandle(); } // Spawn session var session = new ConEmuSession(startinfo, new ConEmuSession.HostContext((void *)Handle, IsStatusbarVisible)); _running = session; StateChanged?.Invoke(this, EventArgs.Empty); startinfo.ConsoleProcessPreExitedEventSink += (sender, args) => OnSessionEnds(); // Wait for its exit session.WaitForConsoleEmulatorCloseAsync().ContinueWith(scheduler: TaskScheduler.FromCurrentSynchronizationContext(), continuationAction: task => { OnSessionEnds(); }); return(session); }
private Process Init_StartConEmu([NotNull] ConEmuStartInfo startinfo, [NotNull] CommandLineBuilder cmdl) { if (startinfo == null) { throw new ArgumentNullException(nameof(startinfo)); } if (cmdl == null) { throw new ArgumentNullException(nameof(cmdl)); } try { if (string.IsNullOrEmpty(startinfo.ConEmuExecutablePath)) { throw new InvalidOperationException("Could not run the console emulator. The path to ConEmu.exe could not be detected."); } if (!File.Exists(startinfo.ConEmuExecutablePath)) { throw new InvalidOperationException($"Missing ConEmu executable at location “{startinfo.ConEmuExecutablePath}”."); } var processNew = new Process() { StartInfo = new ProcessStartInfo(startinfo.ConEmuExecutablePath, cmdl.ToString()) { UseShellExecute = false } }; // Bind process termination processNew.EnableRaisingEvents = true; processNew.Exited += delegate { // Ensure STA Task.Factory.StartNew(scheduler: _schedulerSta, cancellationToken: CancellationToken.None, creationOptions: 0, action: () => { // Tear down all objects TerminateLifetime(); // If we haven't separately caught an exit of the payload process TryFireConsoleProcessExited(_process.ExitCode /* We haven't caught the exit of the payload process, so we haven't gotten a message with its errorlevel as well. Assume ConEmu propagates its exit code, as there ain't other way for getting it now */); // Fire client total exited event ConsoleEmulatorClosed?.Invoke(this, EventArgs.Empty); }); }; if (!processNew.Start()) { throw new Win32Exception("The process did not start."); } return(processNew); } catch (Win32Exception ex) { TerminateLifetime(); throw new InvalidOperationException("Could not run the console emulator. " + ex.Message + $" ({ex.NativeErrorCode:X8})" + Environment.NewLine + Environment.NewLine + "Command:" + Environment.NewLine + startinfo.ConEmuExecutablePath + Environment.NewLine + Environment.NewLine + "Arguments:" + Environment.NewLine + cmdl, ex); } }
/// <summary> /// Starts the session. /// Opens the emulator view in the control (HWND given in <paramref name="hostcontext" />) by starting the ConEmu child process and giving it that HWND; ConEmu then starts the child Console Process for the commandline given in <paramref name="startinfo" /> and makes it run in the console emulator window. /// </summary> /// <param name="startinfo">User-defined startup parameters for the console process.</param> /// <param name="hostcontext">Control-related parameters.</param> /// <param name="joinableTaskFactory">The <see cref="JoinableTaskFactory"/>.</param> public ConEmuSession([NotNull] ConEmuStartInfo startinfo, [NotNull] HostContext hostcontext, [NotNull] JoinableTaskFactory joinableTaskFactory) { if (startinfo == null) { throw new ArgumentNullException(nameof(startinfo)); } if (hostcontext == null) { throw new ArgumentNullException(nameof(hostcontext)); } if (joinableTaskFactory == null) { throw new ArgumentNullException(nameof(joinableTaskFactory)); } if (string.IsNullOrEmpty(startinfo.ConsoleProcessCommandLine)) { throw new InvalidOperationException($"Cannot start a new console process for command line “{startinfo.ConsoleProcessCommandLine}” because it's either NULL, or empty, or whitespace."); } _joinableTaskFactory = joinableTaskFactory; _startinfo = startinfo; startinfo.MarkAsUsedUp(); // No more changes allowed in this copy // Directory for working files, +cleanup _dirTempWorkingFolder = Init_TempWorkingFolder(); // Events wiring: make sure sinks pre-installed with start-info also get notified Init_WireEvents(startinfo); // Should feed ANSI log? if (startinfo.IsReadingAnsiStream) { _ansilog = Init_AnsiLog(startinfo); } // Cmdline CommandLineBuilder cmdl = Init_MakeConEmuCommandLine(startinfo, hostcontext, _ansilog, _dirTempWorkingFolder); // Start ConEmu // If it fails, lifetime will be terminated; from them on, termination will be bound to ConEmu process exit _process = Init_StartConEmu(startinfo, cmdl); // GuiMacro executor _guiMacroExecutor = new GuiMacroExecutor(startinfo.ConEmuConsoleServerExecutablePath); _lifetime.Add(() => ((IDisposable)_guiMacroExecutor).Dispose()); // Monitor payload process Init_ConsoleProcessMonitoring(); }
private AnsiLog Init_AnsiLog([NotNull] ConEmuStartInfo startinfo) { var ansilog = new AnsiLog(_dirTempWorkingFolder); _lifetime.Add(() => ansilog.Dispose()); if (startinfo.AnsiStreamChunkReceivedEventSink != null) { ansilog.AnsiStreamChunkReceived += startinfo.AnsiStreamChunkReceivedEventSink; } // Do the pumping periodically (TODO: take this to async?.. but would like to keep the final evt on the home thread, unless we go to tasks) // TODO: if ConEmu writes to a pipe, we might be getting events when more data comes to the pipe rather than poll it by timer var timer = new Timer() { Interval = (int)TimeSpan.FromSeconds(.1).TotalMilliseconds, Enabled = true }; timer.Tick += delegate { ansilog.PumpStream(); }; _lifetime.Add(() => timer.Dispose()); return(ansilog); }
private static string Init_MakeConEmuCommandLine_EmitConfigFile([NotNull] DirectoryInfo dirForConfigFile, [NotNull] ConEmuStartInfo startinfo, [NotNull] HostContext hostcontext) { if (dirForConfigFile == null) { throw new ArgumentNullException(nameof(dirForConfigFile)); } if (startinfo == null) { throw new ArgumentNullException(nameof(startinfo)); } if (hostcontext == null) { throw new ArgumentNullException(nameof(hostcontext)); } // Take baseline settings from the startinfo XmlDocument xmlBase = startinfo.BaseConfiguration; if (xmlBase.DocumentElement == null) { throw new InvalidOperationException("The BaseConfiguration parameter of the ConEmuStartInfo must be a non-empty XmlDocument. This one does not have a root element."); } if (xmlBase.DocumentElement.Name != ConEmuConstants.XmlElementKey) { throw new InvalidOperationException($"The BaseConfiguration parameter of the ConEmuStartInfo must be an XmlDocument with the root element named “{ConEmuConstants.XmlElementKey}” in an empty namespace. The actual element name is “{xmlBase.DocumentElement.Name}”."); } if (!String.Equals(xmlBase.DocumentElement.GetAttribute(ConEmuConstants.XmlAttrName), ConEmuConstants.XmlValueSoftware, StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException($"The BaseConfiguration parameter of the ConEmuStartInfo must be an XmlDocument whose root element is named “{ConEmuConstants.XmlElementKey}” and has an attribute “{ConEmuConstants.XmlAttrName}” set to “{ConEmuConstants.XmlValueSoftware}”. The actual value of this attribute is “{xmlBase.DocumentElement.GetAttribute(ConEmuConstants.XmlAttrName)}”."); } // Load default template var xmldoc = new XmlDocument(); xmldoc.AppendChild(xmldoc.ImportNode(xmlBase.DocumentElement, true)); // Ensure the settings file has the expected keys structure // As we now allow user-supplied documents, we must ensure these elements exist XmlElement xmlSoftware = xmldoc.DocumentElement; if (xmlSoftware == null) { throw new InvalidOperationException("Not expecting the cloned element to be NULL."); } var xmlConEmu = xmlSoftware.SelectSingleNode($"{ConEmuConstants.XmlElementKey}[@{ConEmuConstants.XmlAttrName}='{ConEmuConstants.XmlValueConEmu}']") as XmlElement; if (xmlConEmu == null) { xmlSoftware.AppendChild(xmlConEmu = xmldoc.CreateElement(ConEmuConstants.XmlElementKey)); xmlConEmu.SetAttribute(ConEmuConstants.XmlAttrName, ConEmuConstants.XmlValueConEmu); } var xmlDotVanilla = xmlConEmu.SelectSingleNode($"{ConEmuConstants.XmlElementKey}[@{ConEmuConstants.XmlAttrName}='{ConEmuConstants.XmlValueDotVanilla}']") as XmlElement; if (xmlDotVanilla == null) { xmlConEmu.AppendChild(xmlDotVanilla = xmldoc.CreateElement(ConEmuConstants.XmlElementKey)); xmlDotVanilla.SetAttribute(ConEmuConstants.XmlAttrName, ConEmuConstants.XmlValueDotVanilla); } // Apply settings from properties XmlNode xmlSettings = xmlDotVanilla; { string keyname = "StatusBar.Show"; var xmlElem = ((XmlElement)(xmlSettings.SelectSingleNode($"value[@name='{keyname}']") ?? xmlSettings.AppendChild(xmldoc.CreateElement("value")))); xmlElem.SetAttribute(ConEmuConstants.XmlAttrName, keyname); xmlElem.SetAttribute("type", "hex"); xmlElem.SetAttribute("data", (hostcontext.IsStatusbarVisibleInitial ? 1 : 0).ToString()); } // Environment variables if ((startinfo.EnumEnv().Any()) || (startinfo.IsEchoingConsoleCommandLine) || (startinfo.GreetingText.Length > 0)) { string keyname = "EnvironmentSet"; var xmlElem = ((XmlElement)(xmlSettings.SelectSingleNode($"value[@name='{keyname}']") ?? xmlSettings.AppendChild(xmldoc.CreateElement("value")))); xmlElem.SetAttribute(ConEmuConstants.XmlAttrName, keyname); xmlElem.SetAttribute("type", "multi"); foreach (string key in startinfo.EnumEnv()) { XmlElement xmlLine; xmlElem.AppendChild(xmlLine = xmldoc.CreateElement("line")); xmlLine.SetAttribute("data", $"set {key}={startinfo.GetEnv(key)}"); } // Echo the custom greeting text if (startinfo.GreetingText.Length > 0) { // Echo each line separately List <string> lines = Regex.Split(startinfo.GreetingText, @"\r\n|\n|\r").ToList(); if ((lines.Any()) && (lines.Last().Length == 0)) // Newline handling, as declared { lines.RemoveAt(lines.Count - 1); } foreach (string line in lines) { XmlElement xmlLine; xmlElem.AppendChild(xmlLine = xmldoc.CreateElement("line")); xmlLine.SetAttribute("data", $"echo {Init_MakeConEmuCommandLine_EmitConfigFile_EscapeEchoText(line)}"); } } // To echo the cmdline, add an echo command to the env-init session if (startinfo.IsEchoingConsoleCommandLine) { XmlElement xmlLine; xmlElem.AppendChild(xmlLine = xmldoc.CreateElement("line")); xmlLine.SetAttribute("data", $"echo {Init_MakeConEmuCommandLine_EmitConfigFile_EscapeEchoText(startinfo.ConsoleProcessCommandLine)}"); } } // Write out to temp location dirForConfigFile.Create(); string sConfigFile = Path.Combine(dirForConfigFile.FullName, "Config.Xml"); xmldoc.Save(sConfigFile); new FileInfo(sConfigFile).IsReadOnly = true; // Mark the file as readonly, so that ConEmu didn't suggest to save modifications to this temp file return(sConfigFile); }
private static unsafe CommandLineBuilder Init_MakeConEmuCommandLine([NotNull] ConEmuStartInfo startinfo, [NotNull] HostContext hostcontext, [CanBeNull] AnsiLog ansilog, [NotNull] DirectoryInfo dirLocalTempRoot) { if (startinfo == null) { throw new ArgumentNullException(nameof(startinfo)); } if (hostcontext == null) { throw new ArgumentNullException(nameof(hostcontext)); } var cmdl = new CommandLineBuilder(); // This sets up hosting of ConEmu in our control cmdl.AppendSwitch("-InsideWnd"); cmdl.AppendFileNameIfNotNull("0x" + ((ulong)hostcontext.HWndParent).ToString("X")); // Don't use keyboard hooks in ConEmu when embedded cmdl.AppendSwitch("-NoKeyHooks"); switch (startinfo.LogLevel) { case ConEmuStartInfo.LogLevels.Basic: cmdl.AppendSwitch("-Log"); break; case ConEmuStartInfo.LogLevels.Detailed: cmdl.AppendSwitch("-Log2"); break; case ConEmuStartInfo.LogLevels.Advanced: cmdl.AppendSwitch("-Log3"); break; case ConEmuStartInfo.LogLevels.Full: cmdl.AppendSwitch("-Log4"); break; } // Basic settings, like fonts and hidden tab bar // Plus some of the properties on this class cmdl.AppendSwitch("-LoadCfgFile"); cmdl.AppendFileNameIfNotNull(Init_MakeConEmuCommandLine_EmitConfigFile(dirLocalTempRoot, startinfo, hostcontext)); if (!string.IsNullOrEmpty(startinfo.StartupDirectory)) { cmdl.AppendSwitch("-Dir"); cmdl.AppendFileNameIfNotNull(startinfo.StartupDirectory); } // ANSI Log file if (ansilog != null) { cmdl.AppendSwitch("-AnsiLog"); cmdl.AppendFileNameIfNotNull(ansilog.Directory.FullName); } if (dirLocalTempRoot == null) { throw new ArgumentNullException(nameof(dirLocalTempRoot)); } // This one MUST be the last switch cmdl.AppendSwitch("-cmd"); // Console mode command // NOTE: if placed AFTER the payload command line, otherwise somehow conemu hooks won't fetch the switch out of the cmdline, e.g. with some complicated git fetch/push cmdline syntax which has a lot of colons inside on itself string sConsoleExitMode; switch (startinfo.WhenConsoleProcessExits) { case WhenConsoleProcessExits.CloseConsoleEmulator: sConsoleExitMode = "n"; break; case WhenConsoleProcessExits.KeepConsoleEmulator: sConsoleExitMode = "c0"; break; case WhenConsoleProcessExits.KeepConsoleEmulatorAndShowMessage: sConsoleExitMode = "c"; break; default: throw new ArgumentOutOfRangeException("ConEmuStartInfo" + "::" + "WhenConsoleProcessExits", startinfo.WhenConsoleProcessExits, "This is not a valid enum value."); } cmdl.AppendSwitchIfNotNull("-cur_console:", $"{(startinfo.IsElevated ? "a" : "")}{sConsoleExitMode}"); if (!string.IsNullOrEmpty(startinfo.ConsoleProcessExtraArgs)) { cmdl.AppendSwitch(startinfo.ConsoleProcessExtraArgs); } // And the shell command line itself cmdl.AppendSwitch(startinfo.ConsoleProcessCommandLine); return(cmdl); }
private ConEmuSession StartProcess(ConEmuStartInfo startInfo) { if (control.InvokeRequired) { return (ConEmuSession)control.Invoke( (ConEmuStarter)(si => { return control.Start(si); }), startInfo); } return control.Start(startInfo); }
private ConEmuStartInfo BuildStartInfo(string cwd, string executable, string arguments) { // http://www.windowsinspired.com/understanding-the-command-line-string-and-arguments-received-by-a-windows-program/ var cmdLine = (arguments.Contains("\"") ? "\"" : "") + CommandLine.EscapeArgument(executable) + " " + arguments; var si = new ConEmuStartInfo(); si.ConEmuExecutablePath = conEmuExe; si.ConsoleProcessCommandLine = cmdLine; si.BaseConfiguration = config; si.StartupDirectory = cwd; si.IsReadingAnsiStream = false; si.WhenConsoleProcessExits = WhenConsoleProcessExits.CloseConsoleEmulator; return si; }
/// <summary> /// Adds a tab with console interface to Git over the current working copy. Recreates the terminal on tab activation if user exits the shell. /// </summary> private void FillTerminalTab() { if (!EnvUtils.RunningOnWindows() || !Module.EffectiveSettings.Detailed.ShowConEmuTab.ValueOrDefault) return; // ConEmu only works on WinNT TabPage tabpage; string sImageKey = "Resources.IconConsole"; CommitInfoTabControl.ImageList.Images.Add(sImageKey, Resources.IconConsole); CommitInfoTabControl.Controls.Add(tabpage = new TabPage(_consoleTabCaption.Text)); tabpage.ImageKey = sImageKey; // After adding page // Delay-create the terminal window when the tab is first selected CommitInfoTabControl.Selecting += (sender, args) => { if (args.TabPage != tabpage) return; if (terminal == null) // Lazy-create on first opening the tab { tabpage.Controls.Clear(); tabpage.Controls.Add( terminal = new ConEmuControl() { Dock = DockStyle.Fill, AutoStartInfo = null, IsStatusbarVisible = false } ); } if (terminal.IsConsoleEmulatorOpen) // If user has typed "exit" in there, restart the shell; otherwise just return return; // Create the terminal var startinfo = new ConEmuStartInfo(); startinfo.StartupDirectory = Module.WorkingDir; startinfo.WhenConsoleProcessExits = WhenConsoleProcessExits.CloseConsoleEmulator; // Choose the console: bash from git with fallback to cmd string sJustBash = "bash.exe"; // Generic bash, should generally be in the git dir, less configured than the specific git-bash string sJustSh = "sh.exe"; // Fallback to SH string cmdPath = new[] { sJustBash, sJustSh }. Select(shell => { string shellPath; if (PathUtil.TryFindShellPath(shell, out shellPath)) return shellPath; return null; }). Where(shellPath => shellPath != null). FirstOrDefault(); if (cmdPath == null) { startinfo.ConsoleProcessCommandLine = ConEmuConstants.DefaultConsoleCommandLine; } else { startinfo.ConsoleProcessCommandLine = cmdPath + " --login -i"; } startinfo.ConsoleProcessExtraArgs = " -new_console:P:\"<Solarized Light>\""; // Set path to git in this window (actually, effective with CMD only) if (!string.IsNullOrEmpty(AppSettings.GitCommandValue)) { string dirGit = Path.GetDirectoryName(AppSettings.GitCommandValue); if (!string.IsNullOrEmpty(dirGit)) startinfo.SetEnv("PATH", dirGit + ";" + "%PATH%"); } terminal.Start(startinfo); }; }
/// <summary> /// Adds a tab with console interface to Git over the current working copy. Recreates the terminal on tab activation if user exits the shell. /// </summary> private void FillTerminalTab() { if(!EnvUtils.RunningOnWindows() || !Module.EffectiveSettings.Detailed.ShowConEmuTab.ValueOrDefault) return; // ConEmu only works on WinNT TabPage tabpage; string sImageKey = "Resources.IconConsole"; CommitInfoTabControl.ImageList.Images.Add(sImageKey, Resources.IconConsole); CommitInfoTabControl.Controls.Add(tabpage = new TabPage("Console")); tabpage.ImageKey = sImageKey; // After adding page // Delay-create the terminal window when the tab is first selected CommitInfoTabControl.Selecting += (sender, args) => { if(args.TabPage != tabpage) return; if(terminal == null) // Lazy-create on first opening the tab { tabpage.Controls.Clear(); tabpage.Controls.Add(terminal = new ConEmuControl() {Dock = DockStyle.Fill, AutoStartInfo = null}); } if(terminal.IsConsoleEmulatorOpen) // If user has typed "exit" in there, restart the shell; otherwise just return return; // Create the terminal var startinfo = new ConEmuStartInfo(); startinfo.StartupDirectory = Module.WorkingDir; startinfo.WhenConsoleProcessExits = WhenConsoleProcessExits.CloseConsoleEmulator; // Choose the console: bash from git with fallback to cmd string sGitBashFromUsrBin = "";/*This is not a console program and is not reliable yet, suppress for now.*/ //Path.Combine(Path.Combine(Path.Combine(AppSettings.GitBinDir, ".."), ".."), "git-bash.exe"); // Git bin dir is /usr/bin under git installdir, so go 2x up string sGitBashFromBinOrCmd = "";/*This is not a console program and is not reliable yet, suppress for now.*/ //Path.Combine(Path.Combine(AppSettings.GitBinDir, ".."), "git-bash.exe"); // In case we're running off just /bin or /cmd var gitDir = Path.GetDirectoryName(AppSettings.GitCommandValue); string sJustBash = Path.Combine(gitDir, "bash.exe"); // Generic bash, should generally be in the git dir, less configured than the specific git-bash string sJustSh = Path.Combine(gitDir, "sh.exe"); // Fallback to SH startinfo.ConsoleProcessCommandLine = new[] {sGitBashFromUsrBin, sGitBashFromBinOrCmd, sJustBash, sJustSh}.Where(File.Exists).FirstOrDefault() ?? ConEmuConstants.DefaultConsoleCommandLine; // Choose whatever exists, or default CMD shell if(startinfo.ConsoleProcessCommandLine != ConEmuConstants.DefaultConsoleCommandLine) { startinfo.ConsoleProcessCommandLine += " --login -i"; } // Set path to git in this window (actually, effective with CMD only) if(!string.IsNullOrEmpty(AppSettings.GitCommand)) { string dirGit = Path.GetDirectoryName(AppSettings.GitCommand); if(!string.IsNullOrEmpty(dirGit)) startinfo.SetEnv("PATH", dirGit + ";" + "%PATH%"); } terminal.Start(startinfo); }; }
/// <summary> /// Starts the session. /// Opens the emulator view in the control (HWND given in <paramref name="hostcontext" />) by starting the ConEmu child process and giving it that HWND; ConEmu then starts the child Console Process for the commandline given in <paramref name="startinfo" /> and makes it run in the console emulator window. /// </summary> /// <param name="startinfo">User-defined startup parameters for the console process.</param> /// <param name="hostcontext">Control-related parameters.</param> public ConEmuSession([NotNull] ConEmuStartInfo startinfo, [NotNull] HostContext hostcontext) { if(startinfo == null) throw new ArgumentNullException(nameof(startinfo)); if(hostcontext == null) throw new ArgumentNullException(nameof(hostcontext)); if(string.IsNullOrEmpty(startinfo.ConsoleProcessCommandLine)) throw new InvalidOperationException($"Cannot start a new console process for command line “{startinfo.ConsoleProcessCommandLine}” because it's either NULL, or empty, or whitespace."); _startinfo = startinfo; startinfo.MarkAsUsedUp(); // No more changes allowed in this copy // Directory for working files, +cleanup _dirTempWorkingFolder = Init_TempWorkingFolder(); // Events wiring: make sure sinks pre-installed with start-info also get notified Init_WireEvents(startinfo); // Should feed ANSI log? if(startinfo.IsReadingAnsiStream) _ansilog = Init_AnsiLog(startinfo); // Cmdline CommandLineBuilder cmdl = Init_MakeConEmuCommandLine(startinfo, hostcontext, _ansilog, _dirTempWorkingFolder); // Start ConEmu // If it fails, lifetime will be terminated; from them on, termination will be bound to ConEmu process exit _process = Init_StartConEmu(startinfo, cmdl); // GuiMacro executor _guiMacroExecutor = new GuiMacroExecutor(startinfo.ConEmuConsoleServerExecutablePath); _lifetime.Add(() => ((IDisposable)_guiMacroExecutor).Dispose()); // Monitor payload process Init_ConsoleProcessMonitoring(); }
public override void StartProcess(string command, string arguments, string workdir) { var cmdl = new CommandLineBuilder(); cmdl.AppendFileNameIfNotNull(command /* do the escaping for it */); cmdl.AppendSwitch(arguments /* expecting to be already escaped */); var startinfo = new ConEmuStartInfo(); startinfo.ConsoleProcessCommandLine = cmdl.ToString(); startinfo.StartupDirectory = workdir; startinfo.WhenConsoleProcessExits = WhenConsoleProcessExits.KeepConsoleEmulatorAndShowMessage; startinfo.AnsiStreamChunkReceivedEventSink = (sender, args) => FireDataReceived(new TextEventArgs(args.GetText(GitModule.SystemEncoding))); startinfo.ConsoleProcessExitedEventSink = (sender, args) => { _nLastExitCode = args.ExitCode; FireProcessExited(); }; startinfo.ConsoleEmulatorClosedEventSink = (s, e) => { if (s == _terminal.RunningSession) { FireTerminated(); } }; startinfo.IsEchoingConsoleCommandLine = true; _terminal.Start(startinfo); }
public override void StartProcess(string command, string arguments, string workdir) { var cmdl = new StringBuilder(); if (command != null) { cmdl.Append(command.Quote() /* do the escaping for it */); cmdl.Append(" "); } cmdl.Append(arguments /* expecting to be already escaped */); var startinfo = new ConEmuStartInfo(); startinfo.ConsoleProcessCommandLine = cmdl.ToString(); startinfo.ConsoleProcessExtraArgs = " -cur_console:P:\"<Solarized Light>\""; startinfo.StartupDirectory = workdir; startinfo.WhenConsoleProcessExits = WhenConsoleProcessExits.KeepConsoleEmulatorAndShowMessage; startinfo.AnsiStreamChunkReceivedEventSink = (sender, args) => { var text = args.GetText(GitModule.SystemEncoding); if (EnvUtils.RunningOnWindows()) text = text.Replace("\n", Environment.NewLine); FireDataReceived(new TextEventArgs(text)); }; startinfo.ConsoleProcessExitedEventSink = (sender, args) => { _nLastExitCode = args.ExitCode; FireProcessExited(); }; startinfo.ConsoleEmulatorClosedEventSink = (s, e) => { if (s == _terminal.RunningSession) { FireTerminated(); } }; startinfo.IsEchoingConsoleCommandLine = true; _terminal.Start(startinfo); }
public ConEmuSession Start([NotNull] ConEmuStartInfo startinfo) { if(startinfo == null) throw new ArgumentNullException(nameof(startinfo)); // Close prev session if there is one _running?.CloseConsoleEmulator(); if(_running != null) throw new InvalidOperationException("Cannot start a new console process because another console emulator session has failed to close in due time."); _autostartinfo = null; // As we're starting, no more chance for an autostart if(!IsHandleCreated) CreateHandle(); // Spawn session var session = new ConEmuSession(startinfo, new ConEmuSession.HostContext((void*)Handle, IsStatusbarVisible)); _running = session; StateChanged?.Invoke(this, EventArgs.Empty); // Wait for its exit session.WaitForConsoleEmulatorCloseAsync().ContinueWith(scheduler : TaskScheduler.FromCurrentSynchronizationContext(), continuationAction : task => { try { _nLastExitCode = _running.GetConsoleProcessExitCode(); } catch(Exception) { // NOP } _running = null; Invalidate(); StateChanged?.Invoke(this, EventArgs.Empty); }); return session; }
public ConEmuSession Start([NotNull] ConEmuStartInfo startinfo, [NotNull] JoinableTaskFactory joinableTaskFactory, [NotNull] string conEmuStyle, string conEmuFontSize) { if (startinfo == null) { throw new ArgumentNullException(nameof(startinfo)); } SetConsoleFontSize(); SetConsoleStyle(); // Close prev session if there is one _running?.CloseConsoleEmulator(); if (_running != null) { throw new InvalidOperationException("Cannot start a new console process because another console emulator session has failed to close in due time."); } _autostartinfo = null; // As we're starting, no more chance for an autostart if (!IsHandleCreated) { CreateHandle(); } // Spawn session var session = new ConEmuSession(startinfo, new ConEmuSession.HostContext((void *)Handle, IsStatusbarVisible), joinableTaskFactory); _running = session; StateChanged?.Invoke(this, EventArgs.Empty); // Wait for its exit session.WaitForConsoleEmulatorCloseAsync().ContinueWith(scheduler: TaskScheduler.FromCurrentSynchronizationContext(), continuationAction: task => { try { _nLastExitCode = _running.GetConsoleProcessExitCode(); } catch (Exception) { // NOP } _running = null; Invalidate(); StateChanged?.Invoke(this, EventArgs.Empty); }).Forget(); return(session); void SetConsoleFontSize() { var startInfoBaseConfiguration = startinfo.BaseConfiguration; if (!string.IsNullOrWhiteSpace(conEmuFontSize)) { if (int.TryParse(conEmuFontSize, out var fontSize)) { var nodeFontSize = startInfoBaseConfiguration.SelectSingleNode("/key/key/key/value[@name='FontSize']"); if (nodeFontSize?.Attributes != null) { nodeFontSize.Attributes["data"].Value = fontSize.ToString("X8"); } } } startinfo.BaseConfiguration = startInfoBaseConfiguration; } void SetConsoleStyle() { if (conEmuStyle != "Default") { startinfo.ConsoleProcessExtraArgs = " -new_console:P:\"" + conEmuStyle + "\""; } } }