├── 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 | 
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 |
--------------------------------------------------------------------------------