├── Deploy ├── .gitignore ├── sign.cmd ├── upload.nuget-org.cmd ├── build.cmd ├── build.nuget-org.cmd └── UpdatePackageVersions.ps1 ├── ConEmuWinForms ├── Snk.Snk ├── package │ ├── icon.png │ └── license.txt ├── packages.config ├── Util │ ├── INotifyCompletion.cs │ ├── IAsyncStateMachine.cs │ ├── ICriticalNotifyCompletion.cs │ ├── TaskAwaiter.cs │ ├── TaskAwaiter!1.cs │ ├── AsyncTaskMethodBuilder!1.cs │ ├── TaskHelpers.cs │ └── WinApi.cs ├── ConsoleProcessExitedEventArgs.cs ├── GuiMacroResult.cs ├── AssemblyInfo.cs ├── ConEmuConstants.cs ├── AnsiStreamChunkEventArgs.cs ├── States.cs ├── Package.nuspec ├── WhenConsoleProcessExits.cs ├── Resources.Designer.cs ├── GuiMacroBuilder.cs ├── AnsiLog.cs ├── ConEmuWinForms.csproj ├── GetInfoRoot.cs ├── Resources.resx ├── GuiMacroExecutor.cs ├── ConEmu.xml └── ConEmuControl.cs ├── Samples └── ConsoleUtilityShowcase │ ├── packages.config │ ├── Program.cs │ └── ConsoleUtilityShowcase.csproj ├── .gitignore ├── ConEmuInside ├── App.config ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Program.cs ├── ConEmuStartArgs.cs ├── StarterForm.cs ├── ConEmuInside.csproj ├── StarterForm.resx ├── TerminalForm.resx ├── TerminalForm.Designer.cs ├── ConEmu.xml ├── GuiMacro.cs ├── TerminalForm.cs └── StarterForm.Designer.cs ├── ConEmuInside.sln.DotSettings ├── Tests └── ControlDllTestbed │ ├── ControlDllTestbed.csproj │ └── Testbed.cs ├── README.md └── ConEmuInside.sln /Deploy/.gitignore: -------------------------------------------------------------------------------- 1 | *.nupkg 2 | *.7z 3 | user_env.cmd 4 | -------------------------------------------------------------------------------- /ConEmuWinForms/Snk.Snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConEmu/conemu-inside/HEAD/ConEmuWinForms/Snk.Snk -------------------------------------------------------------------------------- /ConEmuWinForms/package/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConEmu/conemu-inside/HEAD/ConEmuWinForms/package/icon.png -------------------------------------------------------------------------------- /ConEmuWinForms/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Samples/ConsoleUtilityShowcase/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _*.sln 2 | *.exe 3 | bin 4 | obj 5 | *.user 6 | .vs 7 | *.sdf 8 | *.opensdf 9 | 10 | ConEmu.CommandLine/Tools/ConEmu/* 11 | *.nupkg 12 | packages/** 13 | *.opendb 14 | -------------------------------------------------------------------------------- /ConEmuInside/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Deploy/sign.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | setlocal 4 | 5 | if exist "%~dp0user_env.cmd" ( 6 | call "%~dp0user_env.cmd" 7 | ) 8 | 9 | if exist "%CONEMU_DEPLOY%sign_any.bat" ( 10 | call "%CONEMU_DEPLOY%sign_any.bat" %* 11 | ) 12 | 13 | endlocal 14 | -------------------------------------------------------------------------------- /ConEmuWinForms/Util/INotifyCompletion.cs: -------------------------------------------------------------------------------- 1 | 2 | #pragma warning disable CheckNamespace 3 | 4 | namespace System.Runtime.CompilerServices 5 | { 6 | internal interface INotifyCompletion 7 | { 8 | void OnCompleted(Action continuation); 9 | } 10 | } -------------------------------------------------------------------------------- /ConEmuInside/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ConEmuWinForms/Util/IAsyncStateMachine.cs: -------------------------------------------------------------------------------- 1 | 2 | #pragma warning disable CheckNamespace 3 | 4 | namespace System.Runtime.CompilerServices 5 | { 6 | internal interface IAsyncStateMachine 7 | { 8 | void MoveNext(); 9 | 10 | void SetStateMachine(IAsyncStateMachine stateMachine); 11 | } 12 | } -------------------------------------------------------------------------------- /ConEmuWinForms/Util/ICriticalNotifyCompletion.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CheckNamespace 2 | using System.Security; 3 | 4 | namespace System.Runtime.CompilerServices 5 | { 6 | internal interface ICriticalNotifyCompletion : INotifyCompletion 7 | { 8 | [SecurityCritical] 9 | void UnsafeOnCompleted(Action continuation); 10 | } 11 | } -------------------------------------------------------------------------------- /Deploy/upload.nuget-org.cmd: -------------------------------------------------------------------------------- 1 | setlocal 2 | set "PATH=%~dp0..\..\Tools\Nuget\bin;%PATH%" 3 | cd /d "%~dp0" 4 | if "%~1" == "" ( 5 | for %%g in (ConEmu.Control.WinForms.*.nupkg) do ( 6 | call ..\..\Tools\Uploaders\ConEmuUploadNuget.cmd %%g -Source https://www.nuget.org/api/v2/package 7 | ) 8 | ) else ( 9 | call ..\..\Tools\Uploaders\ConEmuUploadNuget.cmd %* -Source https://www.nuget.org/api/v2/package 10 | ) 11 | -------------------------------------------------------------------------------- /ConEmuInside/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace ConEmuInside 5 | { 6 | static class Program 7 | { 8 | /// 9 | /// The main entry point for the application. 10 | /// 11 | [STAThread] 12 | static void Main() 13 | { 14 | Application.EnableVisualStyles(); 15 | Application.SetCompatibleTextRenderingDefault(false); 16 | Application.Run(new TerminalStarter()); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ConEmuInside/ConEmuStartArgs.cs: -------------------------------------------------------------------------------- 1 | namespace ConEmuInside 2 | { 3 | internal class ConEmuStartArgs 4 | { 5 | internal bool runAs = false; 6 | 7 | internal bool debug = false; 8 | 9 | internal bool log = false; 10 | 11 | internal bool autoClose = false; 12 | 13 | internal bool useGuiMacro = false; 14 | 15 | internal string xmlFilePath = ""; 16 | 17 | internal string startupDirectory = ""; 18 | 19 | internal string cmdLine = ""; 20 | 21 | internal string conemuExePath = ""; 22 | } 23 | } -------------------------------------------------------------------------------- /ConEmuWinForms/ConsoleProcessExitedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ConEmu.WinForms 4 | { 5 | /// 6 | /// Gives the exit code of the console process when it exits in the console emulator. 7 | /// 8 | public class ConsoleProcessExitedEventArgs : EventArgs 9 | { 10 | public ConsoleProcessExitedEventArgs(int exitcode) 11 | { 12 | ExitCode = exitcode; 13 | } 14 | 15 | /// 16 | /// Gets the exit code of the console process. 17 | /// 18 | public int ExitCode { get; } 19 | } 20 | } -------------------------------------------------------------------------------- /ConEmuWinForms/GuiMacroResult.cs: -------------------------------------------------------------------------------- 1 | namespace ConEmu.WinForms 2 | { 3 | /// 4 | /// A result of executing the GUI macro. 5 | /// 6 | public struct GuiMacroResult 7 | { 8 | /// 9 | /// Whether macro execution returned success. 10 | /// 11 | public bool IsSuccessful; 12 | 13 | /// 14 | /// String response of the command, “OK” if successful and without output. 15 | /// 16 | public string Response; 17 | 18 | public override string ToString() 19 | { 20 | return $"{Response} ({(IsSuccessful ? "Succeeded" : "Failed")})"; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /ConEmuWinForms/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly : AssemblyTitle("ConEmuWinForms")] 4 | [assembly : AssemblyDescription("This is a console emulator control that embeds a fully functional console view in a Windows Forms window.")] 5 | [assembly : AssemblyProduct("ConEmu")] 6 | [assembly : AssemblyCopyright("Copyright © hypersw, Maximus5, 2015–2021")] 7 | 8 | // These versions must remain 1.0 as soon as API is considered compatible, this will allow the compiled code to be compatible with minor updates 9 | // Do not use the nuget version here 10 | [assembly : AssemblyVersion("1.21.9.5")] 11 | [assembly : AssemblyFileVersion("1.21.9.5")] 12 | -------------------------------------------------------------------------------- /Deploy/build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | if "%~1" == "" ( 5 | echo Usage: build.cmd ^ 6 | exit /b 1 7 | ) 8 | set CurVerBuild=%~1 9 | 10 | powershell -noprofile -ExecutionPolicy RemoteSigned -command "%~dp0UpdatePackageVersions.ps1" %CurVerBuild% 11 | if errorlevel 1 exit /b 1 12 | 13 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat" 14 | if errorlevel 1 exit /b 1 15 | 16 | cd /d "%~dp0.." 17 | msbuild ConEmuInside.sln -t:Rebuild -p:"Configuration=Release";"Platform=Any CPU" 18 | if errorlevel 1 exit /b 1 19 | 20 | cd /d "%~dp0..\ConEmuInside\bin\Release" 21 | 22 | rem if not exist "%~dp0sign.cmd" ( 23 | rem echo sign.cmd not found, skipping 24 | rem goto skip_sign 25 | rem ) 26 | rem call "%~dp0sign.cmd" ConEmu.WinForms.dll ConEmuInside.exe 27 | rem :skip_sign 28 | -------------------------------------------------------------------------------- /ConEmuWinForms/Util/TaskAwaiter.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | using ConEmu.WinForms.Util; 4 | 5 | #pragma warning disable CheckNamespace 6 | 7 | namespace System.Threading.Tasks 8 | { 9 | internal struct TaskAwaiter : INotifyCompletion 10 | { 11 | private readonly bool _isctx; 12 | 13 | private readonly Task _task; 14 | 15 | internal TaskAwaiter(Task task, bool isctx = true) 16 | { 17 | _task = task; 18 | _isctx = isctx; 19 | } 20 | 21 | public bool IsCompleted => _task.IsCompleted; 22 | 23 | public void GetResult() 24 | { 25 | _task.Wait(); 26 | } 27 | 28 | public void OnCompleted(Action continuation) 29 | { 30 | _task.ContinueWith(param0 => continuation(), _isctx ? TaskHelpers.GetTaskSchedulerFromContext() : TaskScheduler.Default); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /ConEmuWinForms/Util/TaskAwaiter!1.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | using ConEmu.WinForms.Util; 4 | 5 | #pragma warning disable CheckNamespace 6 | 7 | namespace System.Threading.Tasks 8 | { 9 | internal struct TaskAwaiter : INotifyCompletion 10 | { 11 | private readonly bool _isctx; 12 | 13 | private readonly Task _task; 14 | 15 | public TaskAwaiter(Task task, bool isctx = true) 16 | { 17 | _task = task; 18 | _isctx = isctx; 19 | } 20 | 21 | public bool IsCompleted => _task.IsCompleted; 22 | 23 | public TResult GetResult() 24 | { 25 | return _task.Result; 26 | } 27 | 28 | public void OnCompleted(Action continuation) 29 | { 30 | _task.ContinueWith(param0 => continuation(), _isctx ? TaskHelpers.GetTaskSchedulerFromContext() : TaskScheduler.Default); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /ConEmuInside.sln.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 3 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 4 | True 5 | True 6 | True -------------------------------------------------------------------------------- /ConEmuWinForms/ConEmuConstants.cs: -------------------------------------------------------------------------------- 1 | using JetBrains.Annotations; 2 | 3 | namespace ConEmu.WinForms 4 | { 5 | public static class ConEmuConstants 6 | { 7 | [NotNull] 8 | public static readonly string ConEmuConsoleExtenderExeName = "ConEmuC.exe"; 9 | 10 | [NotNull] 11 | public static readonly string ConEmuConsoleServerFileNameNoExt = "ConEmuCD"; 12 | 13 | [NotNull] 14 | public static readonly string ConEmuExeName = "conemu.exe"; 15 | 16 | [NotNull] 17 | public static readonly string ConEmuSubfolderName = "ConEmu"; 18 | 19 | /// 20 | /// The default for . 21 | /// Runs the stock ConEmu task for the Windows command line. 22 | /// 23 | public static readonly string DefaultConsoleCommandLine = "{cmd}"; 24 | 25 | public static readonly string XmlAttrName = "name"; 26 | 27 | public static readonly string XmlElementKey = "key"; 28 | 29 | public static readonly string XmlValueConEmu = "ConEmu"; 30 | 31 | public static readonly string XmlValueDotVanilla = ".Vanilla"; 32 | 33 | public static readonly string XmlValueSoftware = "Software"; 34 | } 35 | } -------------------------------------------------------------------------------- /ConEmuInside/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ConEmuInside.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Deploy/build.nuget-org.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | rem EXPECTED TO BE CALLED AFTER build.cmd 5 | 6 | set "PATH=%~dp0..\..\Tools\Nuget\bin;%~dp0..\..\Tools\Arch;%PATH%" 7 | cd /d "%~dp0..\ConEmuInside\bin\Release" 8 | 9 | if exist "ConEmu.Control.WinForms.*.nupkg" del "ConEmu.Control.WinForms.*.nupkg" 10 | if exist "%~dp0ConEmu.Control.WinForms.*.nupkg" del "%~dp0ConEmu.Control.WinForms.*.nupkg" 11 | 12 | call nuget pack -Verbosity detailed -NoDefaultExcludes 13 | if errorlevel 1 ( 14 | call cecho "Failed to create the package ConEmu.Control.WinForms for Nuget.Org." 15 | exit /b 100 16 | ) 17 | call cecho /green "A package for Nuget.Org were created." 18 | 19 | move "%~dp0..\ConEmuInside\bin\Release\ConEmu.Control.WinForms.*.nupkg" "%~dp0" 20 | if errorlevel 1 ( 21 | call cecho "Moving ConEmu.Control.WinForms package failed." 22 | exit /b 100 23 | ) 24 | 25 | set BUILD_NO=21.9.5 26 | 7z a ConEmuInside.%BUILD_NO%.7z *.exe *.dll ConEmu.xml *.config ConEmu\* 27 | if errorlevel 1 ( 28 | call cecho "Failed to create the 7zip package." 29 | exit /b 100 30 | ) 31 | 7z a ConEmuInside.pdb.%BUILD_NO%.7z *.pdb 32 | if errorlevel 1 ( 33 | call cecho "Failed to create the 7zip package." 34 | exit /b 100 35 | ) 36 | move "%~dp0..\ConEmuInside\bin\Release\ConEmuInside.*.7z" "%~dp0" 37 | if errorlevel 1 ( 38 | call cecho "Moving ConEmu.Control.WinForms package failed." 39 | exit /b 100 40 | ) 41 | -------------------------------------------------------------------------------- /ConEmuInside/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ConEmu-Inside")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("ConEmu-Maximus5")] 12 | [assembly: AssemblyProduct("ConEmuInside")] 13 | [assembly: AssemblyCopyright("© ConEmu.Maximus5@gmail.com")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("44d33e8f-7f78-417d-aa78-e42aee2071e3")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.3.0.0")] 36 | [assembly: AssemblyFileVersion("0.3.0.0")] 37 | -------------------------------------------------------------------------------- /ConEmuWinForms/Util/AsyncTaskMethodBuilder!1.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CheckNamespace 2 | using System.Threading.Tasks; 3 | 4 | namespace System.Runtime.CompilerServices 5 | { 6 | internal struct AsyncTaskMethodBuilder 7 | { 8 | private TaskCompletionSource _tasker; 9 | 10 | public Task Task => _tasker.Task; 11 | 12 | public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine 13 | { 14 | awaiter.OnCompleted(((IAsyncStateMachine)stateMachine).MoveNext); 15 | } 16 | 17 | public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine 18 | { 19 | AwaitOnCompleted(ref awaiter, ref stateMachine); 20 | } 21 | 22 | public static AsyncTaskMethodBuilder Create() 23 | { 24 | AsyncTaskMethodBuilder taskMethodBuilder; 25 | taskMethodBuilder._tasker = new TaskCompletionSource(); 26 | return taskMethodBuilder; 27 | } 28 | 29 | public void SetException(Exception exception) 30 | { 31 | _tasker.SetException(exception); 32 | } 33 | 34 | public void SetResult(TResult result) 35 | { 36 | _tasker.SetResult(result); 37 | } 38 | 39 | public void SetStateMachine(IAsyncStateMachine stateMachine) 40 | { 41 | throw new NotImplementedException(); 42 | } 43 | 44 | public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine 45 | { 46 | stateMachine.MoveNext(); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /ConEmuWinForms/AnsiStreamChunkEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | using JetBrains.Annotations; 5 | 6 | namespace ConEmu.WinForms 7 | { 8 | /// 9 | /// Holds the new chunk of the console ANSI stream. 10 | /// 11 | public class AnsiStreamChunkEventArgs : EventArgs 12 | { 13 | [NotNull] 14 | private readonly byte[] _chunk; 15 | 16 | public AnsiStreamChunkEventArgs([NotNull] byte[] chunk) 17 | { 18 | if(chunk == null) 19 | throw new ArgumentNullException(nameof(chunk)); 20 | if(chunk.Length == 0) 21 | throw new ArgumentOutOfRangeException(nameof(chunk), chunk, "Empty data is not a valid stream chunk."); 22 | _chunk = chunk; 23 | } 24 | 25 | /// 26 | /// Gets the raw bytes of the chunk. 27 | /// 28 | [NotNull] 29 | public byte[] Chunk => _chunk; 30 | 31 | /// 32 | /// Assuming the stream is encoded in the current system's MBCS encoding, gets its text. 33 | /// 34 | public string GetMbcsText() 35 | { 36 | return Encoding.Default.GetString(_chunk); 37 | } 38 | 39 | /// 40 | /// Gets the text of the chunk assuming it's in the specific encoding. 41 | /// 42 | public string GetText([NotNull] Encoding encoding) 43 | { 44 | if(encoding == null) 45 | throw new ArgumentNullException(nameof(encoding)); 46 | return encoding.GetString(_chunk); 47 | } 48 | 49 | public override string ToString() 50 | { 51 | try 52 | { 53 | return $"({_chunk.Length:N0} bytes) {GetMbcsText()}"; 54 | } 55 | catch(Exception ex) 56 | { 57 | return $"({_chunk.Length:N0} bytes) Error getting chunk text. {ex.Message}"; 58 | } 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /Tests/ControlDllTestbed/ControlDllTestbed.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Default 5 | AnyCPU 6 | {FEE30B4B-149C-4878-9C62-8ADEF4C8A6C1} 7 | WinExe 8 | ControlDllTestbed 9 | ControlDllTestbed 10 | v4.5.2 11 | 12 | 13 | AnyCPU 14 | true 15 | full 16 | false 17 | bin\ 18 | DEBUG;TRACE 19 | prompt 20 | 4 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | {1DC7D403-484B-43B4-B017-1356397A32CB} 34 | ConEmuWinForms 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ConEmuWinForms/States.cs: -------------------------------------------------------------------------------- 1 | namespace ConEmu.WinForms 2 | { 3 | /// 4 | /// states. 5 | /// 6 | public enum States 7 | { 8 | /// 9 | /// There has been no console emulator opened in this control yet. 10 | /// The control is now empty, and is NULL. A new session can be started with . 11 | /// 12 | Unused = 0, 13 | 14 | /// 15 | /// The console emulator is open, and the console process is running in it. 16 | /// is available. A new session cannot be started until the current session is closed (). 17 | /// 18 | ConsoleEmulatorWithConsoleProcess = 1, 19 | 20 | /// 21 | /// The console emulator is still open, but the console process in it has already exited, even though the console view is still visible in the control. 22 | /// The console emulator stays open in this case if allows it. 23 | /// is available. A new session cannot be started until the current session is closed (). 24 | /// 25 | ConsoleEmulatorEmpty = 2, 26 | 27 | /// 28 | /// There were a console emulator in this control, but its console process has exited, and then the terminal were closed. 29 | /// The control is now empty and not showing the console view, and is NULL. A new session can be started with . 30 | /// 31 | Recycled = 3 32 | } 33 | } -------------------------------------------------------------------------------- /ConEmuWinForms/Package.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ConEmu.Control.WinForms 5 | 6 | 1.21.9.5 7 | ConEmu Console Emulator — Windows Forms Control Embedding 8 | Maximus5,hypersw 9 | Maximus5,hypersw 10 | 11 | https://conemu.github.io/ 12 | images\icon.png 13 | https://conemu.github.io/en/Whats_New.html 14 | 15 | © 2021, Maksim Moisiuk 16 | false 17 | license\license.txt 18 | 19 | 20 | This is a console emulator control that embeds a fully functional console view in a Windows Forms window. 21 | 22 | 23 | This is a console emulator control that embeds a fully functional console view in a Windows Forms window. 24 | It is capable of running any console application with full interactivity and advanced console functions. 25 | Applications will detect it as an actual console and will not fall back to the output redirection mode with 26 | reduced interactivity or formatting. 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Deploy/UpdatePackageVersions.ps1: -------------------------------------------------------------------------------- 1 | param([string]$build="") 2 | 3 | # This file will update PortableApps and Chocolatey versions 4 | 5 | $Script_File_path = split-path -parent $MyInvocation.MyCommand.Definition 6 | $NuSpec = Join-Path $Script_File_path "..\ConEmuWinForms\Package.nuspec" 7 | $Assembly = Join-Path $Script_File_path "..\ConEmuWinForms\AssemblyInfo.cs" 8 | 9 | if ($build -eq "") { 10 | $build = $env:CurVerBuild 11 | } 12 | 13 | if (($build -eq $null) -Or (-Not ($build -match "\b\d\d\d\d\d\d(\w*)\b"))) { 14 | Write-Host -ForegroundColor Red "Build was not passed as argument!" 15 | $host.SetShouldExit(101) 16 | exit 17 | } 18 | 19 | $build_dot4 = "1.$($build.SubString(0,2)).$($build.SubString(2,2).TrimStart('0')).$($build.SubString(4,2).TrimStart('0'))" 20 | 21 | Write-Host -ForegroundColor Yellow "Updating files with build# $build" 22 | 23 | 24 | # 25 | # Helper to update NuSpec-s 26 | # 27 | function NuSpec-SetBuild([string]$XmlFile) { 28 | Write-Host -ForegroundColor Green $XmlFile 29 | $xml = Get-Content -Raw $XmlFile -Encoding UTF8 30 | $m = ([regex]'\d+\.\d+\.\d+\.\d+<\/version>').Matches($xml) 31 | if (($m -eq $null) -Or ($m.Count -ne 1)) { 32 | Write-Host -ForegroundColor Red "Proper ... tag was not found in:`r`n$XmlFile" 33 | $host.SetShouldExit(101) 34 | return $FALSE 35 | } 36 | $xml = $xml.Replace($m[0].Value, "$build_dot4").Trim() 37 | Set-Content $XmlFile $xml -Encoding UTF8 38 | return $TRUE 39 | } 40 | 41 | # 42 | # Helper to update Assemblies 43 | # 44 | function Assembly-SetBuild([string]$AsmFile) { 45 | Write-Host -ForegroundColor Green $AsmFile 46 | $cs = Get-Content -Raw $AsmFile -Encoding UTF8 47 | $m = ([regex]'Version\("\d+\.\d+\.\d+\.\d+"\)').Matches($cs) 48 | if (($m -eq $null) -Or ($m.Count -ne 2)) { 49 | Write-Host -ForegroundColor Red "Proper ...Version(...) tag was not found in:`r`n$AsmFile" 50 | $host.SetShouldExit(101) 51 | return $FALSE 52 | } 53 | $cs = $cs.Replace($m[0].Value, "Version(`"$build_dot4`")").Trim() 54 | Set-Content $AsmFile $cs -Encoding UTF8 55 | return $TRUE 56 | } 57 | 58 | 59 | 60 | # 61 | # Nuget.org : ConEmuWinForms\Package.nuspec 62 | # 63 | if (-Not (NuSpec-SetBuild $NuSpec)) { 64 | exit 65 | } 66 | 67 | # 68 | # Nuget.org : ConEmuWinForms\AssemblyInfo.cs 69 | # 70 | if (-Not (Assembly-SetBuild $Assembly)) { 71 | exit 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ConEmu Inside 2 | This is an example, how [ConEmu-Maximus5](https://conemu.github.io) 3 | may be embedded into third-party graphical applications. 4 | 5 | ConEmu build 210905 or higher is required. 6 | 7 | 8 | ## Screenshots 9 | ![ConEmu Inside](https://github.com/Maximus5/conemu-inside/wiki/ConEmu-Inside.png) 10 | 11 | 12 | ## Solution's projects 13 | 14 | Solution `ConEmuInside.sln` contains several projects. 15 | 16 | * ConEmuInside: Example, how you may run (directly) `ConEmu.exe` to embed it 17 | into your application. 18 | * ConEmuWinForms: Source for nuget package 19 | [ConEmu.Control.WinForms](https://www.nuget.org/packages/ConEmu.Control.WinForms/). 20 | * ConsoleUtilityShowcase: An example how to use 21 | [ConEmu.Control.WinForms](https://www.nuget.org/packages/ConEmu.Control.WinForms/). 22 | * ControlDllTestbed: For testing... 23 | 24 | 25 | ## License (BSD 3-clause) 26 | 27 | Copyright (c) 2021, Maksim Moisiuk 28 | 29 | Redistribution and use in source and binary forms, with or without 30 | modification, are permitted provided that the following conditions 31 | are met: 32 | 1. Redistributions of source code must retain the above copyright 33 | notice, this list of conditions and the following disclaimer. 34 | 2. Redistributions in binary form must reproduce the above copyright 35 | notice, this list of conditions and the following disclaimer in the 36 | documentation and/or other materials provided with the distribution. 37 | 3. The name of the authors may not be used to endorse or promote products 38 | derived from this software without specific prior written permission. 39 | 40 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR 41 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 42 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 43 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 44 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 46 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 47 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 48 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 49 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | -------------------------------------------------------------------------------- /ConEmuWinForms/WhenConsoleProcessExits.cs: -------------------------------------------------------------------------------- 1 | namespace ConEmu.WinForms 2 | { 3 | /// 4 | /// Controls behavior of the console emulator when the console process running in it terminates. 5 | /// 6 | public enum WhenConsoleProcessExits 7 | { 8 | /// 9 | /// When the console process exits, the console emulator is closed, and its window is hidden from the control. 10 | /// The control shows blank space, output text disappears. 11 | /// and are both fired at this moment. 12 | /// The console emulator control is ready for running a new session. 13 | /// 14 | CloseConsoleEmulator, 15 | 16 | /// 17 | /// When the console process exits, the console emulator stays open, and its window remains visible in the control, with all the console output text. 18 | /// No additional message is written to the console output, but you can still use to write any text. 19 | /// Pressing ESC or ENTER closes the console emulator, makes the control blank, and allows to run further console emulator sessions in this control. 20 | /// fires immediately, and fires on user's ESC/ENTER, or when the console emulator is closed programmatically. 21 | /// 22 | KeepConsoleEmulator, 23 | 24 | /// 25 | /// When the console process exits, the console emulator stays open, and its window remains visible in the control, with all the console output text. 26 | /// The message “Press Enter or Esc to close console...” is displayed. 27 | /// Pressing ESC or ENTER closes the console emulator, makes the control blank, and allows to run further console emulator sessions in this control. 28 | /// fires immediately, and fires on user's ESC/ENTER, or when the console emulator is closed programmatically. 29 | /// 30 | KeepConsoleEmulatorAndShowMessage 31 | } 32 | } -------------------------------------------------------------------------------- /ConEmuWinForms/Util/TaskHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | using JetBrains.Annotations; 7 | 8 | namespace ConEmu.WinForms.Util 9 | { 10 | internal static class TaskHelpers 11 | { 12 | private static Task _completedTask; 13 | 14 | /// Gets a task that's already been completed successfully. 15 | [NotNull] 16 | public static Task CompletedTask 17 | { 18 | get 19 | { 20 | Task task = _completedTask; 21 | if(task == null) 22 | { 23 | var src = new TaskCompletionSource(); 24 | src.SetResult(Missing.Value); 25 | _completedTask = task = src.Task; 26 | } 27 | return task; 28 | } 29 | } 30 | 31 | /// 32 | /// Creates a started tasks which will get a completed state after the specified amount of time. 33 | /// 34 | [NotNull] 35 | public static Task Delay(TimeSpan delay) 36 | { 37 | if(delay.Ticks < 0L) 38 | throw new ArgumentOutOfRangeException(nameof(delay), "The timeout must be non-negative."); 39 | var tasker = new TaskCompletionSource(); 40 | Timer timer = null; 41 | timer = new Timer(o => 42 | { 43 | timer.Dispose(); 44 | tasker.TrySetResult(true); 45 | }, Missing.Value, -1, -1); 46 | timer.Change(delay, TimeSpan.FromMilliseconds(-1.0)); 47 | return tasker.Task; 48 | } 49 | 50 | /// Gets a task that's already been completed successfully. 51 | [NotNull] 52 | public static Task FromResult(TResult result) 53 | { 54 | var completionSource = new TaskCompletionSource(result); 55 | completionSource.TrySetResult(result); 56 | return completionSource.Task; 57 | } 58 | 59 | public static TaskAwaiter GetAwaiter(this Task task) 60 | { 61 | return new TaskAwaiter(task, true); 62 | } 63 | 64 | public static TaskAwaiter GetAwaiter(this Task task) 65 | { 66 | return new TaskAwaiter(task, true); 67 | } 68 | 69 | public static TaskAwaiter GetAwaiter(this Task task) 70 | { 71 | return task.Unwrap().GetAwaiter(); 72 | } 73 | 74 | public static TaskAwaiter GetAwaiter(this Task> task) 75 | { 76 | return task.Unwrap().GetAwaiter(); 77 | } 78 | 79 | internal static TaskScheduler GetTaskSchedulerFromContext() 80 | { 81 | return SynchronizationContext.Current == null ? TaskScheduler.Current : TaskScheduler.FromCurrentSynchronizationContext(); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /ConEmuInside/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ConEmuInside.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ConEmuInside.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ConEmuInside.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30406.217 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConEmuInside", "ConEmuInside\ConEmuInside.csproj", "{44D33E8F-7F78-417D-AA78-E42AEE2071E3}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConEmuWinForms", "ConEmuWinForms\ConEmuWinForms.csproj", "{1DC7D403-484B-43B4-B017-1356397A32CB}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleUtilityShowcase", "Samples\ConsoleUtilityShowcase\ConsoleUtilityShowcase.csproj", "{ECD0914D-ABAE-468A-9265-10E6DFF6EB80}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlDllTestbed", "Tests\ControlDllTestbed\ControlDllTestbed.csproj", "{FEE30B4B-149C-4878-9C62-8ADEF4C8A6C1}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6E427565-9D1D-4D62-81B1-202DA95D7CDA}" 15 | ProjectSection(SolutionItems) = preProject 16 | README.md = README.md 17 | EndProjectSection 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|Any CPU = Debug|Any CPU 22 | Release|Any CPU = Release|Any CPU 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {44D33E8F-7F78-417D-AA78-E42AEE2071E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {44D33E8F-7F78-417D-AA78-E42AEE2071E3}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {44D33E8F-7F78-417D-AA78-E42AEE2071E3}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {44D33E8F-7F78-417D-AA78-E42AEE2071E3}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {1DC7D403-484B-43B4-B017-1356397A32CB}.Debug|Any CPU.ActiveCfg = Default|Any CPU 30 | {1DC7D403-484B-43B4-B017-1356397A32CB}.Debug|Any CPU.Build.0 = Default|Any CPU 31 | {1DC7D403-484B-43B4-B017-1356397A32CB}.Release|Any CPU.ActiveCfg = Default|Any CPU 32 | {1DC7D403-484B-43B4-B017-1356397A32CB}.Release|Any CPU.Build.0 = Default|Any CPU 33 | {ECD0914D-ABAE-468A-9265-10E6DFF6EB80}.Debug|Any CPU.ActiveCfg = Default|Any CPU 34 | {ECD0914D-ABAE-468A-9265-10E6DFF6EB80}.Debug|Any CPU.Build.0 = Default|Any CPU 35 | {ECD0914D-ABAE-468A-9265-10E6DFF6EB80}.Release|Any CPU.ActiveCfg = Default|Any CPU 36 | {ECD0914D-ABAE-468A-9265-10E6DFF6EB80}.Release|Any CPU.Build.0 = Default|Any CPU 37 | {FEE30B4B-149C-4878-9C62-8ADEF4C8A6C1}.Debug|Any CPU.ActiveCfg = Default|Any CPU 38 | {FEE30B4B-149C-4878-9C62-8ADEF4C8A6C1}.Debug|Any CPU.Build.0 = Default|Any CPU 39 | {FEE30B4B-149C-4878-9C62-8ADEF4C8A6C1}.Release|Any CPU.ActiveCfg = Default|Any CPU 40 | {FEE30B4B-149C-4878-9C62-8ADEF4C8A6C1}.Release|Any CPU.Build.0 = Default|Any CPU 41 | EndGlobalSection 42 | GlobalSection(SolutionProperties) = preSolution 43 | HideSolutionNode = FALSE 44 | EndGlobalSection 45 | GlobalSection(ExtensibilityGlobals) = postSolution 46 | SolutionGuid = {276FC0EF-9EF3-44A9-8FDF-B195E76EA89C} 47 | EndGlobalSection 48 | EndGlobal 49 | -------------------------------------------------------------------------------- /ConEmuWinForms/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ConEmu.WinForms { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ConEmu.WinForms.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Byte[]. 65 | /// 66 | internal static byte[] ConEmuSettingsTemplate { 67 | get { 68 | object obj = ResourceManager.GetObject("ConEmuSettingsTemplate", resourceCulture); 69 | return ((byte[])(obj)); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Samples/ConsoleUtilityShowcase/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Text; 4 | using System.Text.RegularExpressions; 5 | using System.Windows.Forms; 6 | 7 | using ConEmu.WinForms; 8 | 9 | namespace ConsoleUtilityShowcase 10 | { 11 | internal static class Program 12 | { 13 | private static Form CreateMainForm() 14 | { 15 | var form = new Form() {AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink, Padding = new Padding(10), Text = "Console Utility in a Terminal"}; 16 | 17 | FlowLayoutPanel stack; 18 | form.Controls.Add(stack = new FlowLayoutPanel() {Dock = DockStyle.Fill, AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink, FlowDirection = FlowDirection.TopDown}); 19 | 20 | stack.Controls.Add(new Label() {AutoSize = true, Dock = DockStyle.Top, Text = "This sample illustrates running a console utility\npresenting the user a real terminal window to its console\nas a control embedded in the form.\n\nThe program also gets the output of the utility,\nthough presenting its progress to the user is the main goal.\n\n"}); 21 | 22 | Button btnPing; 23 | stack.Controls.Add(btnPing = new Button() {Text = "Run ping", Dock = DockStyle.Left}); 24 | btnPing.Click += delegate { CreatePingForm().ShowDialog(form); }; 25 | return form; 26 | } 27 | 28 | private static Form CreatePingForm() 29 | { 30 | var form = new Form() {AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink, Padding = new Padding(10), Text = "Ping Command"}; 31 | 32 | FlowLayoutPanel stack; 33 | form.Controls.Add(stack = new FlowLayoutPanel() {Dock = DockStyle.Fill, AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink, FlowDirection = FlowDirection.TopDown}); 34 | 35 | stack.Controls.Add(new Label() {AutoSize = true, Dock = DockStyle.Top, Text = "Running the ping command.", Padding = new Padding(5)}); 36 | Label labelWaitOrResult; 37 | stack.Controls.Add(labelWaitOrResult = new Label() {AutoSize = true, Dock = DockStyle.Top, Text = "Please wait…", BackColor = Color.Yellow, Padding = new Padding(5)}); 38 | 39 | ConEmuControl conemu; 40 | var sbText = new StringBuilder(); 41 | stack.Controls.Add(conemu = new ConEmuControl() {AutoStartInfo = null, MinimumSize = new Size(800, 600), Dock = DockStyle.Top}); 42 | ConEmuSession session = conemu.Start(new ConEmuStartInfo() { 43 | AnsiStreamChunkReceivedEventSink = (sender, args) => sbText.Append(args.GetMbcsText()), 44 | ConsoleProcessCommandLine = "ping 8.8.8.8", 45 | LogLevel = ConEmuStartInfo.LogLevels.Basic 46 | }); 47 | session.ConsoleProcessExited += delegate 48 | { 49 | Match match = Regex.Match(sbText.ToString(), @"\(.*\b(?\d+)%.*?\)", RegexOptions.Multiline); 50 | if(!match.Success) 51 | { 52 | labelWaitOrResult.Text = "Ping execution completed, failed to parse the result."; 53 | labelWaitOrResult.BackColor = Color.PaleVioletRed; 54 | } 55 | else 56 | { 57 | labelWaitOrResult.Text = $"Ping execution completed, lost {match.Groups["pc"].Value} per cent of packets."; 58 | labelWaitOrResult.BackColor = Color.Lime; 59 | } 60 | }; 61 | session.ConsoleEmulatorClosed += delegate { form.Close(); }; 62 | 63 | return form; 64 | } 65 | 66 | /// 67 | /// The main entry point for the application. 68 | /// 69 | [STAThread] 70 | private static void Main() 71 | { 72 | Application.EnableVisualStyles(); 73 | Application.SetCompatibleTextRenderingDefault(false); 74 | Application.Run(CreateMainForm()); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Samples/ConsoleUtilityShowcase/ConsoleUtilityShowcase.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Default 6 | AnyCPU 7 | {ECD0914D-ABAE-468A-9265-10E6DFF6EB80} 8 | WinExe 9 | ConsoleUtilityShowcase 10 | ConsoleUtilityShowcase 11 | v4.5 12 | 512 13 | true 14 | 15 | 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\ 23 | TRACE 24 | prompt 25 | 4 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | {1dc7d403-484b-43b4-b017-1356397a32cb} 46 | ConEmuWinForms 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 57 | 58 | 59 | 60 | 67 | -------------------------------------------------------------------------------- /ConEmuWinForms/GuiMacroBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using JetBrains.Annotations; 8 | 9 | namespace ConEmu.WinForms 10 | { 11 | /// 12 | /// Fluent API for constructing a GUI macro. Start with the running , call . 13 | /// 14 | public sealed class GuiMacroBuilder 15 | { 16 | [NotNull] 17 | private readonly ConEmuSession _owner; 18 | 19 | [NotNull] 20 | private readonly IEnumerable _parameters; 21 | 22 | [NotNull] 23 | private readonly string _sMacroName; 24 | 25 | internal GuiMacroBuilder([NotNull] ConEmuSession owner, [NotNull] string sMacroName, [NotNull] IEnumerable parameters) 26 | { 27 | if(owner == null) 28 | throw new ArgumentNullException(nameof(owner)); 29 | if(sMacroName == null) 30 | throw new ArgumentNullException(nameof(sMacroName)); 31 | if(parameters == null) 32 | throw new ArgumentNullException(nameof(parameters)); 33 | 34 | _owner = owner; 35 | _sMacroName = sMacroName; 36 | _parameters = parameters; 37 | } 38 | 39 | /// 40 | /// Renders the macro and executes with ConEmu, asynchronously. 41 | /// 42 | [NotNull] 43 | public Task ExecuteAsync() 44 | { 45 | return _owner.ExecuteGuiMacroTextAsync(RenderMacroCommand(_sMacroName, _parameters)); 46 | } 47 | 48 | /// 49 | /// Renders the macro and executes with ConEmu, getting the result synchronously. 50 | /// 51 | public GuiMacroResult ExecuteSync() 52 | { 53 | return _owner.ExecuteGuiMacroTextSync(RenderMacroCommand(_sMacroName, _parameters)); 54 | } 55 | 56 | [Pure] 57 | [NotNull] 58 | public static string RenderMacroCommand([NotNull] string sMacroName, [NotNull] IEnumerable parameters) 59 | { 60 | if(sMacroName == null) 61 | throw new ArgumentNullException(nameof(sMacroName)); 62 | if(parameters == null) 63 | throw new ArgumentNullException(nameof(parameters)); 64 | 65 | var sb = new StringBuilder(); 66 | if(!IsAlphanumeric(sMacroName)) 67 | throw new InvalidOperationException("The macro name must be alphanumeric."); 68 | sb.Append(sMacroName); 69 | 70 | foreach(string parameter in parameters) 71 | { 72 | sb.Append(' '); 73 | 74 | if(IsAlphanumeric(parameter)) 75 | sb.Append(parameter); 76 | else 77 | sb.Append('@').Append('"').Append(parameter.Replace("\"", "\"\"")).Append('"'); 78 | } 79 | return sb.ToString(); 80 | } 81 | 82 | /// 83 | /// Adds a parameter. 84 | /// 85 | [NotNull] 86 | [Pure] 87 | public GuiMacroBuilder WithParam([NotNull] string value) 88 | { 89 | if(value == null) 90 | throw new ArgumentNullException(nameof(value)); 91 | return new GuiMacroBuilder(_owner, _sMacroName, _parameters.Concat(new[] {value})); 92 | } 93 | 94 | /// 95 | /// Adds a parameter. 96 | /// 97 | [NotNull] 98 | [Pure] 99 | public GuiMacroBuilder WithParam(int value) 100 | { 101 | return WithParam(value.ToString()); 102 | } 103 | 104 | private static bool IsAlphanumeric([NotNull] string s) 105 | { 106 | if(s == null) 107 | throw new ArgumentNullException(nameof(s)); 108 | foreach(char ch in s) 109 | { 110 | if((!Char.IsLetterOrDigit(ch)) && (ch != '_')) 111 | return false; 112 | } 113 | return true; 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /ConEmuWinForms/AnsiLog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | using JetBrains.Annotations; 5 | 6 | namespace ConEmu.WinForms 7 | { 8 | /// 9 | /// Manages reading the ANSI log output of the conemu and firing events with its data to the user. 10 | /// 11 | internal class AnsiLog : IDisposable 12 | { 13 | /// 14 | /// When we found the ansi file. 15 | /// 16 | [CanBeNull] 17 | private FileStream _fstream; 18 | 19 | private bool _isDisposed; 20 | 21 | public AnsiLog([NotNull] DirectoryInfo directory) 22 | { 23 | if(directory == null) 24 | throw new ArgumentNullException(nameof(directory)); 25 | Directory = directory; 26 | 27 | // Ensure exists for conemu to create the log file in 28 | directory.Create(); 29 | } 30 | 31 | /// 32 | /// The directory into which we instruct ConEmu to write its ansi log. 33 | /// 34 | [NotNull] 35 | public readonly DirectoryInfo Directory; 36 | 37 | public void Dispose() 38 | { 39 | // If dispose is not called by owner: not critical, even if the file is open, it would close itself upon finalization 40 | // Multiple calls OK 41 | 42 | // Must pump out the rest of the stream, if there's something left 43 | PumpStream(); 44 | 45 | // AFTER the final pumpout 46 | _isDisposed = true; 47 | 48 | // Close the file if open 49 | _fstream?.Dispose(); 50 | _fstream = null; 51 | } 52 | 53 | /// 54 | /// A function which processes the part of the stream which gets available (or does the rest of it at the end). 55 | /// 56 | public void PumpStream() 57 | { 58 | if(_isDisposed) 59 | return; // Nonfiring, yep 60 | 61 | // Try acquiring the stream if not yet 62 | _fstream = _fstream ?? FindAnsiLogFile(); 63 | 64 | // No ANSI stream file (yet?) 65 | if(_fstream == null) 66 | return; 67 | 68 | // Read the available chunk 69 | long length = _fstream.Length; // Take the length and keep it for the rest of the iteration, might change right as we're reading 70 | if(_fstream.Position >= length) 71 | return; // Nothing new 72 | var buffer = new byte[length - _fstream.Position]; // TODO: buffer pooling to save mem traffic 73 | int nRead = _fstream.Read(buffer, 0, buffer.Length); 74 | if(nRead <= 0) 75 | return; // Hmm should have succeeded, but anyway 76 | 77 | // Make a smaller buffer if we got less data (unlikely) 78 | AnsiStreamChunkEventArgs args; 79 | if(nRead < buffer.Length) 80 | { 81 | var subbuffer = new byte[nRead]; 82 | Buffer.BlockCopy(buffer, 0, subbuffer, 0, nRead); 83 | args = new AnsiStreamChunkEventArgs(subbuffer); 84 | } 85 | else 86 | args = new AnsiStreamChunkEventArgs(buffer); 87 | 88 | // Fire 89 | AnsiStreamChunkReceived?.Invoke(this, args); 90 | } 91 | 92 | /// 93 | /// Fires when the console process writes into its output or error stream. Gets a chunk of the raw ANSI stream contents. 94 | /// 95 | public event EventHandler AnsiStreamChunkReceived; 96 | 97 | [CanBeNull] 98 | private FileStream FindAnsiLogFile() 99 | { 100 | // NOTE: it's theoretically possible to get ANSI log file path with “BeginGuiMacro("GetInfo").WithParam("AnsiLog")” 101 | // However, this does not provide reliable means for reading the full ANSI output for short-lived processes, we might be too late to ask it for its path 102 | // So we specify a new empty folder for the log and expect the single log file to appear in that folder; we'll catch that just as good even after the process exits 103 | 104 | foreach(FileInfo fiLog in Directory.GetFiles("ConEmu*.log")) 105 | return fiLog.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); 106 | 107 | return null; 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /ConEmuInside/StarterForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Windows.Forms; 4 | using System.Runtime.InteropServices; 5 | using System.Diagnostics; 6 | using System.IO; 7 | 8 | namespace ConEmuInside 9 | { 10 | public partial class TerminalStarter : Form 11 | { 12 | protected ChildTerminal terminal; 13 | 14 | public TerminalStarter() 15 | { 16 | InitializeComponent(); 17 | } 18 | 19 | private void TerminalStarter_Load(object sender, EventArgs e) 20 | { 21 | argConEmuExe.Text = GetConEmu(); 22 | argDirectory.Text = Directory.GetCurrentDirectory(); 23 | var lsOurDir = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); 24 | argXmlFile.Text = Path.Combine(lsOurDir, "ConEmu.xml"); 25 | argCmdLine.Text = @"{cmd}"; // Use ConEmu's default {cmd} task 26 | RefreshControls(false); 27 | // Force focus to ‘cmd line’ control 28 | argCmdLine.Select(); 29 | } 30 | 31 | internal void RefreshControls(bool bTermActive) 32 | { 33 | if (bTermActive) 34 | { 35 | AcceptButton = null; 36 | if (startPanel.Enabled) 37 | { 38 | startPanel.Enabled = false; 39 | } 40 | } 41 | else 42 | { 43 | if (!startPanel.Enabled) 44 | { 45 | startPanel.Enabled = true; 46 | argCmdLine.Focus(); 47 | } 48 | AcceptButton = startBtn; 49 | } 50 | 51 | 52 | } 53 | 54 | internal string GetConEmu() 55 | { 56 | string sOurDir = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); 57 | string[] sSearchIn = { 58 | Directory.GetCurrentDirectory(), 59 | sOurDir, 60 | Path.Combine(sOurDir, ".."), 61 | Path.Combine(sOurDir, "ConEmu"), 62 | "%PATH%", "%REG%" 63 | }; 64 | 65 | string[] sNames; 66 | sNames = new string[] { "ConEmu.exe", "ConEmu64.exe" }; 67 | 68 | foreach (string sd in sSearchIn) 69 | { 70 | foreach (string sn in sNames) 71 | { 72 | string spath; 73 | if (sd == "%PATH%" || sd == "%REG%") 74 | { 75 | spath = sn; //TODO 76 | } 77 | else 78 | { 79 | spath = Path.Combine(sd, sn); 80 | } 81 | if (File.Exists(spath)) 82 | return spath; 83 | } 84 | } 85 | 86 | // Default 87 | return "ConEmu.exe"; 88 | } 89 | 90 | private void exeBtn_Click(object sender, EventArgs e) 91 | { 92 | openFileDialog1.Title = "Choose ConEmu main executable"; 93 | openFileDialog1.FileName = argConEmuExe.Text; 94 | if (openFileDialog1.ShowDialog() == DialogResult.OK) 95 | { 96 | argConEmuExe.Text = openFileDialog1.FileName; 97 | } 98 | argConEmuExe.Focus(); 99 | } 100 | 101 | private void cmdBtn_Click(object sender, EventArgs e) 102 | { 103 | openFileDialog1.Title = "Choose startup shell"; 104 | openFileDialog1.FileName = ""; 105 | if (openFileDialog1.ShowDialog() == DialogResult.OK) 106 | { 107 | argCmdLine.Text = openFileDialog1.FileName; 108 | } 109 | argCmdLine.Focus(); 110 | } 111 | 112 | private void dirBtn_Click(object sender, EventArgs e) 113 | { 114 | folderBrowserDialog1.SelectedPath = argDirectory.Text; 115 | if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) 116 | { 117 | argDirectory.Text = folderBrowserDialog1.SelectedPath; 118 | } 119 | argDirectory.Focus(); 120 | } 121 | 122 | private void startBtn_Click(object sender, EventArgs e) 123 | { 124 | var args = new ConEmuStartArgs 125 | { 126 | runAs = argRunAs.Checked, 127 | debug = argDebug.Checked, 128 | log = argLog.Checked, 129 | autoClose = argAutoClose.Checked, 130 | useGuiMacro = argUseGuiMacro.Checked, 131 | xmlFilePath = argXmlFile.Text, 132 | conemuExePath = argConEmuExe.Text, 133 | cmdLine = argCmdLine.Text, 134 | startupDirectory = argDirectory.Text, 135 | }; 136 | 137 | terminal = new ChildTerminal(this, args); 138 | terminal.ShowDialog(this); 139 | } 140 | 141 | private void startArgs_Enter(object sender, EventArgs e) 142 | { 143 | AcceptButton = startBtn; 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /ConEmuWinForms/ConEmuWinForms.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Default 6 | AnyCPU 7 | {1DC7D403-484B-43B4-B017-1356397A32CB} 8 | Library 9 | ConEmu.WinForms 10 | ConEmu.WinForms 11 | v4.0 12 | Client 13 | 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\ 21 | TRACE 22 | prompt 23 | 4 24 | true 25 | 1696;1591 26 | bin\ConEmu.WinForms.Xml 27 | 28 | 29 | true 30 | 31 | 32 | Snk.Snk 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Component 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | True 60 | True 61 | Resources.resx 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | PreserveNewest 79 | 80 | 81 | PreserveNewest 82 | 83 | 84 | PreserveNewest 85 | 86 | 87 | 88 | 89 | 90 | 91 | ResXFileCodeGenerator 92 | Resources.Designer.cs 93 | Designer 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 102 | 103 | 104 | 105 | 106 | "$(SolutionDir)Deploy\sign.cmd" "$(TargetPath)" 107 | 108 | -------------------------------------------------------------------------------- /ConEmuInside/ConEmuInside.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {44D33E8F-7F78-417D-AA78-E42AEE2071E3} 8 | WinExe 9 | Properties 10 | ConEmuInside 11 | ConEmuInside 12 | v4.0 13 | 512 14 | true 15 | Client 16 | 17 | 18 | x86 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Form 55 | 56 | 57 | TerminalForm.cs 58 | 59 | 60 | Form 61 | 62 | 63 | StarterForm.cs 64 | 65 | 66 | 67 | 68 | 69 | TerminalForm.cs 70 | 71 | 72 | StarterForm.cs 73 | 74 | 75 | ResXFileCodeGenerator 76 | Resources.Designer.cs 77 | Designer 78 | 79 | 80 | True 81 | Resources.resx 82 | True 83 | 84 | 85 | SettingsSingleFileGenerator 86 | Settings.Designer.cs 87 | 88 | 89 | True 90 | Settings.settings 91 | True 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | {1dc7d403-484b-43b4-b017-1356397a32cb} 100 | ConEmuWinForms 101 | 102 | 103 | 104 | 105 | PreserveNewest 106 | 107 | 108 | 109 | 110 | if "$(ConfigurationName)" == "Debug" if not exist "$(TargetDir)ConEmu.xml" copy "$(SolutionDir)ConEmu.xml" "$(TargetDir)" 111 | "$(SolutionDir)Deploy\sign.cmd" "$(TargetPath)" 112 | 113 | 120 | -------------------------------------------------------------------------------- /ConEmuInside/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /ConEmuWinForms/GetInfoRoot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using System.Xml; 7 | 8 | using ConEmu.WinForms.Util; 9 | 10 | using JetBrains.Annotations; 11 | 12 | namespace ConEmu.WinForms 13 | { 14 | /// 15 | /// Handles the GetInfo GuiMacro for the Root command. 16 | /// 17 | public class GetInfoRoot 18 | { 19 | private GetInfoRoot(States state, [NotNull] string name, uint? pid, int? exitCode) 20 | { 21 | if(name == null) 22 | throw new ArgumentNullException(nameof(name)); 23 | Name = name; 24 | Pid = pid; 25 | State = state; 26 | ExitCode = exitCode; 27 | } 28 | 29 | /// 30 | /// Exit code of the payload process, if it has exited. 31 | /// 32 | public readonly int? ExitCode; 33 | 34 | /// 35 | /// Whether the payload process were running at the moment when the macro were executed. 36 | /// 37 | public bool IsRunning => State == States.Running; 38 | 39 | /// 40 | /// Name of the process, should always be available whether it's running or not (yet/already). 41 | /// 42 | [NotNull] 43 | public readonly string Name; 44 | 45 | /// 46 | /// The process ID, available only when the payload process is running. 47 | /// 48 | public readonly uint? Pid; 49 | 50 | /// 51 | /// The current state of the root console process, as in the GetInfo Root GUI Macro State field: Empty, NotStarted, Running, Exited. 52 | /// 53 | public readonly States State; 54 | 55 | [NotNull] 56 | public static async Task QueryAsync([NotNull] ConEmuSession session) 57 | { 58 | if(session == null) 59 | throw new ArgumentNullException(nameof(session)); 60 | 61 | GuiMacroResult result = await session.BeginGuiMacro("GetInfo").WithParam("Root").ExecuteAsync(); 62 | Trace.WriteLine("[ROOT]: " + result.Response); 63 | if(!result.IsSuccessful) 64 | throw new InvalidOperationException("The GetInfo-Root call did not succeed."); 65 | if(string.IsNullOrWhiteSpace(result.Response)) // Might yield an empty string randomly if not ready yet 66 | throw new InvalidOperationException("The GetInfo-Root call has yielded an empty result."); 67 | 68 | // Interpret the string as XML 69 | var xmlDoc = new XmlDocument(); 70 | try 71 | { 72 | xmlDoc.LoadXml(result.Response); 73 | } 74 | catch(Exception ex) 75 | { 76 | // Could not parse the XML response. Not expected. Wait more. 77 | throw new InvalidOperationException($"The GetInfo-Root call result “{result.Response}” were not a valid XML document.", ex); 78 | } 79 | XmlElement xmlRoot = xmlDoc.DocumentElement; 80 | if(xmlRoot == null) 81 | throw new InvalidOperationException($"The GetInfo-Root call result “{result.Response}” didn't have a root XML element."); 82 | 83 | // Current possible records: 84 | // 85 | // 86 | // 87 | // Also, there's the State="Empty" documented, though it would be hard to catch 88 | 89 | // Start with detecting the state 90 | string sState = xmlRoot.GetAttribute("State"); 91 | if(string.IsNullOrWhiteSpace(sState)) 92 | throw new InvalidOperationException($"The GetInfo-Root call result “{result.Response}” didn't specify the current ConEmu state."); 93 | States state; 94 | if(!Enum.TryParse(sState, false, out state)) 95 | throw new InvalidOperationException($"The GetInfo-Root call result “{result.Response}” specifies the State “{sState}” which cannot be matched against the list of the known states {Enum.GetValues(typeof(States)).OfType().Select(o => o.ToString()).OrderBy(o => o, StringComparer.InvariantCultureIgnoreCase).Aggregate((x, y) => x + ", " + y)}."); 96 | 97 | string sName = xmlRoot.GetAttribute("Name"); 98 | 99 | uint nPidRaw; 100 | uint? nPid = ((state == States.Running) && (uint.TryParse(xmlRoot.GetAttribute("PID"), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out nPidRaw))) ? nPidRaw : default(uint?); 101 | 102 | int nExitCodeRaw; 103 | int? nExitCode = ((state == States.Exited) && (int.TryParse(xmlRoot.GetAttribute("ExitCode"), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out nExitCodeRaw))) ? nExitCodeRaw : default(int?); 104 | 105 | return new GetInfoRoot(state, sName, nPid, nExitCode); 106 | } 107 | 108 | /// 109 | /// State: Empty, NotStarted, Running, Exited. 110 | /// 111 | public enum States 112 | { 113 | /// 114 | /// If there are not consoles in ConEmu. 115 | /// 116 | /// <Root State="Empty" /> 117 | Empty, 118 | 119 | /// 120 | /// If console initialization is in progress (ping localhost -t for example). 121 | /// 122 | /// <Root State="NotStarted" Name="ping.exe" /> 123 | NotStarted, 124 | 125 | /// 126 | /// If root process was started and is running. Note, 259 in ExitCode is STILL_ACTIVE constant. 127 | /// 128 | /// <Root State="Running" Name="ping.exe" PID="7136" ExitCode="259" UpTime="3183" /> 129 | Running, 130 | 131 | /// 132 | /// • If root process was finished (terminated by `Ctrl+C` as example). 133 | /// • Another example for `cmd.exe` normal exit. 134 | /// 135 | /// <Root State="Exited" Name="ping.exe" PID="7136" ExitCode="3221225786" UpTime="10195" /> 136 | /// <Root State="Exited" Name="cmd.exe" PID="6688" ExitCode="0" UpTime="1825" /> 137 | Exited 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /ConEmuInside/StarterForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 104, 17 122 | 123 | 124 | 244, 17 125 | 126 | -------------------------------------------------------------------------------- /ConEmuWinForms/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ConEmu.xml;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 123 | 124 | -------------------------------------------------------------------------------- /ConEmuInside/TerminalForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | 104, 17 125 | 126 | 127 | 244, 17 128 | 129 | -------------------------------------------------------------------------------- /Tests/ControlDllTestbed/Testbed.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Text.RegularExpressions; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | using ConEmu.WinForms; 8 | 9 | namespace ControlDllTestbed 10 | { 11 | internal static class Testbed 12 | { 13 | /// 14 | /// The main entry point for the application. 15 | /// 16 | [STAThread] 17 | private static int Main() 18 | { 19 | try 20 | { 21 | Application.EnableVisualStyles(); 22 | Application.SetCompatibleTextRenderingDefault(false); 23 | Application.Run(RenderView(new Form())); 24 | return 0; 25 | } 26 | catch(Exception ex) 27 | { 28 | MessageBox.Show(ex.ToString(), "Startup Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 29 | return -1; 30 | } 31 | } 32 | 33 | private static Form RenderView(Form form) 34 | { 35 | form.Size = new Size(800, 600); 36 | 37 | ConEmuControl conemu; 38 | form.Controls.Add(conemu = new ConEmuControl() {Dock = DockStyle.Fill, MinimumSize = new Size(200, 200), IsStatusbarVisible = true}); 39 | if(conemu.AutoStartInfo != null) 40 | { 41 | conemu.AutoStartInfo.SetEnv("one", "two"); 42 | conemu.AutoStartInfo.SetEnv("geet", "huub"); 43 | conemu.AutoStartInfo.GreetingText = "• Running \"cmd.exe\" as the default shell in the terminal. \n\n"; 44 | //conemu.AutoStartInfo.GreetingText = "\"C:\\Program Files\\Git\\bin\\git.exe\" fetch --progress \"--all\" "; // A test specimen with advanced quoting 45 | conemu.AutoStartInfo.IsEchoingConsoleCommandLine = true; 46 | } 47 | //conemu.AutoStartInfo = null; 48 | TextBox txt; 49 | form.Controls.Add(txt = new TextBox() {Text = "AnotherFocusableControl", AutoSize = true, Dock = DockStyle.Top}); 50 | 51 | FlowLayoutPanel stack; 52 | form.Controls.Add(stack = new FlowLayoutPanel() {FlowDirection = FlowDirection.LeftToRight, Dock = DockStyle.Top, AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink}); 53 | 54 | Button btn; 55 | stack.Controls.Add(btn = new Button() {Text = "Paste Command", AutoSize = true, Dock = DockStyle.Left}); 56 | btn.Click += delegate { conemu.RunningSession?.WriteInputText("whois microsoft.com" + Environment.NewLine); }; 57 | 58 | stack.Controls.Add(btn = new Button() {Text = "Write StdOut", AutoSize = true, Dock = DockStyle.Left}); 59 | btn.Click += delegate { conemu.RunningSession?.WriteOutputText("\x001B7\x001B[90mEcho \"Hello world!\"\x001B[m\x001B8"); }; 60 | 61 | stack.Controls.Add(btn = new Button() {Text = "Query HWND", AutoSize = true, Dock = DockStyle.Left}); 62 | btn.Click += delegate { conemu.RunningSession?.BeginGuiMacro("GetInfo").WithParam("HWND").ExecuteAsync().ContinueWith(task => txt.Text = $"ConEmu HWND: {Regex.Replace(task.Result.Response, "\\s+", " ")}", TaskScheduler.FromCurrentSynchronizationContext()); }; 63 | 64 | stack.Controls.Add(btn = new Button() {Text = "Query PID", AutoSize = true, Dock = DockStyle.Left}); 65 | btn.Click += delegate { conemu.RunningSession?.BeginGuiMacro("GetInfo").WithParam("PID").ExecuteAsync().ContinueWith(task => txt.Text = $"ConEmu PID: {Regex.Replace(task.Result.Response, "\\s+", " ")}", TaskScheduler.FromCurrentSynchronizationContext()); }; 66 | 67 | stack.Controls.Add(btn = new Button() {Text = "Kill Payload", AutoSize = true, Dock = DockStyle.Left}); 68 | btn.Click += delegate { conemu.RunningSession?.KillConsoleProcessAsync(); }; 69 | 70 | stack.Controls.Add(btn = new Button() {Text = "Ctrl+C", AutoSize = true, Dock = DockStyle.Left}); 71 | btn.Click += delegate { conemu.RunningSession?.SendControlCAsync(); }; 72 | 73 | CheckBox checkStatusBar; 74 | stack.Controls.Add(checkStatusBar = new CheckBox() {Text = "StatusBar", Checked = conemu.IsStatusbarVisible}); 75 | checkStatusBar.CheckedChanged += delegate { conemu.IsStatusbarVisible = checkStatusBar.Checked; }; 76 | 77 | TextBox txtOutput = null; 78 | 79 | stack.Controls.Add(btn = new Button() {Text = "&Ping", AutoSize = true, Dock = DockStyle.Left}); 80 | btn.Click += delegate 81 | { 82 | if(conemu.IsConsoleEmulatorOpen) 83 | { 84 | MessageBox.Show(form, "The console is busy right now.", "Ping", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 85 | return; 86 | } 87 | if(txtOutput == null) 88 | form.Controls.Add(txtOutput = new TextBox() {Multiline = true, Dock = DockStyle.Right, Width = 200}); 89 | conemu.Start(new ConEmuStartInfo() {ConsoleProcessCommandLine = "ping ya.ru", IsEchoingConsoleCommandLine = true, AnsiStreamChunkReceivedEventSink = (sender, args) => txtOutput.Text += args.GetMbcsText(), WhenConsoleProcessExits = WhenConsoleProcessExits.KeepConsoleEmulatorAndShowMessage, ConsoleProcessExitedEventSink = (sender, args) => txtOutput.Text += $"Exited with ERRORLEVEL {args.ExitCode}.", GreetingText = $"This will showcase getting the command output live in the backend.{Environment.NewLine}As the PING command runs, the textbox would duplicate its stdout in real time.{Environment.NewLine}{Environment.NewLine}"}); 90 | }; 91 | 92 | stack.Controls.Add(btn = new Button() {Text = "&Choice", AutoSize = true, Dock = DockStyle.Left}); 93 | btn.Click += delegate 94 | { 95 | conemu.RunningSession?.CloseConsoleEmulator(); 96 | DialogResult result = MessageBox.Show(form, "Keep terminal when payload exits?", "Choice", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); 97 | if(result == DialogResult.Cancel) 98 | return; 99 | ConEmuSession session = conemu.Start(new ConEmuStartInfo() {ConsoleProcessCommandLine = "choice", IsEchoingConsoleCommandLine = true, WhenConsoleProcessExits = result == DialogResult.Yes ? WhenConsoleProcessExits.KeepConsoleEmulatorAndShowMessage : WhenConsoleProcessExits.CloseConsoleEmulator, ConsoleProcessExitedEventSink = (sender, args) => MessageBox.Show($"Your choice is {args.ExitCode} (powered by startinfo event sink).")}); 100 | #pragma warning disable 4014 101 | ShowMessageForChoiceAsync(session); 102 | #pragma warning restore 4014 103 | }; 104 | 105 | return form; 106 | } 107 | 108 | /// 109 | /// This method checks that the async-await compiler syntax is not prevented in netfx45+ projects due to the shim types present in the conemu assembly (https://github.com/Maximus5/conemu-inside/issues/20). 110 | /// 111 | private static async Task ShowMessageForChoiceAsync(ConEmuSession session) 112 | { 113 | if(session == null) 114 | throw new ArgumentNullException(nameof(session)); 115 | ConsoleProcessExitedEventArgs exitargs = await session.WaitForConsoleProcessExitAsync(); 116 | MessageBox.Show($"Your choice is {exitargs.ExitCode} (powered by wait-for-exit-async)."); 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /ConEmuWinForms/package/license.txt: -------------------------------------------------------------------------------- 1 | ConEmu-Maximus5 - Handy Windows terminal 2 | Copyright (c) 2006-2008, Zoin 3 | Copyright (c) 2009-2021, Maksim Moisiuk 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. The name of the authors may not be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR 17 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | ------------------------------------------------------------------------------- 28 | MinHook - The Minimalistic API Hooking Library for x64/x86 29 | Copyright (C) 2009-2015 Tsuda Kageyu. 30 | All rights reserved. 31 | 32 | Redistribution and use in source and binary forms, with or without 33 | modification, are permitted provided that the following conditions 34 | are met: 35 | 36 | 1. Redistributions of source code must retain the above copyright 37 | notice, this list of conditions and the following disclaimer. 38 | 2. Redistributions in binary form must reproduce the above copyright 39 | notice, this list of conditions and the following disclaimer in the 40 | documentation and/or other materials provided with the distribution. 41 | 42 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 43 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 44 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 45 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 46 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 47 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 48 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 49 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 50 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 51 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 52 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 | 54 | ------------------------------------------------------------------------------- 55 | Hacker Disassembler Engine 32 C 56 | Copyright (c) 2008-2009, Vyacheslav Patkov. 57 | All rights reserved. 58 | 59 | Redistribution and use in source and binary forms, with or without 60 | modification, are permitted provided that the following conditions 61 | are met: 62 | 63 | 1. Redistributions of source code must retain the above copyright 64 | notice, this list of conditions and the following disclaimer. 65 | 2. Redistributions in binary form must reproduce the above copyright 66 | notice, this list of conditions and the following disclaimer in the 67 | documentation and/or other materials provided with the distribution. 68 | 69 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 70 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 71 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 72 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR 73 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 74 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 75 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 76 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 77 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 78 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 79 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 80 | 81 | ------------------------------------------------------------------------------- 82 | Hacker Disassembler Engine 64 C 83 | Copyright (c) 2008-2009, Vyacheslav Patkov. 84 | All rights reserved. 85 | 86 | Redistribution and use in source and binary forms, with or without 87 | modification, are permitted provided that the following conditions 88 | are met: 89 | 90 | 1. Redistributions of source code must retain the above copyright 91 | notice, this list of conditions and the following disclaimer. 92 | 2. Redistributions in binary form must reproduce the above copyright 93 | notice, this list of conditions and the following disclaimer in the 94 | documentation and/or other materials provided with the distribution. 95 | 96 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 97 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 98 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 99 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR 100 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 101 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 102 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 103 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 104 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 105 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 106 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 107 | 108 | ------------------------------------------------------------------------------- 109 | json-parser 110 | Copyright (C) 2012, 2013 James McLaughlin et al. All rights reserved. 111 | 112 | Redistribution and use in source and binary forms, with or without 113 | modification, are permitted provided that the following conditions 114 | are met: 115 | 116 | 1. Redistributions of source code must retain the above copyright 117 | notice, this list of conditions and the following disclaimer. 118 | 119 | 2. Redistributions in binary form must reproduce the above copyright 120 | notice, this list of conditions and the following disclaimer in the 121 | documentation and/or other materials provided with the distribution. 122 | 123 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 124 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 125 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 126 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 127 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 128 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 129 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 130 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 131 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 132 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 133 | SUCH DAMAGE. 134 | -------------------------------------------------------------------------------- /ConEmuWinForms/GuiMacroExecutor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Globalization; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | using ConEmu.WinForms.Util; 10 | 11 | using JetBrains.Annotations; 12 | 13 | using Microsoft.Build.Utilities; 14 | 15 | namespace ConEmu.WinForms 16 | { 17 | /// 18 | /// Implements calling GuiMacro to the remote ConEmu instance, and getting the result. 19 | /// Got switching implementation for out-of-process (classic, via a console tool) and in-process (new feature which loads the helper comm DLL directly) access. 20 | /// 21 | public unsafe class GuiMacroExecutor : IDisposable 22 | { 23 | [CanBeNull] 24 | private FGuiMacro _fnGuiMacro; 25 | 26 | [CanBeNull] 27 | private void* _hConEmuCD; 28 | 29 | /// 30 | /// Prevent unloads when async calls are being placed. 31 | /// 32 | private readonly object _lock = new object(); 33 | 34 | /// 35 | /// Inits the object, loads the extender DLL if known. If NULL, in-process operations will not be available. 36 | /// 37 | public GuiMacroExecutor([CanBeNull] string asLibrary) 38 | { 39 | if(!String.IsNullOrWhiteSpace(asLibrary)) 40 | LoadConEmuDll(asLibrary); 41 | } 42 | 43 | /// 44 | /// Loads the ConEmu Console Server DLL and uses it to execute the GUI Macro. 45 | /// The execution is async, because the call must not be placed on the same thread. 46 | /// 47 | [NotNull] 48 | public Task ExecuteInProcessAsync(int nConEmuPid, [NotNull] string asMacro) 49 | { 50 | if(asMacro == null) 51 | throw new ArgumentNullException(nameof(asMacro)); 52 | if(_hConEmuCD == null) // Check on home thread 53 | throw new GuiMacroException("ConEmuCD was not loaded."); 54 | 55 | // Bring the call on another thread, because placing the call on the same thread as ConEmu might cause a deadlock when it's still in the process of initialization 56 | // (the GuiMacro stuff was designed for out-of-process comm and would blocking-wait for init to complete) 57 | return Task.Factory.StartNew(() => 58 | { 59 | lock(_lock) // Don't allow unloading in parallel 60 | { 61 | if(_hConEmuCD == null) // Re-check after lock-protecting from unload 62 | throw new GuiMacroException("ConEmuCD has just been unloaded."); 63 | if(_fnGuiMacro == null) 64 | throw new GuiMacroException("The function pointer has not been bound."); 65 | 66 | string sResult; 67 | int iRc = _fnGuiMacro(nConEmuPid.ToString(CultureInfo.InvariantCulture), asMacro, out sResult); 68 | switch(iRc) 69 | { 70 | case 0: // This is expected 71 | case 133: // CERR_GUIMACRO_SUCCEEDED: not expected, but... 72 | return new GuiMacroResult() {IsSuccessful = true, Response = sResult ?? ""}; 73 | case 134: // CERR_GUIMACRO_FAILED 74 | return new GuiMacroResult() {IsSuccessful = false}; 75 | default: 76 | throw new GuiMacroException($"Internal ConEmuCD error: {iRc:N0}."); 77 | } 78 | } 79 | }); 80 | } 81 | 82 | /// 83 | /// Invokes ConEmuC.exe to execute the GUI Macro. 84 | /// The execution is asynchronous. 85 | /// 86 | [NotNull] 87 | public Task ExecuteViaExtenderProcessAsync([NotNull] string macrotext, int nConEmuPid, [NotNull] string sConEmuConsoleExtenderExecutablePath) 88 | { 89 | if(macrotext == null) 90 | throw new ArgumentNullException(nameof(macrotext)); 91 | if(sConEmuConsoleExtenderExecutablePath == null) 92 | throw new ArgumentNullException(nameof(sConEmuConsoleExtenderExecutablePath)); 93 | 94 | // conemuc.exe -silent -guimacro:1234 print("\e","git"," --version","\n") 95 | var cmdl = new CommandLineBuilder(); 96 | cmdl.AppendSwitch("-silent"); 97 | cmdl.AppendSwitchIfNotNull("-GuiMacro:", nConEmuPid.ToString()); 98 | cmdl.AppendSwitch(macrotext /* appends the text unquoted for cmdline */); 99 | 100 | if(sConEmuConsoleExtenderExecutablePath == "") 101 | throw new InvalidOperationException("The ConEmu Console Extender Executable is not available."); 102 | if(!File.Exists(sConEmuConsoleExtenderExecutablePath)) 103 | throw new InvalidOperationException($"The ConEmu Console Extender Executable does not exist on disk at “{sConEmuConsoleExtenderExecutablePath}”."); 104 | 105 | try 106 | { 107 | Task> taskStart = Task.Factory.StartNew(() => 108 | { 109 | var processExtender = new Process() {StartInfo = new ProcessStartInfo(sConEmuConsoleExtenderExecutablePath, cmdl.ToString()) {WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, RedirectStandardError = true, RedirectStandardOutput = true, UseShellExecute = false}}; 110 | 111 | processExtender.EnableRaisingEvents = true; 112 | var sbResult = new StringBuilder(); 113 | DataReceivedEventHandler FOnData = (sender, args) => 114 | { 115 | lock(sbResult) 116 | sbResult.Append(args.Data); 117 | }; 118 | processExtender.OutputDataReceived += FOnData; 119 | processExtender.ErrorDataReceived += FOnData; 120 | 121 | var taskresult = new TaskCompletionSource(); 122 | processExtender.Exited += delegate 123 | { 124 | GuiMacroResult result; 125 | lock(sbResult) 126 | result = new GuiMacroResult() {IsSuccessful = processExtender.ExitCode == 0, Response = sbResult.ToString()}; 127 | taskresult.SetResult(result); 128 | }; 129 | 130 | processExtender.Start(); 131 | 132 | processExtender.BeginOutputReadLine(); 133 | processExtender.BeginErrorReadLine(); 134 | 135 | return taskresult.Task; 136 | }); 137 | 138 | return taskStart.Unwrap(); 139 | } 140 | catch(Exception ex) 141 | { 142 | throw new InvalidOperationException($"Could not run the ConEmu Console Extender Executable at “{sConEmuConsoleExtenderExecutablePath}” with command-line arguments “{cmdl}”.", ex); 143 | } 144 | } 145 | 146 | void IDisposable.Dispose() 147 | { 148 | lock(_lock) 149 | UnloadConEmuDll(); 150 | GC.SuppressFinalize(this); 151 | } 152 | 153 | ~GuiMacroExecutor() 154 | { 155 | // Locking: don't take lock in the finalizer, could do nasty things, supposedly, “this” is reachable when background tasks are running 156 | UnloadConEmuDll(); 157 | } 158 | 159 | private void LoadConEmuDll([NotNull] string asLibrary) 160 | { 161 | if(asLibrary == null) 162 | throw new ArgumentNullException(nameof(asLibrary)); 163 | if(_hConEmuCD != null) 164 | return; 165 | 166 | _hConEmuCD = WinApi.LoadLibrary(asLibrary); 167 | if(_hConEmuCD == null) 168 | { 169 | int errorCode = Marshal.GetLastWin32Error(); 170 | throw new GuiMacroException($"Can't load library, ErrCode={errorCode}\n{asLibrary}"); 171 | } 172 | 173 | const string fnName = "GuiMacro"; 174 | void* exportPtr = WinApi.GetProcAddress(_hConEmuCD, fnName); 175 | if(exportPtr == null) 176 | { 177 | UnloadConEmuDll(); 178 | throw new GuiMacroException($"Function {fnName} not found in library\n{asLibrary}\nUpdate ConEmu modules"); 179 | } 180 | _fnGuiMacro = (FGuiMacro)Marshal.GetDelegateForFunctionPointer((IntPtr)exportPtr, typeof(FGuiMacro)); 181 | } 182 | 183 | private void UnloadConEmuDll() 184 | { 185 | if(_hConEmuCD != null) 186 | { 187 | WinApi.FreeLibrary(_hConEmuCD); 188 | _hConEmuCD = null; 189 | } 190 | } 191 | 192 | /// 193 | /// int __stdcall GuiMacro(LPCWSTR asInstance, LPCWSTR asMacro, BSTR* bsResult = NULL); 194 | /// 195 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)] 196 | private delegate int FGuiMacro([MarshalAs(UnmanagedType.LPWStr)] string asInstance, [MarshalAs(UnmanagedType.LPWStr)] string asMacro, [MarshalAs(UnmanagedType.BStr)] out string bsResult); 197 | 198 | public class GuiMacroException : Exception 199 | { 200 | public GuiMacroException(string asMessage) 201 | : base(asMessage) 202 | { 203 | } 204 | } 205 | } 206 | } -------------------------------------------------------------------------------- /ConEmuWinForms/Util/WinApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Reflection; 4 | using System.Runtime.InteropServices; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | using JetBrains.Annotations; 9 | 10 | using Microsoft.Win32.SafeHandles; 11 | 12 | namespace ConEmu.WinForms.Util 13 | { 14 | [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] 15 | internal static unsafe class WinApi 16 | { 17 | public static readonly uint SYNCHRONIZE = 1048576; 18 | 19 | /// 20 | /// The EnumChildWindows function enumerates the child windows that belong to the specified parent window by passing the handle to each child window, in turn, to an application-defined callback function. EnumChildWindows continues until the last child window is enumerated or the callback function returns FALSE. 21 | /// 22 | /// [in] Handle to the parent window whose child windows are to be enumerated. If this parameter is NULL, this function is equivalent to EnumWindows. Windows 95/98/Me: hWndParent cannot be NULL. 23 | /// [in] Pointer to an application-defined callback function. For more information, see EnumChildProc. 24 | /// [in] Specifies an application-defined value to be passed to the callback function. 25 | /// Not used. 26 | /// If a child window has created child windows of its own, EnumChildWindows enumerates those windows as well. A child window that is moved or repositioned in the Z order during the enumeration process will be properly enumerated. The function does not enumerate a child window that is destroyed before being enumerated or that is created during the enumeration process. 27 | [DllImport("user32.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] 28 | public static extern Int32 EnumChildWindows(void* hWndParent, void* lpEnumFunc, IntPtr lParam); 29 | 30 | [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 31 | public static extern bool FreeLibrary(void* hModule); 32 | 33 | [DllImport("kernel32.dll", CharSet = CharSet.Ansi)] 34 | public static extern void* GetProcAddress(void* hModule, string lpProcName); 35 | 36 | [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 37 | public static extern void* LoadLibrary(string libname); 38 | 39 | /// 40 | /// The MoveWindow function changes the position and dimensions of the specified window. For a top-level window, the position and dimensions are relative to the upper-left corner of the screen. For a child window, they are relative to the upper-left corner of the parent window's client area. 41 | /// 42 | /// [in] Handle to the window. 43 | /// [in] Specifies the new position of the left side of the window. 44 | /// [in] Specifies the new position of the top of the window. 45 | /// [in] Specifies the new width of the window. 46 | /// [in] Specifies the new height of the window. 47 | /// [in] Specifies whether the window is to be repainted. If this parameter is TRUE, the window receives a message. If the parameter is FALSE, no repainting of any kind occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of moving a child window. 48 | /// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError. 49 | [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 50 | public static extern int MoveWindow(void* hWnd, int X, int Y, int nWidth, int nHeight, int bRepaint); 51 | 52 | /// Opens an existing local process object. 53 | /// The access to the process object. 54 | /// If this value is TRUE, processes created by this process will inherit the handle. 55 | /// The identifier of the local process to be opened. If the specified process is the System Process (0x00000000), the function fails and the last error code is ERROR_INVALID_PARAMETER. If the specified process is the Idle process or one of the CSRSS processes, this function fails and the last error code is ERROR_ACCESS_DENIED because their access restrictions prevent user-level code from opening them. 56 | /// If the function succeeds, the return value is an open handle to the specified process. If the function fails, the return value is NULL. To get extended error information, call GetLastError. 57 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] 58 | public static extern void* OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId); 59 | 60 | /// 61 | /// The SetFocus function sets the keyboard focus to the specified window. The window must be attached to the calling thread's message queue. The SetFocus function sends a WM_KILLFOCUS message to the window that loses the keyboard focus and a WM_SETFOCUS message to the window that receives the keyboard focus. It also activates either the window that receives the focus or the parent of the window that receives the focus. If a window is active but does not have the focus, any key pressed will produce the WM_SYSCHAR, WM_SYSKEYDOWN, or WM_SYSKEYUP message. If the VK_MENU key is also pressed, the lParam parameter of the message will have bit 30 set. Otherwise, the messages produced do not have this bit set. By using the AttachThreadInput function, a thread can attach its input processing to another thread. This allows a thread to call SetFocus to set the keyboard focus to a window attached to another thread's message queue. 62 | /// 63 | /// [in] Handle to the window that will receive the keyboard input. If this parameter is NULL, keystrokes are ignored. 64 | /// If the function succeeds, the return value is the handle to the window that previously had the keyboard focus. If the hWnd parameter is invalid or the window is not attached to the calling thread's message queue, the return value is NULL. To get extended error information, call GetLastError. 65 | [DllImport("user32.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = false, ExactSpelling = true)] 66 | public static extern void* SetFocus(void* hWnd); 67 | 68 | /// 69 | /// The EnumWindowsProc function is an application-defined callback function used with the EnumWindows or EnumDesktopWindows function. It receives top-level window handles. The WNDENUMPROC type defines a pointer to this callback function. EnumWindowsProc is a placeholder for the application-defined function name. 70 | /// 71 | /// [in] Handle to a top-level window. 72 | /// [in] Specifies the application-defined value given in EnumWindows or EnumDesktopWindows. 73 | /// To continue enumeration, the callback function must return TRUE; to stop enumeration, it must return FALSE. 74 | /// An application must register this callback function by passing its address to EnumWindows or EnumDesktopWindows. 75 | public delegate Int32 EnumWindowsProc(void* hwnd, IntPtr lParam); 76 | 77 | public static class Helpers 78 | { 79 | [NotNull] 80 | public static Task WaitForProcessExitAsync(uint pid) 81 | { 82 | void* hProcess = OpenProcess(SYNCHRONIZE, 0, pid); 83 | if(hProcess == null) 84 | return TaskHelpers.FromResult(false); 85 | 86 | var tasker = new TaskCompletionSource(); 87 | 88 | var hProcessSafe = new NativeWaitHandle(hProcess, true); 89 | RegisteredWaitHandle registered = null; 90 | WaitOrTimerCallback λHappened = (state, timeout) => 91 | { 92 | hProcessSafe.Close(); 93 | #pragma warning disable once AccessToModifiedClosure 94 | registered?.Unregister(null); 95 | tasker.SetResult(true); 96 | }; 97 | registered = ThreadPool.RegisterWaitForSingleObject(hProcessSafe, λHappened, Missing.Value, -1, true); 98 | 99 | return tasker.Task; 100 | } 101 | } 102 | 103 | public class NativeWaitHandle : WaitHandle 104 | { 105 | public NativeWaitHandle(void* handle, bool isOwning) 106 | { 107 | SafeWaitHandle = new SafeWaitHandle((IntPtr)handle, isOwning); 108 | } 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /ConEmuInside/TerminalForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ConEmuInside 2 | { 3 | partial class ChildTerminal 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | this.groupBox1 = new System.Windows.Forms.GroupBox(); 33 | this.termPanel = new System.Windows.Forms.Panel(); 34 | this.groupBox2 = new System.Windows.Forms.GroupBox(); 35 | this.closeBtn = new System.Windows.Forms.Button(); 36 | this.macroBtn = new System.Windows.Forms.Button(); 37 | this.printBtn = new System.Windows.Forms.Button(); 38 | this.promptBox = new System.Windows.Forms.TextBox(); 39 | this.timer1 = new System.Windows.Forms.Timer(this.components); 40 | this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); 41 | this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); 42 | this.groupBox1.SuspendLayout(); 43 | this.groupBox2.SuspendLayout(); 44 | this.SuspendLayout(); 45 | // 46 | // groupBox1 47 | // 48 | this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 49 | | System.Windows.Forms.AnchorStyles.Left) 50 | | System.Windows.Forms.AnchorStyles.Right))); 51 | this.groupBox1.Controls.Add(this.termPanel); 52 | this.groupBox1.Location = new System.Drawing.Point(12, 12); 53 | this.groupBox1.Name = "groupBox1"; 54 | this.groupBox1.Size = new System.Drawing.Size(576, 355); 55 | this.groupBox1.TabIndex = 0; 56 | this.groupBox1.TabStop = false; 57 | this.groupBox1.Text = "Terminal"; 58 | // 59 | // termPanel 60 | // 61 | this.termPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 62 | | System.Windows.Forms.AnchorStyles.Left) 63 | | System.Windows.Forms.AnchorStyles.Right))); 64 | this.termPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(43)))), ((int)(((byte)(54))))); 65 | this.termPanel.Location = new System.Drawing.Point(6, 19); 66 | this.termPanel.Name = "termPanel"; 67 | this.termPanel.Size = new System.Drawing.Size(564, 330); 68 | this.termPanel.TabIndex = 0; 69 | // 70 | // groupBox2 71 | // 72 | this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 73 | | System.Windows.Forms.AnchorStyles.Right))); 74 | this.groupBox2.Controls.Add(this.closeBtn); 75 | this.groupBox2.Controls.Add(this.macroBtn); 76 | this.groupBox2.Controls.Add(this.printBtn); 77 | this.groupBox2.Controls.Add(this.promptBox); 78 | this.groupBox2.Location = new System.Drawing.Point(12, 373); 79 | this.groupBox2.Name = "groupBox2"; 80 | this.groupBox2.Size = new System.Drawing.Size(576, 48); 81 | this.groupBox2.TabIndex = 1; 82 | this.groupBox2.TabStop = false; 83 | this.groupBox2.Text = "Controlling box"; 84 | // 85 | // closeBtn 86 | // 87 | this.closeBtn.Anchor = System.Windows.Forms.AnchorStyles.Right; 88 | this.closeBtn.Location = new System.Drawing.Point(495, 17); 89 | this.closeBtn.Name = "closeBtn"; 90 | this.closeBtn.Size = new System.Drawing.Size(75, 23); 91 | this.closeBtn.TabIndex = 3; 92 | this.closeBtn.Text = "&Close"; 93 | this.closeBtn.UseVisualStyleBackColor = true; 94 | this.closeBtn.Click += new System.EventHandler(this.closeBtn_Click); 95 | // 96 | // macroBtn 97 | // 98 | this.macroBtn.Anchor = System.Windows.Forms.AnchorStyles.Right; 99 | this.macroBtn.Location = new System.Drawing.Point(413, 17); 100 | this.macroBtn.Name = "macroBtn"; 101 | this.macroBtn.Size = new System.Drawing.Size(75, 23); 102 | this.macroBtn.TabIndex = 2; 103 | this.macroBtn.Text = "Gui&Macro"; 104 | this.macroBtn.UseVisualStyleBackColor = true; 105 | this.macroBtn.Click += new System.EventHandler(this.macroBtn_Click); 106 | // 107 | // printBtn 108 | // 109 | this.printBtn.Anchor = System.Windows.Forms.AnchorStyles.Right; 110 | this.printBtn.Location = new System.Drawing.Point(332, 17); 111 | this.printBtn.Name = "printBtn"; 112 | this.printBtn.Size = new System.Drawing.Size(75, 23); 113 | this.printBtn.TabIndex = 1; 114 | this.printBtn.Text = "&Print"; 115 | this.printBtn.UseVisualStyleBackColor = true; 116 | this.printBtn.Click += new System.EventHandler(this.printBtn_Click); 117 | // 118 | // promptBox 119 | // 120 | this.promptBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); 121 | this.promptBox.Location = new System.Drawing.Point(6, 19); 122 | this.promptBox.Name = "promptBox"; 123 | this.promptBox.Size = new System.Drawing.Size(316, 20); 124 | this.promptBox.TabIndex = 0; 125 | this.promptBox.Enter += new System.EventHandler(this.promptBox_Enter); 126 | this.promptBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.promptBox_KeyDown); 127 | this.promptBox.Leave += new System.EventHandler(this.promptBox_Leave); 128 | // 129 | // timer1 130 | // 131 | this.timer1.Tick += new System.EventHandler(this.timer1_Tick); 132 | // 133 | // openFileDialog1 134 | // 135 | this.openFileDialog1.DefaultExt = "exe"; 136 | this.openFileDialog1.FileName = "openFileDialog1"; 137 | this.openFileDialog1.Filter = "*.exe files|*.exe|All files|*.*"; 138 | // 139 | // folderBrowserDialog1 140 | // 141 | this.folderBrowserDialog1.Description = "Choose working directory"; 142 | // 143 | // ChildTerminal 144 | // 145 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 146 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 147 | this.ClientSize = new System.Drawing.Size(600, 433); 148 | this.Controls.Add(this.groupBox2); 149 | this.Controls.Add(this.groupBox1); 150 | this.MinimumSize = new System.Drawing.Size(40, 39); 151 | this.Name = "ChildTerminal"; 152 | this.Text = "ConEmu Inside"; 153 | this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ChildTerminal_FormClosed); 154 | this.Load += new System.EventHandler(this.ChildTerminal_Load); 155 | this.groupBox1.ResumeLayout(false); 156 | this.groupBox2.ResumeLayout(false); 157 | this.groupBox2.PerformLayout(); 158 | this.ResumeLayout(false); 159 | 160 | } 161 | 162 | #endregion 163 | 164 | private System.Windows.Forms.GroupBox groupBox1; 165 | private System.Windows.Forms.Panel termPanel; 166 | private System.Windows.Forms.GroupBox groupBox2; 167 | private System.Windows.Forms.Button macroBtn; 168 | private System.Windows.Forms.Button printBtn; 169 | private System.Windows.Forms.TextBox promptBox; 170 | private System.Windows.Forms.Timer timer1; 171 | private System.Windows.Forms.OpenFileDialog openFileDialog1; 172 | private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1; 173 | private System.Windows.Forms.Button closeBtn; 174 | } 175 | } 176 | 177 | -------------------------------------------------------------------------------- /ConEmuInside/ConEmu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /ConEmuWinForms/ConEmu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /ConEmuInside/GuiMacro.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Threading; 4 | 5 | namespace ConEmuInside 6 | { 7 | public class GuiMacroException : Exception 8 | { 9 | public GuiMacroException(string asMessage) 10 | : base(asMessage) 11 | { 12 | } 13 | } 14 | 15 | public class GuiMacro 16 | { 17 | public enum GuiMacroResult 18 | { 19 | // Succeeded 20 | gmrOk = 0, 21 | // Reserved for .Net control module 22 | gmrPending = 1, 23 | gmrDllNotLoaded = 2, 24 | gmrException = 3, 25 | // Bad PID or ConEmu HWND was specified 26 | gmrInvalidInstance = 4, 27 | // Unknown macro execution error in ConEmu 28 | gmrExecError = 5, 29 | }; 30 | 31 | [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 32 | private static extern IntPtr LoadLibrary(string libname); 33 | 34 | [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 35 | private static extern bool FreeLibrary(IntPtr hModule); 36 | 37 | [DllImport("kernel32.dll", CharSet = CharSet.Ansi)] 38 | private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); 39 | 40 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)] 41 | private delegate int FConsoleMain3(int anWorkMode, string asCommandLine); 42 | 43 | public delegate void ExecuteResult(GuiMacroResult code, string data); 44 | 45 | [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)] 46 | private delegate int FGuiMacro(string asWhere, string asMacro, out IntPtr bstrResult); 47 | 48 | private string libraryPath; 49 | private IntPtr ConEmuCD; 50 | private FConsoleMain3 fnConsoleMain3; 51 | private FGuiMacro fnGuiMacro; 52 | 53 | public string LibraryPath 54 | { 55 | get 56 | { 57 | return libraryPath; 58 | } 59 | } 60 | 61 | 62 | protected string ExecuteLegacy(string asWhere, string asMacro) 63 | { 64 | if (ConEmuCD == IntPtr.Zero) 65 | { 66 | throw new GuiMacroException("ConEmuCD was not loaded"); 67 | } 68 | if (fnConsoleMain3 == null) 69 | { 70 | throw new GuiMacroException("ConsoleMain3 function was not found"); 71 | } 72 | 73 | 74 | string cmdLine = " -GuiMacro"; 75 | if (!String.IsNullOrEmpty(asWhere)) 76 | cmdLine += ":" + asWhere; 77 | cmdLine += " " + asMacro; 78 | 79 | Environment.SetEnvironmentVariable("ConEmuMacroResult", null); 80 | 81 | string result; 82 | 83 | int iRc = fnConsoleMain3.Invoke(3, cmdLine); 84 | 85 | switch (iRc) 86 | { 87 | case 200: // CERR_CMDLINEEMPTY 88 | case 201: // CERR_CMDLINE 89 | throw new GuiMacroException("Bad command line was passed to ConEmuCD"); 90 | case 0: // This is expected 91 | case 133: // CERR_GUIMACRO_SUCCEEDED: not expected, but... 92 | result = Environment.GetEnvironmentVariable("ConEmuMacroResult"); 93 | if (result == null) 94 | throw new GuiMacroException("ConEmuMacroResult was not set"); 95 | break; 96 | case 134: // CERR_GUIMACRO_FAILED 97 | throw new GuiMacroException("GuiMacro execution failed"); 98 | default: 99 | throw new GuiMacroException(string.Format("Internal ConEmuCD error: {0}", iRc)); 100 | } 101 | 102 | return result; 103 | } 104 | 105 | protected void ExecuteHelper(string asWhere, string asMacro, ExecuteResult aCallbackResult) 106 | { 107 | if (aCallbackResult == null) 108 | { 109 | throw new GuiMacroException("aCallbackResult was not specified"); 110 | } 111 | 112 | string result; 113 | GuiMacroResult code; 114 | 115 | // New ConEmu builds exports "GuiMacro" function 116 | if (fnGuiMacro != null) 117 | { 118 | IntPtr fnCallback = Marshal.GetFunctionPointerForDelegate(aCallbackResult); 119 | if (fnCallback == IntPtr.Zero) 120 | { 121 | throw new GuiMacroException("GetFunctionPointerForDelegate failed"); 122 | } 123 | 124 | IntPtr bstrPtr = IntPtr.Zero; 125 | int iRc = fnGuiMacro.Invoke(asWhere, asMacro, out bstrPtr); 126 | 127 | switch (iRc) 128 | { 129 | case 0: // This is not expected for `GuiMacro` exported funciton, but JIC 130 | case 133: // CERR_GUIMACRO_SUCCEEDED: expected 131 | code = GuiMacroResult.gmrOk; 132 | break; 133 | case 134: // CERR_GUIMACRO_FAILED 134 | code = GuiMacroResult.gmrExecError; 135 | break; 136 | default: 137 | throw new GuiMacroException(string.Format("Internal ConEmuCD error: {0}", iRc)); 138 | } 139 | 140 | if (bstrPtr == IntPtr.Zero) 141 | { 142 | // Not expected, `GuiMacro` must return some BSTR in any case 143 | throw new GuiMacroException("Empty bstrPtr was returned"); 144 | } 145 | 146 | result = Marshal.PtrToStringBSTR(bstrPtr); 147 | Marshal.FreeBSTR(bstrPtr); 148 | 149 | if (result == null) 150 | { 151 | // Not expected, `GuiMacro` must return some BSTR in any case 152 | throw new GuiMacroException("Marshal.PtrToStringBSTR failed"); 153 | } 154 | } 155 | else 156 | { 157 | result = ExecuteLegacy(asWhere, asMacro); 158 | code = GuiMacroResult.gmrOk; 159 | } 160 | 161 | aCallbackResult(code, result); 162 | } 163 | 164 | public GuiMacroResult Execute(string asWhere, string asMacro, ExecuteResult aCallbackResult) 165 | { 166 | if (ConEmuCD == IntPtr.Zero) 167 | return GuiMacroResult.gmrDllNotLoaded; 168 | 169 | new Thread(() => 170 | { 171 | // Don't block application termination 172 | Thread.CurrentThread.IsBackground = true; 173 | // Start GuiMacro execution 174 | try 175 | { 176 | ExecuteHelper(asWhere, asMacro, aCallbackResult); 177 | } 178 | catch (GuiMacroException e) 179 | { 180 | aCallbackResult(GuiMacroResult.gmrException, e.Message); 181 | } 182 | }).Start(); 183 | 184 | return GuiMacroResult.gmrPending; 185 | } 186 | 187 | public GuiMacro(string asLibrary) 188 | { 189 | ConEmuCD = IntPtr.Zero; 190 | fnConsoleMain3 = null; 191 | fnGuiMacro = null; 192 | libraryPath = asLibrary; 193 | LoadConEmuDll(asLibrary); 194 | } 195 | 196 | ~GuiMacro() 197 | { 198 | UnloadConEmuDll(); 199 | } 200 | 201 | private void LoadConEmuDll(string asLibrary) 202 | { 203 | if (ConEmuCD != IntPtr.Zero) 204 | { 205 | return; 206 | } 207 | 208 | ConEmuCD = LoadLibrary(asLibrary); 209 | if (ConEmuCD == IntPtr.Zero) 210 | { 211 | int errorCode = Marshal.GetLastWin32Error(); 212 | throw new GuiMacroException(string.Format("Can't load library, ErrCode={0}\n{1}", errorCode, asLibrary)); 213 | } 214 | 215 | // int __stdcall ConsoleMain3(int anWorkMode/*0-Server&ComSpec,1-AltServer,2-Reserved*/, LPCWSTR asCmdLine) 216 | const string fnNameOld = "ConsoleMain3"; 217 | IntPtr ptrConsoleMain = GetProcAddress(ConEmuCD, fnNameOld); 218 | const string fnNameNew = "GuiMacro"; 219 | IntPtr ptrGuiMacro = GetProcAddress(ConEmuCD, fnNameNew); 220 | 221 | if ((ptrConsoleMain == IntPtr.Zero) && (ptrGuiMacro == IntPtr.Zero)) 222 | { 223 | UnloadConEmuDll(); 224 | throw new GuiMacroException(string.Format("Function {0} not found in library\n{1}\nUpdate ConEmu modules", fnNameOld, asLibrary)); 225 | } 226 | 227 | if (ptrGuiMacro != IntPtr.Zero) 228 | { 229 | // To call: ExecGuiMacro.Invoke(asWhere, asCommand, callbackDelegate); 230 | fnGuiMacro = (FGuiMacro)Marshal.GetDelegateForFunctionPointer(ptrGuiMacro, typeof(FGuiMacro)); 231 | } 232 | if (ptrConsoleMain != IntPtr.Zero) 233 | { 234 | // To call: ConsoleMain3.Invoke(0, cmdline); 235 | fnConsoleMain3 = (FConsoleMain3)Marshal.GetDelegateForFunctionPointer(ptrConsoleMain, typeof(FConsoleMain3)); 236 | } 237 | } 238 | 239 | private void UnloadConEmuDll() 240 | { 241 | if (ConEmuCD != IntPtr.Zero) 242 | { 243 | FreeLibrary(ConEmuCD); 244 | ConEmuCD = IntPtr.Zero; 245 | } 246 | } 247 | } 248 | 249 | } 250 | -------------------------------------------------------------------------------- /ConEmuInside/TerminalForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Windows.Forms; 4 | using System.Runtime.InteropServices; 5 | using System.Diagnostics; 6 | using System.IO; 7 | 8 | namespace ConEmuInside 9 | { 10 | public partial class ChildTerminal : Form 11 | { 12 | private Process conemu; 13 | private GuiMacro guiMacro; 14 | private readonly TerminalStarter starter; 15 | private ConEmuStartArgs args; 16 | 17 | internal ChildTerminal(TerminalStarter starter, ConEmuStartArgs args) 18 | { 19 | this.starter = starter; 20 | this.args = args; 21 | InitializeComponent(); 22 | } 23 | 24 | private void ChildTerminal_Load(object sender, EventArgs e) 25 | { 26 | this.Left = this.starter.Left + 100; 27 | this.Top = this.starter.Top + 100; 28 | RefreshControls(false); 29 | termPanel.Resize += new System.EventHandler(this.termPanel_Resize); 30 | StartConEmu(); 31 | } 32 | 33 | private void RefreshControls(bool bTermActive) 34 | { 35 | if (bTermActive) 36 | { 37 | AcceptButton = null; 38 | groupBox2.Enabled = true; 39 | if (!termPanel.Visible) 40 | { 41 | termPanel.Visible = true; 42 | } 43 | if (!termPanel.Enabled) 44 | { 45 | termPanel.Enabled = true; 46 | } 47 | } 48 | else 49 | { 50 | if (termPanel.Enabled) 51 | { 52 | termPanel.Enabled = false; 53 | } 54 | groupBox2.Enabled = false; 55 | } 56 | starter.RefreshControls(bTermActive); 57 | } 58 | 59 | internal string GetConEmuExe() 60 | { 61 | bool bExeLoaded = false; 62 | string lsConEmuExe = null; 63 | 64 | while (!bExeLoaded && (conemu != null) && !conemu.HasExited) 65 | { 66 | try 67 | { 68 | lsConEmuExe = conemu.Modules[0].FileName; 69 | bExeLoaded = true; 70 | } 71 | catch (System.ComponentModel.Win32Exception) 72 | { 73 | Thread.Sleep(50); 74 | } 75 | } 76 | 77 | return lsConEmuExe; 78 | } 79 | 80 | // Returns Path to "ConEmuCD[64].dll" (to GuiMacro execution) 81 | internal string GetConEmuDll() 82 | { 83 | // Query real (full) path of started executable 84 | string lsConEmuExe = GetConEmuExe(); 85 | if (lsConEmuExe == null) 86 | return null; 87 | 88 | // Determine bitness of **our** process 89 | string lsDll = (IntPtr.Size == 8) ? "ConEmuCD64.dll" : "ConEmuCD.dll"; 90 | 91 | // Ready to find the library 92 | String lsExeDir, ConEmuCD; 93 | lsExeDir = Path.GetDirectoryName(lsConEmuExe); 94 | ConEmuCD = Path.Combine(lsExeDir, "ConEmu\\" + lsDll); 95 | if (!File.Exists(ConEmuCD)) 96 | { 97 | ConEmuCD = Path.Combine(lsExeDir, lsDll); 98 | if (!File.Exists(ConEmuCD)) 99 | { 100 | ConEmuCD = lsDll; // Must not get here actually 101 | } 102 | } 103 | 104 | return ConEmuCD; 105 | } 106 | 107 | private void ExecuteGuiMacro(string asMacro) 108 | { 109 | // conemuc.exe -silent -guimacro:1234 print("\e","git"," --version","\n") 110 | string conemuDll = GetConEmuDll(); 111 | if (conemuDll == null) 112 | { 113 | throw new GuiMacroException("ConEmuCD must not be null"); 114 | } 115 | 116 | if (guiMacro != null && guiMacro.LibraryPath != conemuDll) 117 | { 118 | guiMacro = null; 119 | } 120 | 121 | try 122 | { 123 | if (guiMacro == null) 124 | guiMacro = new GuiMacro(conemuDll); 125 | guiMacro.Execute(conemu.Id.ToString(), asMacro, 126 | (GuiMacro.GuiMacroResult code, string data) => { 127 | Debugger.Log(0, "GuiMacroResult", "code=" + code.ToString() + "; data=" + data + "\n"); 128 | }); 129 | } 130 | catch (GuiMacroException e) 131 | { 132 | MessageBox.Show(e.Message, "GuiMacroException", MessageBoxButtons.OK, MessageBoxIcon.Error); 133 | } 134 | } 135 | 136 | private void printBtn_Click(object sender, EventArgs e) 137 | { 138 | if (promptBox.Text == "") 139 | return; 140 | String lsMacro; 141 | lsMacro = "Print(@\"" + promptBox.Text.Replace("\"", "\"\"") + "\",\"\n\")"; 142 | ExecuteGuiMacro(lsMacro); 143 | promptBox.SelectAll(); 144 | } 145 | 146 | private void macroBtn_Click(object sender, EventArgs e) 147 | { 148 | if (promptBox.Text == "") 149 | return; 150 | ExecuteGuiMacro(promptBox.Text); 151 | promptBox.SelectAll(); 152 | } 153 | 154 | private void timer1_Tick(object sender, EventArgs e) 155 | { 156 | if ((conemu != null) && conemu.HasExited) 157 | { 158 | timer1.Stop(); 159 | conemu = null; 160 | RefreshControls(false); 161 | Close(); 162 | } 163 | } 164 | 165 | private void promptBox_KeyDown(object sender, KeyEventArgs e) 166 | { 167 | //TODO: Enter and Leave events are not triggered when focus is put into ConEmu window 168 | if (e.KeyValue == 13) 169 | { 170 | printBtn_Click(sender, null); 171 | } 172 | } 173 | 174 | private void promptBox_Enter(object sender, EventArgs e) 175 | { 176 | //TODO: Enter and Leave events are not triggered when focus is put into ConEmu window 177 | //AcceptButton = printBtn; 178 | //promptBox.Text = "...in..."; 179 | } 180 | 181 | private void promptBox_Leave(object sender, EventArgs e) 182 | { 183 | //TODO: Enter and Leave events are not triggered when focus is put into ConEmu window 184 | //if (AcceptButton == printBtn) 185 | //AcceptButton = null; 186 | //promptBox.Text = "...out..."; 187 | } 188 | 189 | internal void StartConEmu() 190 | { 191 | RefreshControls(true); 192 | 193 | var sRunAs = this.args.runAs ? " -cur_console:a" : ""; 194 | 195 | var sRunArgs = (this.args.debug ? " -debugw" : "") + 196 | " -NoKeyHooks" + 197 | " -InsideWnd 0x" + termPanel.Handle.ToString("X") + 198 | " -LoadCfgFile \"" + this.args.xmlFilePath + "\"" + 199 | " -Dir \"" + this.args.startupDirectory + "\"" + 200 | (this.args.log ? " -Log" : "") + 201 | (this.args.useGuiMacro ? " -detached" : " -run " + this.args.cmdLine + sRunAs); 202 | 203 | if (this.args.useGuiMacro) 204 | { 205 | promptBox.Text = "Shell(\"new_console\", \"\", \"" + 206 | (this.args.cmdLine + sRunAs).Replace("\"", "\\\"") + 207 | "\")"; 208 | } 209 | 210 | try 211 | { 212 | // Start ConEmu 213 | conemu = Process.Start(this.args.conemuExePath, sRunArgs); 214 | } 215 | catch (System.ComponentModel.Win32Exception ex) 216 | { 217 | RefreshControls(false); 218 | MessageBox.Show(ex.Message + "\r\n\r\n" + 219 | "Command:\r\n" + this.args.conemuExePath + "\r\n\r\n" + 220 | "Arguments:\r\n" + sRunArgs, 221 | ex.GetType().FullName + " (" + ex.NativeErrorCode.ToString() + ")", 222 | MessageBoxButtons.OK, MessageBoxIcon.Error); 223 | return; 224 | } 225 | 226 | RefreshControls(true); 227 | // Start monitoring 228 | timer1.Start(); 229 | 230 | // Execute "startup" macro 231 | if (this.args.useGuiMacro) 232 | { 233 | macroBtn_Click(null, null); 234 | } 235 | } 236 | 237 | [DllImport("user32.dll", SetLastError = true)] 238 | internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); 239 | [DllImport("user32.dll", SetLastError = true)] 240 | internal static extern IntPtr FindWindowEx(IntPtr hParent, IntPtr hChild, string szClass, string szWindow); 241 | 242 | private void termPanel_Resize(object sender, EventArgs e) 243 | { 244 | if (conemu != null) 245 | { 246 | IntPtr hConEmu = FindWindowEx(termPanel.Handle, (IntPtr)0, null, null); 247 | if (hConEmu != (IntPtr)0) 248 | { 249 | //MoveWindow(hConEmu, 0, 0, termPanel.Width, termPanel.Height, true); 250 | } 251 | } 252 | } 253 | 254 | private void closeBtn_Click(object sender, EventArgs e) 255 | { 256 | ExecuteGuiMacro("Close(2,1)"); 257 | } 258 | 259 | private void ChildTerminal_FormClosed(object sender, FormClosedEventArgs e) 260 | { 261 | starter.RefreshControls(false); 262 | } 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /ConEmuWinForms/ConEmuControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Drawing; 4 | using System.Runtime.InteropServices; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | 8 | using ConEmu.WinForms.Util; 9 | 10 | using JetBrains.Annotations; 11 | 12 | namespace ConEmu.WinForms 13 | { 14 | /// 15 | /// This is a console emulator control that embeds a fully functional console view in a Windows Forms window. It is capable of running any console application with full interactivity and advanced console functions. Applications will detect it as an actual console and will not fall back to the output redirection mode with reduced interactivity or formatting. 16 | /// The control can be used to run a console process in the console emulator. The console process is the single command executed in the control, which could be a simple executable (the console emulator is not usable after it exits), or an interactive shell like cmd or powershell or bash, which in turn can execute multiple commands, either by user input or programmatically with . The console emulator is what implements the console and renders the console view in the control. A new console emulator (represented by a ) is started for each console process. After the root console process terminates, the console emulator might remain open (see ) and still present the console window, or get closed. After the console emulator exits, the control is blank until spawns a new console emulator for a console process in it. You cannot run more than one console emulator (or console process) simultaneousely. 17 | /// 18 | public unsafe class ConEmuControl : Control 19 | { 20 | /// 21 | /// Enabled by default, and with all default values (runs the cmd shell). 22 | /// 23 | private ConEmuStartInfo _autostartinfo = new ConEmuStartInfo(); 24 | 25 | private bool _isStatusbarVisible = true; 26 | 27 | /// 28 | /// After the first console process exits (not session), stores its exit code. Changes on the main thread only. 29 | /// 30 | private int? _nLastExitCode; 31 | 32 | /// 33 | /// The running session, if currently running. 34 | /// 35 | [CanBeNull] 36 | private ConEmuSession _running; 37 | 38 | public ConEmuControl() 39 | { 40 | SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.Opaque | ControlStyles.Selectable, true); 41 | 42 | // Prevent downsizing to zero because the current ConEmu implementation asserts on its HWND having positive dimensions 43 | #pragma warning disable once VirtualMemberCallInContructor 44 | MinimumSize = new Size(1, 1); 45 | } 46 | 47 | /// 48 | /// Gets or sets whether this control will start the console process as soon as it's loaded on the form: yes if non-NULL, and no if NULL. 49 | /// Set this to NULL to prevent the console emulator from opening automatically. Adjust this object or assign a new one to setup the console process to be run in the console emulator automatically. 50 | /// You can either specify the console executable to run in , or use its default value for the default Windows console and execute your command in that console with (the console will remain operable and ready to run more commands after the command completes). 51 | /// 52 | /// 53 | /// This object cannot be changed after the first console emulator session starts. The value of the property becomes NULL and cannot be changed either. 54 | /// If you're chaning NULL to non-NULL and the control has already been loaded, it will start executing a new session with these parameters immediately, so make sure you've completed settings up all the parameters before making the assignment. 55 | /// 56 | [CanBeNull] 57 | public ConEmuStartInfo AutoStartInfo 58 | { 59 | get 60 | { 61 | return _autostartinfo; 62 | } 63 | set 64 | { 65 | if(State != States.Unused) 66 | throw new InvalidOperationException("AutoStartInfo can only be changed before the first console emulator session runs in this control."); 67 | _autostartinfo = value; 68 | 69 | // Invariant: if changed to TRUE past the normal AutoStartInfo checking point 70 | if((value != null) && (IsHandleCreated)) 71 | Start(value); 72 | } 73 | } 74 | 75 | /// 76 | /// Gets or sets whether the status bar of the console emulator view should be visible. 77 | /// 78 | public bool IsStatusbarVisible 79 | { 80 | get 81 | { 82 | return _isStatusbarVisible; 83 | } 84 | set 85 | { 86 | _isStatusbarVisible = value; 87 | _running?.BeginGuiMacro("Status").WithParam(0).WithParam(value ? 1 : 2).ExecuteAsync(); 88 | } 89 | } 90 | 91 | /// 92 | /// Gets the exit code of the most recently terminated console process. 93 | /// NULL if no console process has exited in this control yet. 94 | /// Note that if a console process is currently running in the console emulator then you'd be getting the previous exit code until it exits. 95 | /// 96 | public int? LastExitCode 97 | { 98 | get 99 | { 100 | // Special case for just-exited payload: user might get the payload-exited event before us and call this property to get its exit code, while we have not recorded the fresh exit code yet 101 | // So call into the current session and fetch the actual value, if available (no need to write to field, will update in our event handler soon) 102 | ConEmuSession running = _running; 103 | if((running != null) && (running.IsConsoleProcessExited)) 104 | return running.GetConsoleProcessExitCode(); 105 | return _nLastExitCode; // No console emulator open or current process still running in the console emulator, use prev exit code if there were 106 | } 107 | } 108 | 109 | /// 110 | /// Gets the running console emulator session, or NULL if there currently is none. 111 | /// A session represents an open console emulator view displayed in the control, in which a console process is either still running, or has already terminated. 112 | /// To guarantee getting the running session object of a short-lived session before it closes, call manually rather than rely on . 113 | /// This only changes on the main thread. 114 | /// 115 | [CanBeNull] 116 | public ConEmuSession RunningSession => _running; 117 | 118 | /// 119 | /// Gets the current state of the console emulator control regarding whether a console emulator is open in it, and whether there is still a console process running in that emulator. 120 | /// This only changes on the main thread. 121 | /// 122 | public States State => _running != null ? (_running.IsConsoleProcessExited ? States.ConsoleEmulatorEmpty : States.ConsoleEmulatorWithConsoleProcess) : (_nLastExitCode.HasValue ? States.Recycled : States.Unused); 123 | 124 | /// 125 | /// Gets whether a console emulator is currently open, and its console window view is displayed in the control. Of , that's either or . 126 | /// When a console emulator is not open, the control is blank. 127 | /// This only changes on the main thread. 128 | /// 129 | public bool IsConsoleEmulatorOpen => _running != null; 130 | 131 | /// 132 | /// Starts a new console process in the console emulator control, and shows the console emulator view. When a session is not running, the control is blank. 133 | /// If another session is running, it will be closed, and the new session will replace it. will call and create a session automatically if configured. 134 | /// 135 | /// 136 | /// The control state transitions to , then to (unless configured to close on exit), then to . 137 | /// 138 | /// Returns the newly-started session, as in . 139 | [NotNull] 140 | public ConEmuSession Start([NotNull] ConEmuStartInfo startinfo) 141 | { 142 | if(startinfo == null) 143 | throw new ArgumentNullException(nameof(startinfo)); 144 | 145 | // Close prev session if there is one 146 | _running?.CloseConsoleEmulator(); 147 | if(_running != null) 148 | throw new InvalidOperationException("Cannot start a new console process because another console emulator session has failed to close in due time."); 149 | 150 | _autostartinfo = null; // As we're starting, no more chance for an autostart 151 | if(!IsHandleCreated) 152 | CreateHandle(); 153 | 154 | // Spawn session 155 | var session = new ConEmuSession(startinfo, new ConEmuSession.HostContext((void*)Handle, IsStatusbarVisible)); 156 | _running = session; 157 | StateChanged?.Invoke(this, EventArgs.Empty); 158 | 159 | // Wait for its exit 160 | session.WaitForConsoleEmulatorCloseAsync().ContinueWith(scheduler : TaskScheduler.FromCurrentSynchronizationContext(), continuationAction : task => 161 | { 162 | try 163 | { 164 | _nLastExitCode = _running.GetConsoleProcessExitCode(); 165 | } 166 | catch(Exception) 167 | { 168 | // NOP 169 | } 170 | _running = null; 171 | Invalidate(); 172 | StateChanged?.Invoke(this, EventArgs.Empty); 173 | }); 174 | 175 | return session; 176 | } 177 | 178 | [SuppressMessage("ReSharper", "UnusedMember.Local")] 179 | private void AssertNotRunning() 180 | { 181 | if(_running != null) 182 | throw new InvalidOperationException("This change is not possible when a console process is already running."); 183 | } 184 | 185 | protected override void Dispose(bool disposing) 186 | { 187 | base.Dispose(disposing); 188 | 189 | // Cleanup console process 190 | if(_running != null) 191 | { 192 | try 193 | { 194 | _running.CloseConsoleEmulator(); 195 | } 196 | catch(Exception) 197 | { 198 | // Nothing to do with it 199 | } 200 | } 201 | } 202 | 203 | protected override void OnGotFocus(EventArgs e) 204 | { 205 | base.OnGotFocus(e); 206 | 207 | void* hwnd = TryGetConEmuHwnd(); 208 | if(hwnd != null) 209 | WinApi.SetFocus(hwnd); 210 | } 211 | 212 | protected override void OnLayout(LayoutEventArgs levent) 213 | { 214 | base.OnLayout(levent); 215 | void* hwnd = TryGetConEmuHwnd(); 216 | if(hwnd != null) 217 | WinApi.MoveWindow(hwnd, 0, 0, ClientSize.Width, ClientSize.Height, 1); 218 | } 219 | 220 | protected override void OnHandleCreated(EventArgs e) 221 | { 222 | if(AutoStartInfo != null) 223 | Start(AutoStartInfo); 224 | 225 | base.OnHandleCreated(e); 226 | } 227 | 228 | protected override void OnPaint(PaintEventArgs args) 229 | { 230 | if(_running != null) // Occupies the whole area 231 | return; 232 | args.Graphics.FillRectangle(SystemBrushes.ControlDark, args.ClipRectangle); 233 | } 234 | 235 | /// 236 | /// Fires on the main thread whenever changes. 237 | /// 238 | public event EventHandler StateChanged; 239 | 240 | [CanBeNull] 241 | private void* TryGetConEmuHwnd() 242 | { 243 | if(!IsHandleCreated) // Without this check, getting the Handle would cause the control to be loaded, and AutoStartInfo be executed right in the .ctor, because the first call into this func goes in the .ctor 244 | return null; 245 | void* hwndConEmu = null; 246 | WinApi.EnumWindowsProc callback = (hwnd, param) => 247 | { 248 | *((void**)param) = hwnd; 249 | return 0; 250 | }; 251 | WinApi.EnumChildWindows((void*)Handle, (void*)Marshal.GetFunctionPointerForDelegate(callback), (IntPtr)(&hwndConEmu)); 252 | GC.KeepAlive(callback); 253 | return hwndConEmu; 254 | } 255 | } 256 | } -------------------------------------------------------------------------------- /ConEmuInside/StarterForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ConEmuInside 2 | { 3 | partial class TerminalStarter 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.groupBox1 = new System.Windows.Forms.GroupBox(); 32 | this.startPanel = new System.Windows.Forms.Panel(); 33 | this.argAutoClose = new System.Windows.Forms.CheckBox(); 34 | this.argLog = new System.Windows.Forms.CheckBox(); 35 | this.argDebug = new System.Windows.Forms.CheckBox(); 36 | this.label4 = new System.Windows.Forms.Label(); 37 | this.xmlBtn = new System.Windows.Forms.Button(); 38 | this.argXmlFile = new System.Windows.Forms.TextBox(); 39 | this.startBtn = new System.Windows.Forms.Button(); 40 | this.dirBtn = new System.Windows.Forms.Button(); 41 | this.cmdBtn = new System.Windows.Forms.Button(); 42 | this.exeBtn = new System.Windows.Forms.Button(); 43 | this.argRunAs = new System.Windows.Forms.CheckBox(); 44 | this.argDirectory = new System.Windows.Forms.TextBox(); 45 | this.argCmdLine = new System.Windows.Forms.TextBox(); 46 | this.label3 = new System.Windows.Forms.Label(); 47 | this.label2 = new System.Windows.Forms.Label(); 48 | this.argConEmuExe = new System.Windows.Forms.TextBox(); 49 | this.label1 = new System.Windows.Forms.Label(); 50 | this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); 51 | this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); 52 | this.argUseGuiMacro = new System.Windows.Forms.CheckBox(); 53 | this.groupBox1.SuspendLayout(); 54 | this.startPanel.SuspendLayout(); 55 | this.SuspendLayout(); 56 | // 57 | // groupBox1 58 | // 59 | this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 60 | | System.Windows.Forms.AnchorStyles.Left) 61 | | System.Windows.Forms.AnchorStyles.Right))); 62 | this.groupBox1.Controls.Add(this.startPanel); 63 | this.groupBox1.Location = new System.Drawing.Point(12, 12); 64 | this.groupBox1.Name = "groupBox1"; 65 | this.groupBox1.Size = new System.Drawing.Size(576, 332); 66 | this.groupBox1.TabIndex = 0; 67 | this.groupBox1.TabStop = false; 68 | this.groupBox1.Text = "Terminal start parameters"; 69 | // 70 | // startPanel 71 | // 72 | this.startPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 73 | | System.Windows.Forms.AnchorStyles.Right))); 74 | this.startPanel.BackColor = System.Drawing.SystemColors.ButtonFace; 75 | this.startPanel.Controls.Add(this.argUseGuiMacro); 76 | this.startPanel.Controls.Add(this.argAutoClose); 77 | this.startPanel.Controls.Add(this.argLog); 78 | this.startPanel.Controls.Add(this.argDebug); 79 | this.startPanel.Controls.Add(this.label4); 80 | this.startPanel.Controls.Add(this.xmlBtn); 81 | this.startPanel.Controls.Add(this.argXmlFile); 82 | this.startPanel.Controls.Add(this.startBtn); 83 | this.startPanel.Controls.Add(this.dirBtn); 84 | this.startPanel.Controls.Add(this.cmdBtn); 85 | this.startPanel.Controls.Add(this.exeBtn); 86 | this.startPanel.Controls.Add(this.argRunAs); 87 | this.startPanel.Controls.Add(this.argDirectory); 88 | this.startPanel.Controls.Add(this.argCmdLine); 89 | this.startPanel.Controls.Add(this.label3); 90 | this.startPanel.Controls.Add(this.label2); 91 | this.startPanel.Controls.Add(this.argConEmuExe); 92 | this.startPanel.Controls.Add(this.label1); 93 | this.startPanel.Location = new System.Drawing.Point(9, 17); 94 | this.startPanel.Name = "startPanel"; 95 | this.startPanel.Size = new System.Drawing.Size(558, 309); 96 | this.startPanel.TabIndex = 0; 97 | this.startPanel.Text = "Start parameters"; 98 | // 99 | // argAutoClose 100 | // 101 | this.argAutoClose.AutoSize = true; 102 | this.argAutoClose.Location = new System.Drawing.Point(117, 197); 103 | this.argAutoClose.Name = "argAutoClose"; 104 | this.argAutoClose.Size = new System.Drawing.Size(215, 17); 105 | this.argAutoClose.TabIndex = 17; 106 | this.argAutoClose.Text = "Close automatically after command ends"; 107 | this.argAutoClose.UseVisualStyleBackColor = true; 108 | // 109 | // argLog 110 | // 111 | this.argLog.AutoSize = true; 112 | this.argLog.Location = new System.Drawing.Point(117, 174); 113 | this.argLog.Name = "argLog"; 114 | this.argLog.Size = new System.Drawing.Size(108, 17); 115 | this.argLog.TabIndex = 16; 116 | this.argLog.Text = "ConEmu LogFiles"; 117 | this.argLog.UseVisualStyleBackColor = true; 118 | // 119 | // argDebug 120 | // 121 | this.argDebug.AutoSize = true; 122 | this.argDebug.Location = new System.Drawing.Point(117, 151); 123 | this.argDebug.Name = "argDebug"; 124 | this.argDebug.Size = new System.Drawing.Size(111, 17); 125 | this.argDebug.TabIndex = 15; 126 | this.argDebug.Text = "Wait for debugger"; 127 | this.argDebug.UseVisualStyleBackColor = true; 128 | // 129 | // label4 130 | // 131 | this.label4.AutoSize = true; 132 | this.label4.Location = new System.Drawing.Point(6, 101); 133 | this.label4.Name = "label4"; 134 | this.label4.Size = new System.Drawing.Size(68, 13); 135 | this.label4.TabIndex = 14; 136 | this.label4.Text = "ConEmu xml:"; 137 | // 138 | // xmlBtn 139 | // 140 | this.xmlBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 141 | this.xmlBtn.Location = new System.Drawing.Point(525, 97); 142 | this.xmlBtn.Name = "xmlBtn"; 143 | this.xmlBtn.Size = new System.Drawing.Size(24, 21); 144 | this.xmlBtn.TabIndex = 13; 145 | this.xmlBtn.Text = "..."; 146 | this.xmlBtn.UseVisualStyleBackColor = true; 147 | // 148 | // argXmlFile 149 | // 150 | this.argXmlFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 151 | | System.Windows.Forms.AnchorStyles.Right))); 152 | this.argXmlFile.Location = new System.Drawing.Point(117, 97); 153 | this.argXmlFile.Name = "argXmlFile"; 154 | this.argXmlFile.Size = new System.Drawing.Size(402, 20); 155 | this.argXmlFile.TabIndex = 12; 156 | this.argXmlFile.Enter += new System.EventHandler(this.startArgs_Enter); 157 | // 158 | // startBtn 159 | // 160 | this.startBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 161 | this.startBtn.Location = new System.Drawing.Point(117, 274); 162 | this.startBtn.Name = "startBtn"; 163 | this.startBtn.Size = new System.Drawing.Size(169, 23); 164 | this.startBtn.TabIndex = 11; 165 | this.startBtn.Text = "&Start ConEmu"; 166 | this.startBtn.UseVisualStyleBackColor = true; 167 | this.startBtn.Click += new System.EventHandler(this.startBtn_Click); 168 | // 169 | // dirBtn 170 | // 171 | this.dirBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 172 | this.dirBtn.Location = new System.Drawing.Point(525, 70); 173 | this.dirBtn.Name = "dirBtn"; 174 | this.dirBtn.Size = new System.Drawing.Size(24, 21); 175 | this.dirBtn.TabIndex = 10; 176 | this.dirBtn.Text = "..."; 177 | this.dirBtn.UseVisualStyleBackColor = true; 178 | this.dirBtn.Click += new System.EventHandler(this.dirBtn_Click); 179 | // 180 | // cmdBtn 181 | // 182 | this.cmdBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 183 | this.cmdBtn.Location = new System.Drawing.Point(525, 45); 184 | this.cmdBtn.Name = "cmdBtn"; 185 | this.cmdBtn.Size = new System.Drawing.Size(24, 21); 186 | this.cmdBtn.TabIndex = 9; 187 | this.cmdBtn.Text = "..."; 188 | this.cmdBtn.UseVisualStyleBackColor = true; 189 | this.cmdBtn.Click += new System.EventHandler(this.cmdBtn_Click); 190 | // 191 | // exeBtn 192 | // 193 | this.exeBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 194 | this.exeBtn.Location = new System.Drawing.Point(525, 18); 195 | this.exeBtn.Name = "exeBtn"; 196 | this.exeBtn.Size = new System.Drawing.Size(24, 21); 197 | this.exeBtn.TabIndex = 8; 198 | this.exeBtn.Text = "..."; 199 | this.exeBtn.UseVisualStyleBackColor = true; 200 | this.exeBtn.Click += new System.EventHandler(this.exeBtn_Click); 201 | // 202 | // argRunAs 203 | // 204 | this.argRunAs.AutoSize = true; 205 | this.argRunAs.Location = new System.Drawing.Point(117, 128); 206 | this.argRunAs.Name = "argRunAs"; 207 | this.argRunAs.Size = new System.Drawing.Size(123, 17); 208 | this.argRunAs.TabIndex = 7; 209 | this.argRunAs.Text = "&Run as Administrator"; 210 | this.argRunAs.UseVisualStyleBackColor = true; 211 | // 212 | // argDirectory 213 | // 214 | this.argDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 215 | | System.Windows.Forms.AnchorStyles.Right))); 216 | this.argDirectory.Location = new System.Drawing.Point(117, 71); 217 | this.argDirectory.Name = "argDirectory"; 218 | this.argDirectory.Size = new System.Drawing.Size(402, 20); 219 | this.argDirectory.TabIndex = 6; 220 | this.argDirectory.Enter += new System.EventHandler(this.startArgs_Enter); 221 | // 222 | // argCmdLine 223 | // 224 | this.argCmdLine.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 225 | | System.Windows.Forms.AnchorStyles.Right))); 226 | this.argCmdLine.Location = new System.Drawing.Point(117, 45); 227 | this.argCmdLine.Name = "argCmdLine"; 228 | this.argCmdLine.Size = new System.Drawing.Size(402, 20); 229 | this.argCmdLine.TabIndex = 5; 230 | this.argCmdLine.Text = "{cmd}"; 231 | this.argCmdLine.Enter += new System.EventHandler(this.startArgs_Enter); 232 | // 233 | // label3 234 | // 235 | this.label3.AutoSize = true; 236 | this.label3.Location = new System.Drawing.Point(6, 74); 237 | this.label3.Name = "label3"; 238 | this.label3.Size = new System.Drawing.Size(93, 13); 239 | this.label3.TabIndex = 4; 240 | this.label3.Text = "Working directory:"; 241 | // 242 | // label2 243 | // 244 | this.label2.AutoSize = true; 245 | this.label2.Location = new System.Drawing.Point(6, 48); 246 | this.label2.Name = "label2"; 247 | this.label2.Size = new System.Drawing.Size(81, 13); 248 | this.label2.TabIndex = 3; 249 | this.label2.Text = "Start command:"; 250 | // 251 | // argConEmuExe 252 | // 253 | this.argConEmuExe.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 254 | | System.Windows.Forms.AnchorStyles.Right))); 255 | this.argConEmuExe.Location = new System.Drawing.Point(117, 19); 256 | this.argConEmuExe.Name = "argConEmuExe"; 257 | this.argConEmuExe.Size = new System.Drawing.Size(402, 20); 258 | this.argConEmuExe.TabIndex = 1; 259 | this.argConEmuExe.Text = "ConEmu.exe"; 260 | this.argConEmuExe.Enter += new System.EventHandler(this.startArgs_Enter); 261 | // 262 | // label1 263 | // 264 | this.label1.AutoSize = true; 265 | this.label1.Location = new System.Drawing.Point(6, 22); 266 | this.label1.Name = "label1"; 267 | this.label1.Size = new System.Drawing.Size(105, 13); 268 | this.label1.TabIndex = 0; 269 | this.label1.Text = "ConEmu executable:"; 270 | // 271 | // openFileDialog1 272 | // 273 | this.openFileDialog1.DefaultExt = "exe"; 274 | this.openFileDialog1.FileName = "openFileDialog1"; 275 | this.openFileDialog1.Filter = "*.exe files|*.exe|All files|*.*"; 276 | // 277 | // folderBrowserDialog1 278 | // 279 | this.folderBrowserDialog1.Description = "Choose working directory"; 280 | // 281 | // argUseGuiMacro 282 | // 283 | this.argUseGuiMacro.AutoSize = true; 284 | this.argUseGuiMacro.Checked = true; 285 | this.argUseGuiMacro.CheckState = System.Windows.Forms.CheckState.Checked; 286 | this.argUseGuiMacro.Location = new System.Drawing.Point(117, 220); 287 | this.argUseGuiMacro.Name = "argUseGuiMacro"; 288 | this.argUseGuiMacro.Size = new System.Drawing.Size(173, 17); 289 | this.argUseGuiMacro.TabIndex = 18; 290 | this.argUseGuiMacro.Text = "Use GuiMacro to run command"; 291 | this.argUseGuiMacro.UseVisualStyleBackColor = true; 292 | // 293 | // TerminalStarter 294 | // 295 | this.AcceptButton = this.startBtn; 296 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 297 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 298 | this.ClientSize = new System.Drawing.Size(600, 356); 299 | this.Controls.Add(this.groupBox1); 300 | this.MinimumSize = new System.Drawing.Size(40, 39); 301 | this.Name = "TerminalStarter"; 302 | this.Text = "ConEmu Inside"; 303 | this.Load += new System.EventHandler(this.TerminalStarter_Load); 304 | this.groupBox1.ResumeLayout(false); 305 | this.startPanel.ResumeLayout(false); 306 | this.startPanel.PerformLayout(); 307 | this.ResumeLayout(false); 308 | 309 | } 310 | 311 | #endregion 312 | 313 | private System.Windows.Forms.GroupBox groupBox1; 314 | private System.Windows.Forms.Panel startPanel; 315 | private System.Windows.Forms.Label label1; 316 | private System.Windows.Forms.Button dirBtn; 317 | private System.Windows.Forms.Button cmdBtn; 318 | private System.Windows.Forms.Button exeBtn; 319 | private System.Windows.Forms.CheckBox argRunAs; 320 | private System.Windows.Forms.TextBox argDirectory; 321 | private System.Windows.Forms.TextBox argCmdLine; 322 | private System.Windows.Forms.Label label3; 323 | private System.Windows.Forms.Label label2; 324 | private System.Windows.Forms.TextBox argConEmuExe; 325 | private System.Windows.Forms.OpenFileDialog openFileDialog1; 326 | private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1; 327 | private System.Windows.Forms.Button startBtn; 328 | private System.Windows.Forms.Label label4; 329 | private System.Windows.Forms.Button xmlBtn; 330 | private System.Windows.Forms.TextBox argXmlFile; 331 | private System.Windows.Forms.CheckBox argLog; 332 | private System.Windows.Forms.CheckBox argDebug; 333 | private System.Windows.Forms.CheckBox argAutoClose; 334 | private System.Windows.Forms.CheckBox argUseGuiMacro; 335 | } 336 | } 337 | --------------------------------------------------------------------------------