Manages reading the ANSI log output of the conemu and firing events with its data to the user.
Inheritance: IDisposable
Esempio n. 1
0
        /// <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();
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
		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;
		}
Esempio n. 5
0
		/// <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();
		}