├── .gitattributes ├── .gitignore ├── Build.xml ├── CHANGES ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── inventory ├── .gitignore ├── Build.xml ├── CHANGES ├── Inventory.csproj ├── Inventory.sln ├── LICENSE ├── Properties │ └── AssemblyInfo.cs ├── README.md └── Sources │ ├── Messages.cs │ ├── Paths.cs │ ├── Program.cs │ ├── Program.ico │ ├── Scanner.cs │ └── Storage.cs ├── launcher ├── .gitignore ├── Build.xml ├── CHANGES ├── LICENSE ├── Launcher.csproj ├── Launcher.sln ├── Properties │ ├── App.manifest │ └── AssemblyInfo.cs ├── README.md ├── Resources │ └── animation.gif └── Sources │ ├── Control.Designer.cs │ ├── Control.cs │ ├── Control.resx │ ├── Messages.cs │ ├── Program.cs │ ├── Program.ico │ ├── Settings.cs │ ├── Settings.xml │ ├── Tiles │ ├── MetaTile.cs │ ├── MetaTileGrid.cs │ └── MetaTileScreen.cs │ └── Utilities │ ├── Graphics.cs │ └── ScanCode.cs ├── platform ├── .gitignore ├── Build.xml ├── CHANGES ├── LICENSE ├── Platform.csproj ├── Platform.sln ├── Properties │ ├── App.manifest │ └── AssemblyInfo.cs ├── README.md ├── Resources │ ├── diskpart │ │ ├── attach │ │ ├── compact │ │ ├── create │ │ └── detach │ ├── platform │ │ ├── AutoRun.inf │ │ ├── Programs │ │ │ ├── Macros │ │ │ │ ├── macro.cmd │ │ │ │ └── macros.cmd │ │ │ └── Platform │ │ │ │ ├── inventory.exe │ │ │ │ ├── launcher.exe │ │ │ │ ├── launcher.xml │ │ │ │ ├── platform.dll │ │ │ │ └── startup.exe │ │ ├── Resources │ │ │ ├── manual.md │ │ │ ├── platform.ico │ │ │ └── platform.png │ │ ├── Startup.cmd │ │ └── Storage │ │ │ └── registry.data │ └── settings.ini └── Sources │ ├── Diskpart.cs │ ├── Messages.cs │ ├── Program.cs │ ├── Program.ico │ ├── Resources.Designer.cs │ ├── Resources.Extension.cs │ ├── Resources.resx │ ├── Service.cs │ ├── Settings.cs │ ├── Worker.Designer.cs │ ├── Worker.cs │ └── Worker.resx ├── resources ├── example.gif └── usage.gif ├── shiftdown └── README.md └── startup ├── .gitignore ├── Build.xml ├── CHANGES ├── LICENSE ├── Properties └── AssemblyInfo.cs ├── README.md ├── Sources ├── Program.cs └── Program.ico ├── Startup.csproj └── Startup.sln /.gitattributes: -------------------------------------------------------------------------------- 1 | core.autocrlf true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /**/.idea/ 2 | /**/Release/ 3 | /**/Target/ 4 | 5 | /platform/Resources/platform/Programs/Platform/platform.dll 6 | -------------------------------------------------------------------------------- /Build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Following targets are available: 5 | 6 | changes Synchronizes README.md with CHANGES 7 | 8 | release Builds the complete release 9 | Synchronizes the version in README.md 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 27 | 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 | 61 | 62 | 63 | 64 | 67 | 68 | 69 | 70 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 83 | 86 | 89 | 90 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | 3.6.0 20241230 2 | BF: Platform: Optimization and corrections 3 | BF: Launcher: Correction/optimization 4 | BF: Launcher: Correction when using custom scaling 5 | Correction of the possibly incorrect calculation of 6 | FormWindowState.Maximized for custom scaling. 7 | BF: Settings: Correction to ignore invalid paths in section [FILES] 8 | Previously, the replacement of the placeholders was terminated without error 9 | after the first incorrect path and the initialization of the platform 10 | continued. 11 | BF: Platform: Names of environment variables are case-sensitive 12 | CR: Platform: Omission of the steps recorder (deprecated by Microsoft) 13 | CR: Platform: Simplification of the terminal action 14 | CR: Launcher: Added events (SessionEndingReason) 15 | 16 | 3.5.0 20240706 17 | BF: DiskPart: Optimization of attach 18 | - Name of the volume is no longer relevant 19 | BF: DiskPart: Optimization of detach if an error occurs 20 | BF: DiskPart: Optimization of compact 21 | BF: Platform: Correction if no .ini file exists 22 | - Caused an ArgumentNullException during attachment 23 | CR: Platform: Optimization of output/logging 24 | - If an error occurs 25 | - Batch processes (startup / exit) is output in the log file 26 | 27 | 3.4.0 20240302 28 | BF: Review: Optimization and corrections 29 | BF: DiskPart: Optimization when attaching disks with the same label 30 | BF: DiskPart: Correction when creating with Windows 11 31 | CR: DiskPart: Optimization of detach if an error occurs 32 | CR: Macros: Optimization of the use of WORKDIR 33 | CR: Macros: Usable as direct short commands 34 | CR: Project: Updated TargetFrameworkVersion to v4.8 35 | CR: Platform: Refactoring of the standard directory structure 36 | - Spaces in the path have been omitted 37 | - Formerly Database is now part of Storage 38 | - Formerly Install is now part of Resources 39 | - Core components of the platform are located in /Programs/Platform 40 | + Documents 41 | + Music 42 | + Pictures 43 | + Videos 44 | + Programs 45 | + Macros 46 | + macros 47 | + Platform 48 | + Resources 49 | + Settings 50 | + Storage 51 | + Temp 52 | CR: Launcher: Updated TargetFrameworkVersion to v4.8 53 | CR: Startup: Updated TargetFrameworkVersion to v4.8 54 | 55 | 3.3.0 20230710 56 | BF: Settings: Spaces at the end of values are now ignored 57 | BF: Launcher: Correction/optimization of the output if the HotKey cannot be registered 58 | CR: Build: Releases are now only available on the release page 59 | CR: Macros: Added to temporarily change the command line configuration 60 | Create your own macros as cmd-file in Program Portables/Macros/macros. 61 | Call: 'macro [macro]' or 'macros [macro]' on the command line. 62 | CR: Platform: Added batch processing freeze detection 63 | Detects freezing script on attach and detach the platform and causes 64 | error instead of freezing itself. 65 | CR: ShiftDown: Omission of ShiftDown as standard tool 66 | CR: ShiftDown: Renaming in Balancer 67 | CR: ShiftDown: Outsourcing as a separate project 68 | 69 | 3.2.0 20220625 70 | BF: Build: Correction of the release info process 71 | BF: Launcher: Correction of the behavior when the screen resolution changes 72 | Triggers the update of the user interface. 73 | CR: Platform: Optimization when detaching / process termination 74 | Killing of processes can be blocked by system protection. 75 | It is tried up to three times and then ignored. 76 | CR: Platform: Integrated settings as a core component 77 | The key values of the settings are part of the environment variables of 78 | the virtual environment. 79 | CR: Launcher: Scaling of icons depending on screen resolution (aesthetic reasons) 80 | CR: Launcher: Increase from the default value of OPACITY (95) 81 | CR: Launcher: Added option AutoScale (default true) 82 | Scales the view according to the screen resolution ot the primary screen 83 | CR: Shiftdown: Change the location to /Program Portables/ShiftDown 84 | 85 | 3.1.0 20220401 86 | BF: Platform: Correction of settings template synchronization 87 | If the target file is newer than the template, the template will be updated. 88 | BF: Platform Create: Correction of settings directory 89 | Has been moved from \Documents\Settings to \Settings. 90 | BF: Platform: Compact per Diskpart was not executed 91 | BF: Platform: Optimization and corrections 92 | BF: Platform: Optimization and corrections of the texts 93 | BF: Settings: Correction of template synchronization 94 | If the target file is newer than the template, the template will be updated. 95 | BF: Settings: Optimization and corrections 96 | CR: Environment: Unification of namespace / platform icon / (sub) project structure 97 | CR: Environment: Added build script/process via Ant 98 | CR: Launcher: Switching to a self-developed one 99 | So far MaxLauncher was preferred -- is great software, many ideas were taken from there. 100 | But the virtual environment should get its own, where the license fits. 101 | CR: Platform: Optimization / enhancement of function compact 102 | CR: Platform: Optimization of notification message output 103 | CR: Platform: Unification of namespace / platform icon / (sub) project structure 104 | CR: Platform: Added build script/process via Ant 105 | CR: Platform: Optimization of error logging 106 | CR: Platform: Added console as default command line prompt 107 | CR: Platform: Added launcher as default launcher to keep the environment alive 108 | CR: Platform: Added shiftdown as optional service to shift down the process priority 109 | The service automatically downgrades the process priority of CPU-intensive processes. 110 | For older Intel generations that suffer from the update of Windows and Intel. 111 | CR: Settings: Unification of namespace / platform icon / (sub) project structure 112 | CR: Settings: Added build script/process via Ant 113 | CR: ShiftDown: Added to improve multitasking of older CPUs 114 | The service automatically downgrades the process priority of CPU-intensive processes. 115 | For older Intel generations that suffer from the update of Windows and Intel. 116 | 117 | 3.0.0 20211126 118 | CR: License: Changed to Apache License Version 2.0 119 | CR: Project: Change from Ant to .NET 120 | CR: Platform: Added function compact 121 | Cleans the temp directory on the virtual disk and compacts the disk in general. 122 | e.g. platform.exe B: compact 123 | CR: Platform: Added function shortcuts 124 | Creates the usual calls as shortcuts. 125 | e.g. platform.exe B: shortcuts 126 | CR: Settings: Added for placeholder replacement in files 127 | This simplifies the personalization , distribution, migrations and updates. 128 | 129 | 2.5.0 2019xxxx 130 | CR: Added support for VHDX and BitLocker 131 | NT: More details have been lost 132 | 133 | 2.0.0 2015xxxx 134 | CR: Change from SUBST to virtual disk VHD 135 | NT: More details have been lost 136 | 137 | 1.0.0 20xxxxxx 138 | NT: More details have been lost 139 | NT: Release is available 140 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | ## Table of Contents 4 | - [Code Conventions](#code-conventions) 5 | - [Action](#action) 6 | - [Constants](#constants) 7 | - [Func](#func) 8 | - [Private Field](#private-field) 9 | 10 | ## Code Conventions 11 | 12 | ### Action 13 | - PascalCase 14 | ```csharp 15 | Action OutputMessage = message => 16 | Console.WriteLine(message); 17 | ``` 18 | 19 | ### Constant 20 | - SCREAMING_SNAKE_CASE 21 | ```csharp 22 | const int EXAMPLE_CONSTANT = 1; 23 | ``` 24 | 25 | ### Func 26 | - PascalCase 27 | ```csharp 28 | Func IsEmptyString = text => 29 | String.IsNullOrWhiteSpace(text); 30 | ``` 31 | 32 | ### Private Field 33 | - leading underscore and camelCase 34 | ```csharp 35 | private int _examplePrivateField = 1; 36 | ``` 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 7 | 11 | 14 | 17 |

18 | 19 | 20 | # Description 21 | Since about 2010, there is the project of a virtual environment with modular 22 | structure for developers and users, so that they can use a fully pre-configured 23 | environment with all programs, tools and services, without modifying the host 24 | environment or requiring additional dedicated virtualization resources. 25 | 26 | Short setup times, uniform tools with uniform configuration, uniform paths in 27 | the file system, centralized maintenance and easy distribution and updating are 28 | some of the benefits. The environment is easily customizable, can be quickly 29 | switched to use for different projects, and the environment can be easily 30 | transferred to other machines where work started can be continued. 31 | 32 | __The project includes with [platform](platform), a tool for the initial 33 | creation, use and management of the virtual environment and a 34 | [module concept](modules) for the automatic integration and configuration of 35 | tools and programs from any source on the Internet.__ 36 | 37 | __The module concept is a successful PoC (proof of concept), but is not 38 | currently the focus of the project. So the software has to be set up manually 39 | in the virtual environment, but that's easy because it's a normal drive.__ 40 | 41 | Since in large companies the strict use of BitLocker is often required, this is 42 | also supported. 43 | 44 | __What is the difference with PortableApps.com or portapps.io?__ 45 | 46 | The virtual environment focuses on the virtual drive as a platform. It is about 47 | the advantages that the platform can be used as a single file and programs and 48 | services can be used in it with a complete configuration and with reliable 49 | absolute paths. 50 | 51 | The integration and distribution of portable applications are not the ambition 52 | of this project. 53 | 54 | The use of modules for the integration of programs and services is planned, but 55 | is more an exemplification of the possibilities for the integration of programs 56 | and services. However, it is not the intention of the project to establish a 57 | corresponding eco-system or repository. 58 | 59 | [PortableApps.com](https://portableapps.com/apps) and 60 | [portapps.io](https://portapps.io/apps) complement the virtual environment 61 | perfectly and both release very good portable versions of programs that can be 62 | used in the virtual environment. 63 | 64 | 65 | ## Advantages 66 | - A virtual drive is used, which contains all data in one file. 67 | - The drives can also be supplied and used via the network. 68 | - Only one large file can be copied faster and also shared. 69 | - Snapshots and versioning are possible. 70 | - Multiple drives with different environments can be used in parallel on one computer. 71 | - Fast switching between different drives and environments is possible. 72 | - Fixed drive letters and paths are used. 73 | - The use of the file system and registry from the host is avoided. 74 | - Environments can be maintained and distributed centrally. 75 | - A team use the same environment with the same paths and configurations, which facilitates automation. 76 | 77 | 78 | # Features 79 | - Supports VHD, VHDX as virtual drive also with Bitlocker 80 | - Functions to create, launch, manage and compact the environment 81 | - The environment is immediately usable after creation 82 | - Integrated program launcher with optimized keyboard support for fast program access 83 | - Personalization of environment and programs through a separate key values file 84 | - Very small and resource-efficient implementation of the platform 85 | - The use of the local file system and the registry is avoided 86 | - Easy customization according to the requirements 87 | - Simplifies centralized maintenance and distribution 88 | - Simplifies automation 89 | 90 | 91 | # Licence Agreement 92 | LIZENZBEDINGUNGEN - Seanox Software Solutions ist ein Open-Source-Projekt, im 93 | Folgenden Seanox Software Solutions oder kurz Seanox genannt. 94 | 95 | Diese Software unterliegt der Version 2 der Apache License. 96 | 97 | Copyright (C) 2025 Seanox Software Solutions 98 | 99 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 100 | this file except in compliance with the License. You may obtain a copy of the 101 | License at 102 | 103 | https://www.apache.org/licenses/LICENSE-2.0 104 | 105 | Unless required by applicable law or agreed to in writing, software distributed 106 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 107 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 108 | specific language governing permissions and limitations under the License. 109 | 110 | 111 | # System Requirement 112 | - Microsoft Windows 10 or higher 113 | - Microsoft .NET 4.8.x or higher (for runtime) 114 | - [Microsoft .NET 4.8.x Developer Pack or higher]( 115 | https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48) (for development only) 116 | 117 | 118 | # Downloads 119 | [Seanox Virtual Environment 3.5.0](https://github.com/seanox/virtual-environment/releases/download/3.5.0/seanox-platform-3.5.0.zip) 120 | [Seanox Virtual Environment 3.5.0 Update](https://github.com/seanox/virtual-environment/releases/download/3.5.0/seanox-platform-3.5.0-update.zip) for existing environment 121 | 122 | 123 | ## Example 124 | Download the master templates as virtual environments (approx __4 GB__ / 125 | last update 2024-09-20): 126 | https://seanox.com/storage/master-3.6.0.7z 127 | https://seanox.com/storage/master-proxy-3.6.0.7z 128 | 129 | Included is a complete development environment with various tools for AWS, 130 | Kubernetes, Terraform, Java and Node.js, including a customized Eclipse, a 131 | PostgreSQL database and much more. 132 | 133 | Start `master.exe B: attach`. 134 | 135 | The host key combination for the launcher: `Win + ESC` 136 | 137 | To exit, use the Detach button at the bottom right of the launcher. 138 | 139 | 140 | 141 | ## Use the examples as a template for your own environment 142 | - Download the example(s) 143 | - Rename `master.exe`, `master.ini` and `master.vhdx` to your name 144 | 145 | Next steps are optional and after attaching 146 | 147 | - Change the label of the virtual disk (properties of disk) 148 | - Change the name of the virtual volume in `AutoRun.inf` 149 | 150 | 151 | # Usage 152 | - Download the last release of [seanox-platform.zip](#downloads) 153 | - Extract the file to any location in the local file system 154 | - Rename __platform.exe__ to the name that will be used for the environment and drive 155 | 156 | Then the program can be used as follows:: 157 | 158 | `usage: platform.exe A-Z: [create|attach|detach|compact|shortcuts] ` 159 | 160 | Example 161 | - `platform.exe B: create` to create the initial environment as VHDX 162 | - `platform.exe B: shortcuts` to create the usual calls as shortcuts 163 | - `platform.exe B: attach` to attach the environment 164 | 165 | Configure __Startup.cmd__ in the root directory of the virtual environment and 166 | add the desired programs and services. It is recommended to use a launcher so 167 | that the environment variables are available to the called programs. Detach 168 | should also be started via the launcher if programs and services are terminated 169 | when detaching and the environment variables are needed for this. 170 | 171 | - `platform.exe B: detach` to detach the environment 172 | - `platform.exe B: compact` to compact the virtual disk 173 | 174 | __Module integration will come later, but will be similar.__ 175 | 176 | 177 | 178 | 179 | # Changes 180 | ## 3.5.0 20240706 181 | BF: DiskPart: Optimization of attach 182 | BF: DiskPart: Optimization of detach if an error occurs 183 | BF: DiskPart: Optimization of compact 184 | BF: Platform: Correction if no .ini file exists 185 | CR: Platform: Optimization of output/logging 186 | 187 | [Read more](https://raw.githubusercontent.com/seanox/virtual-environment/main/CHANGES) 188 | 189 | 190 | # Contact 191 | [Issues](https://github.com/seanox/virtual-environment/issues) 192 | [Requests](https://github.com/seanox/virtual-environment/pulls) 193 | [Mail](https://seanox.com/contact) 194 | -------------------------------------------------------------------------------- /inventory/.gitignore: -------------------------------------------------------------------------------- 1 | # Use the parent .gitignore 2 | -------------------------------------------------------------------------------- /inventory/Build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Following targets are available: 5 | 6 | changes Synchronizes README.md with CHANGES 7 | 8 | release Builds the complete release 9 | Synchronizes the version in README.md 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 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 | 109 | 110 | 111 | 112 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 129 | 130 | 131 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 160 | 161 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /inventory/CHANGES: -------------------------------------------------------------------------------- 1 | 1.0.0 20250701 2 | NT: Release is available 3 | -------------------------------------------------------------------------------- /inventory/Inventory.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {E23F6A19-4C7D-482B-9F90-3D65C1A8A177} 8 | Exe 9 | VirtualEnvironment.Inventory 10 | Inventory 11 | v4.8 12 | 512 13 | true 14 | true 15 | Sources\Program.ico 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | Target\bin\Debug\ 23 | Target\obj\Debug\ 24 | Target\obj\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | false 29 | 30 | 31 | AnyCPU 32 | pdbonly 33 | true 34 | Target\bin\Release\ 35 | Target\obj\Release\ 36 | Target\obj\Release\ 37 | prompt 38 | 4 39 | false 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /inventory/Inventory.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Inventory", "Inventory.csproj", "{E23F6A19-4C7D-482B-9F90-3D65C1A8A177}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {E23F6A19-4C7D-482B-9F90-3D65C1A8A177}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {E23F6A19-4C7D-482B-9F90-3D65C1A8A177}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {E23F6A19-4C7D-482B-9F90-3D65C1A8A177}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {E23F6A19-4C7D-482B-9F90-3D65C1A8A177}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {F83D2CBA-1A5F-4E92-BCF3-7D6E8A5C90B1} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /inventory/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Inventory for Seanox Virtual Environment")] 8 | [assembly: AssemblyDescription("Scans and extracts changes in the file system and registry.")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Seanox Software Solutions")] 11 | [assembly: AssemblyProduct("Inventory")] 12 | [assembly: AssemblyCopyright("Copyright © 0000 Seanox Software Solutions")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("e23f6a19-4c7d-482b-9f90-3d65c1a8a177")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("0.0.0")] 35 | [assembly: AssemblyFileVersion("0.0.0")] 36 | [assembly: AssemblyMetadata("Build", "00000000")] 37 | -------------------------------------------------------------------------------- /inventory/README.md: -------------------------------------------------------------------------------- 1 | # Inventory 2 | Scans and extracts changes in the file system and registry. 3 | 4 | The program analyzes changes in the file system of the system disk and the 5 | Windows registry through comparative status snapshots. It creates hash-based 6 | scan files that either contain full paths or aggregated hash values -- depending 7 | on the user-defined scan depth. 8 | 9 | Up to the specified scan depth, paths are fully recorded in the scan files. For 10 | deeper structures beyond this depth, a hash value is calculated that represents 11 | their entire content. The maximum scan depth is limited by the file system of 12 | the operating system. 13 | 14 | A second scan again creates scan files for the file system and the registry. By 15 | comparing the two scans, only modified and added data is extracted and stored as 16 | an exact copy of the affected files in an inventory directory. Deleted data is 17 | not recorded. 18 | 19 | For the copy of the file system, standard environment variables are used for 20 | paths, making them independent of drive letters and user accounts. Registry 21 | changes are saved in plain text in registry.data. 22 | 23 | The tool facilitates the creation of portable applications, as the recorded 24 | changes make it clear which files and registry entries an application requires 25 | and which may need to be abstracted. Additionally, it improves the traceability 26 | of changes after a software installation. 27 | 28 | # System Requirement 29 | - Microsoft Windows 10 or higher 30 | - Microsoft .NET 4.8.x or higher (for runtime) 31 | - [Microsoft .NET 4.8.x Developer Pack or higher]( 32 | https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48) (for development only) 33 | 34 | # Download 35 | Inventory is [part of the virtual environment]( 36 | https://github.com/seanox/virtual-environment/tree/main/platform/Resources/platform/Programs/Platform) 37 | but can also be downloaded and used separately. 38 | 39 | https://github.com/seanox/virtual-environment/releases 40 | 41 | # Changes 42 | ## 0.0.0 00000000 43 | NT: Coming soon 44 | 45 | [Read more](https://raw.githubusercontent.com/seanox/virtual-environment/master/inventory/CHANGES) 46 | -------------------------------------------------------------------------------- /inventory/Sources/Messages.cs: -------------------------------------------------------------------------------- 1 | // LICENSE TERMS - Seanox Software Solutions is an open source project, 2 | // hereinafter referred to as Seanox Software Solutions or Seanox for short. 3 | // This software is subject to version 2 of the Apache License. 4 | // 5 | // Virtual Environment Inventory 6 | // Scans and extracts changes in the file system and registry. 7 | // Copyright (C) 2025 Seanox Software Solutions 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 10 | // use this file except in compliance with the License. You may obtain a copy of 11 | // the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | // License for the specific language governing permissions and limitations under 19 | // the License. 20 | 21 | using System; 22 | using System.Collections.Generic; 23 | using System.Linq; 24 | using System.Text; 25 | using System.Text.RegularExpressions; 26 | using System.Threading.Tasks; 27 | 28 | namespace VirtualEnvironment.Inventory 29 | { 30 | internal static class Messages 31 | { 32 | private static readonly HashSet _subscriptions; 33 | 34 | private static readonly object _lock; 35 | 36 | static Messages() 37 | { 38 | _subscriptions = new HashSet(); 39 | _lock = new object(); 40 | } 41 | 42 | internal static void Subscribe(ISubscriber recipient) 43 | { 44 | if (recipient is null) 45 | throw new ArgumentNullException(); 46 | lock (_lock) 47 | _subscriptions.Add(recipient); 48 | } 49 | 50 | internal static void Unsubscribe(ISubscriber recipient) 51 | { 52 | if (recipient is null) 53 | throw new ArgumentNullException(); 54 | lock (_lock) 55 | _subscriptions.Remove(recipient); 56 | } 57 | 58 | internal interface ISubscriber 59 | { 60 | void Receive(Message message); 61 | } 62 | 63 | internal static void Push(params Message[] messages) 64 | { 65 | List recipients; 66 | lock (_lock) 67 | recipients = _subscriptions.ToList(); 68 | 69 | Parallel.ForEach(messages, message => 70 | Parallel.ForEach(recipients, recipient => 71 | { 72 | try { recipient.Receive(message); } catch { } 73 | })); 74 | } 75 | 76 | internal static void Push(Type type, params string[] data) 77 | { 78 | Push(new Message(type, data)); 79 | } 80 | 81 | internal static void Push(Type type, string context, params string[] data) 82 | { 83 | Push(new Message(type, context, data)); 84 | } 85 | 86 | internal static void Push(Type type, object data) 87 | { 88 | Push(new Message(type, data)); 89 | } 90 | 91 | internal static void Push(Type type, string context, object data) 92 | { 93 | Push(new Message(type, context, data)); 94 | } 95 | 96 | internal enum Type 97 | { 98 | Error, 99 | Warning, 100 | Trace, 101 | Verbose, 102 | Data, 103 | Exit 104 | } 105 | 106 | internal readonly struct Message 107 | { 108 | internal Type Type { get; } 109 | internal string Context { get; } 110 | internal object Data { get; } 111 | 112 | internal Message(Type type, object data) 113 | : this(type, null, data) 114 | { 115 | } 116 | 117 | internal Message(Type type, string context, object data) 118 | { 119 | Type = type; 120 | if (!String.IsNullOrWhiteSpace(context)) 121 | context = Regex.Replace(context, @"[\r\n]+", " ").Trim(); 122 | Context = !String.IsNullOrWhiteSpace(context) ? context : null; 123 | if (data is IEnumerable lines) 124 | data = String.Join(System.Environment.NewLine, lines); 125 | Data = data; 126 | } 127 | 128 | internal Message ConvertTo(Type type) 129 | { 130 | return new Message(type, Context, Data); 131 | } 132 | 133 | public override string ToString() 134 | { 135 | var stringBuilder = new StringBuilder(Type.ToString().ToUpper()) 136 | .Append(" "); 137 | 138 | var content = Data; 139 | 140 | if (!String.IsNullOrWhiteSpace(Context)) 141 | stringBuilder.AppendLine(Context); 142 | 143 | if (Data is Exception exception) 144 | { 145 | stringBuilder.Append(exception.GetType().Name); 146 | if (!String.IsNullOrWhiteSpace(exception.Message)) 147 | stringBuilder.Append($": {exception.Message.Trim()}"); 148 | stringBuilder.AppendLine(); 149 | if (!(exception.StackTrace is null)) 150 | content = exception.StackTrace 151 | .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) 152 | .Select(line => Convert.ToString(line).Trim()); 153 | else content = null; 154 | } 155 | 156 | if (!(content is IEnumerable) 157 | && content is IEnumerable objects) 158 | content = objects 159 | .Where(line => !(line is null)) 160 | .Select(line => Convert.ToString(line).Trim()) 161 | .Where(line => !String.IsNullOrWhiteSpace(line)); 162 | 163 | if (content is IEnumerable strings) 164 | content = String.Join(Environment.NewLine, 165 | strings.Where(line => !String.IsNullOrWhiteSpace(line))); 166 | 167 | content = Convert.ToString(content).Trim(); 168 | if (!String.IsNullOrEmpty((string)content)) 169 | stringBuilder.Append(content); 170 | 171 | return stringBuilder.ToString().Trim(); 172 | } 173 | } 174 | } 175 | } -------------------------------------------------------------------------------- /inventory/Sources/Paths.cs: -------------------------------------------------------------------------------- 1 | // LICENSE TERMS - Seanox Software Solutions is an open source project, 2 | // hereinafter referred to as Seanox Software Solutions or Seanox for short. 3 | // This software is subject to version 2 of the Apache License. 4 | // 5 | // Virtual Environment Inventory 6 | // Scans and extracts changes in the file system and registry. 7 | // Copyright (C) 2025 Seanox Software Solutions 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 10 | // use this file except in compliance with the License. You may obtain a copy of 11 | // the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | // License for the specific language governing permissions and limitations under 19 | // the License. 20 | 21 | using System; 22 | using System.Collections.Generic; 23 | using System.IO; 24 | using System.Linq; 25 | using System.Text.RegularExpressions; 26 | 27 | namespace VirtualEnvironment.Inventory 28 | { 29 | internal static class Paths 30 | { 31 | // https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation 32 | // Please read twice: 260 vs. 256 vs. 259 -1 characters 33 | // I don't understand how the documentary comes to 260 characters :-| 34 | // - drive letter (C:) 2 Chars 35 | // - backslash 1 Char 36 | // - max. path characters 256 Chars 37 | // Subtotal 259 Chars 38 | // - terminating null character -1 Char 39 | // Total 258 Chars 40 | // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem -> LongPathsEnabled 41 | // Possible customizations is ignored. That's too much :-| 42 | internal const int FILE_SYSTEM_MAX_PATH = 258; 43 | 44 | internal static readonly string SYSTEM_DRIVE; 45 | internal static readonly string SYSTEM_DRIVE_PATH; 46 | 47 | internal static readonly string SYSTEM_VOLUME_INFORMATION_PATH; 48 | 49 | internal static readonly string SYSTEM_PROGRAM_FILES_PATH; 50 | internal static readonly string SYSTEM_PROGRAM_FILES_X86_PATH; 51 | internal static readonly string SYSTEM_PROGRAM_DATA_PATH; 52 | 53 | internal static readonly string SYSTEM_ROOT_PATH; 54 | 55 | internal static readonly string SYSTEM_WINDOWS_PATH; 56 | 57 | internal static readonly string USER_PROFILE_PATH; 58 | 59 | static Paths() 60 | { 61 | var systemDrive = Environment.GetEnvironmentVariable("SystemDrive"); 62 | if (String.IsNullOrEmpty(systemDrive)) 63 | systemDrive = "C:"; 64 | SYSTEM_DRIVE = systemDrive; 65 | SYSTEM_DRIVE_PATH = PathNormalize(systemDrive).ToUpper() + Path.DirectorySeparatorChar; 66 | 67 | var environmentVariables = new Dictionary(StringComparer.OrdinalIgnoreCase) 68 | { 69 | { "ProgramData", $@"{SYSTEM_DRIVE}\ProgramData" }, 70 | { "ProgramFiles", $@"{SYSTEM_DRIVE}\Program Files" }, 71 | { "ProgramFiles(x86)", $@"{SYSTEM_DRIVE}\Program Files (x86)" }, 72 | { "SystemRoot", $@"{SYSTEM_DRIVE}\Windows" }, 73 | { "WinDir", $@"{SYSTEM_DRIVE}\Windows" }, 74 | }; 75 | 76 | foreach (var key in environmentVariables.Keys.ToList()) 77 | { 78 | var value = Environment.GetEnvironmentVariable(key); 79 | if (!string.IsNullOrEmpty(value)) 80 | environmentVariables[key] = value; 81 | } 82 | 83 | SYSTEM_VOLUME_INFORMATION_PATH = 84 | PathNormalize(Path.Combine(SYSTEM_DRIVE_PATH, "System Volume Information")); 85 | 86 | SYSTEM_PROGRAM_FILES_PATH = PathNormalize(environmentVariables["ProgramFiles"]); 87 | SYSTEM_PROGRAM_FILES_X86_PATH = PathNormalize(environmentVariables["ProgramFiles(x86)"]); 88 | SYSTEM_PROGRAM_DATA_PATH = PathNormalize(environmentVariables["ProgramData"]); 89 | 90 | SYSTEM_ROOT_PATH = PathNormalize(environmentVariables["SystemRoot"]); 91 | SYSTEM_WINDOWS_PATH = PathNormalize(environmentVariables["WinDir"]); 92 | 93 | USER_PROFILE_PATH = PathNormalize(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); 94 | } 95 | 96 | internal static string PathNormalize(string path) 97 | { 98 | path = (path ?? "").Trim(); 99 | if (path.EndsWith(Path.DirectorySeparatorChar.ToString())) 100 | return path.TrimEnd(Path.DirectorySeparatorChar); 101 | return path; 102 | } 103 | 104 | private static bool PathStartsWithOrEquals(string path, string pattern) 105 | { 106 | path = PathNormalize(path) + Path.DirectorySeparatorChar; 107 | pattern = PathNormalize(pattern) + Path.DirectorySeparatorChar; 108 | return path.StartsWith(pattern, StringComparison.OrdinalIgnoreCase) 109 | || path.Equals(pattern, StringComparison.OrdinalIgnoreCase); 110 | } 111 | 112 | private static string PathAbstractAlias(string path, string pattern, string alias) 113 | { 114 | if (!PathStartsWithOrEquals(path, pattern)) 115 | return path; 116 | path = PathNormalize(path) + Path.DirectorySeparatorChar; 117 | pattern = PathNormalize(pattern) + Path.DirectorySeparatorChar; 118 | if (path.Equals(pattern, StringComparison.OrdinalIgnoreCase)) 119 | return alias; 120 | return PathNormalize(Path.Combine(alias, path.Substring(pattern.Length))); 121 | } 122 | 123 | internal static string PathAbstract(string path) 124 | { 125 | if (PathStartsWithOrEquals(path, USER_PROFILE_PATH)) 126 | return PathAbstractAlias(path, USER_PROFILE_PATH, "%UserProfile%"); 127 | if (PathStartsWithOrEquals(path, SYSTEM_PROGRAM_FILES_PATH)) 128 | return PathAbstractAlias(path, SYSTEM_PROGRAM_FILES_PATH, "%ProgramFiles%"); 129 | if (PathStartsWithOrEquals(path, SYSTEM_PROGRAM_FILES_X86_PATH)) 130 | return PathAbstractAlias(path, SYSTEM_PROGRAM_FILES_X86_PATH, "%ProgramFiles(x86)%"); 131 | if (PathStartsWithOrEquals(path, SYSTEM_PROGRAM_DATA_PATH)) 132 | return PathAbstractAlias(path, SYSTEM_PROGRAM_DATA_PATH, "%ProgramData%"); 133 | if (PathStartsWithOrEquals(path, SYSTEM_ROOT_PATH)) 134 | return PathAbstractAlias(path, SYSTEM_ROOT_PATH, "%SystemRoot%"); 135 | path = Regex.Replace(path, @"^([A-Za-z]):", match => 136 | $"%%{match.Groups[1].Value.ToUpper()}%"); 137 | return path; 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /inventory/Sources/Program.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/inventory/Sources/Program.ico -------------------------------------------------------------------------------- /launcher/.gitignore: -------------------------------------------------------------------------------- 1 | # Use the parent .gitignore 2 | -------------------------------------------------------------------------------- /launcher/Build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Following targets are available: 5 | 6 | changes Synchronizes README.md with CHANGES 7 | 8 | release Builds the complete release 9 | Synchronizes the version in README.md 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 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 | 109 | 110 | 111 | 112 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 127 | 128 | 129 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 159 | 160 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /launcher/CHANGES: -------------------------------------------------------------------------------- 1 | 1.2.0 20250701 2 | BF: Launcher: Correction when using custom scaling 3 | Correction of the possibly incorrect calculation of 4 | FormWindowState.Maximized for custom scaling. 5 | CR: Platform: Optimization and corrections 6 | - Omission of the steps recorder (deprecated by Microsoft) 7 | - Simplification of the terminal action 8 | CR: Launcher: Optimization and corrections 9 | - Shutdown and session ending 10 | - Internal communication via message bus 11 | - Build uses AssemblyInfo.cs for version and build number 12 | - Adjustment to updated platform environment variables 13 | CR: Launcher: Added additional environment variables for the tile action 14 | For details, see the documentation/comments in the Settings.xml 15 | settings -> tiles -> tile -> environment 16 | 17 | 1.1.2 20240302 18 | CR: Project: Updated TargetFrameworkVersion to v4.8 19 | CR: Platform: Refactoring of the standard directory structure 20 | 21 | 1.1.1 20230710 22 | BF: Launcher: Correction/optimization of the output if the HotKey cannot be registered 23 | CR: Build: Releases are now only available on the release page 24 | 25 | 1.1.0 20220625 26 | BF: Build: Correction of the release info process 27 | BF: Launcher: Correction of the behavior when the screen resolution changes 28 | Triggers the update of the user interface. 29 | CR: Launcher: Scaling of icons depending on screen resolution (aesthetic reasons) 30 | CR: Launcher: Increase from the default value of OPACITY (95) 31 | CR: Launcher: Added option AutoScale (default true) 32 | Scales the view according to the screen resolution ot the primary screen 33 | 34 | 1.0.1 20220401 35 | BF: Build: Correction of the version number 36 | Release date was not set correctly. 37 | BF: Build: Optimization of the release info process 38 | BF: Build: Optimization of the build process 39 | 40 | 1.0.0 20220325 41 | NT: Release is available 42 | -------------------------------------------------------------------------------- /launcher/Launcher.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6A26CE5A-C11C-4B6D-844A-24DF30C932F7} 8 | WinExe 9 | VirtualEnvironment.Launcher 10 | Launcher 11 | v4.8 12 | 512 13 | true 14 | true 15 | Properties\App.manifest 16 | Sources\Program.ico 17 | 18 | 19 | AnyCPU 20 | true 21 | full 22 | false 23 | Target\bin\Debug\ 24 | Target\obj\Debug\ 25 | Target\obj\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | 30 | 31 | AnyCPU 32 | pdbonly 33 | true 34 | Target\bin\Release\ 35 | Target\obj\Release\ 36 | Target\obj\Release\ 37 | prompt 38 | 4 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 | Form 66 | 67 | 68 | Control.cs 69 | 70 | 71 | Control.cs 72 | 73 | 74 | 75 | 76 | {50A7E9B0-70EF-11D1-B75A-00A0C90564FE} 77 | 1 78 | 0 79 | 0 80 | tlbimp 81 | False 82 | True 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /launcher/Launcher.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher", "Launcher.csproj", "{6A26CE5A-C11C-4B6D-844A-24DF30C932F7}" 3 | EndProject 4 | Global 5 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 6 | Debug|Any CPU = Debug|Any CPU 7 | Release|Any CPU = Release|Any CPU 8 | EndGlobalSection 9 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 10 | {6A26CE5A-C11C-4B6D-844A-24DF30C932F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 11 | {6A26CE5A-C11C-4B6D-844A-24DF30C932F7}.Debug|Any CPU.Build.0 = Debug|Any CPU 12 | {6A26CE5A-C11C-4B6D-844A-24DF30C932F7}.Release|Any CPU.ActiveCfg = Release|Any CPU 13 | {6A26CE5A-C11C-4B6D-844A-24DF30C932F7}.Release|Any CPU.Build.0 = Release|Any CPU 14 | EndGlobalSection 15 | EndGlobal 16 | -------------------------------------------------------------------------------- /launcher/Properties/App.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | true/PM 7 | 8 | 9 | -------------------------------------------------------------------------------- /launcher/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Launcher for Seanox Virtual Environment")] 8 | [assembly: AssemblyDescription("Full screen tile menu for launching programs.")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Seanox Software Solutions")] 11 | [assembly: AssemblyProduct("Launcher")] 12 | [assembly: AssemblyCopyright("Copyright © 0000 Seanox Software Solutions")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("6A26CE5A-C11C-4B6D-844A-24DF30C932F7")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("0.0.0")] 35 | [assembly: AssemblyFileVersion("0.0.0")] 36 | [assembly: AssemblyMetadata("Build", "00000000")] 37 | -------------------------------------------------------------------------------- /launcher/README.md: -------------------------------------------------------------------------------- 1 | # Launcher 2 | A portable program launcher specially developed for the Seanox Virtual 3 | Environment with a full-screen tile-based interface that can also be used 4 | standalone and independently. 5 | 6 | 7 | 8 | Focus is on fast keyboard usage -- open a program with three keys. 9 | Through the global hotkey even when the launcher is not visible. 10 | 11 | # Features 12 | - Full screen overlay user interface 13 | The full screen overlay is displayed on the primary screen. 14 | - User interface in tile optics 15 | There are 40 freely configurable tiles available. 16 | - Global HotKey combination 17 | A global HotKey combination is used to show and hide the user interface. 18 | - HotKey for tiles and programs 19 | Quick access via the keyboard, optimized for the used keyboard layout. 20 | Support for international keyboard layouts. 21 | - Automatic settings update 22 | Changes in the settings are used immediately. 23 | - Settings supports environment variables 24 | Environment variables can be used in text-based values. 25 | - Visual style per settings (themes support) 26 | The user interface supports the configuration of colors, opacity, background 27 | color and image, and the appearance of the grid. 28 | - No icons or functions appear in the taskbar or system tray 29 | The program is optimized for the virtual environment to ensure that the shell 30 | remains accessible. The program runs continuously in the background and cannot 31 | be terminated directly. However, quitting can be configured via a tile. 32 | - Portable application without installation 33 | 34 | # System Requirement 35 | - Microsoft Windows 10 or higher 36 | - Microsoft .NET 4.8.x or higher (for runtime) 37 | - [Microsoft .NET 4.8.x Developer Pack or higher]( 38 | https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48) (for development only) 39 | 40 | # Download 41 | The launcher is [part of the virtual environment]( 42 | https://github.com/seanox/virtual-environment/tree/main/platform/Program%20Portables/Launcher) 43 | but can also be downloaded and used separately. 44 | 45 | https://github.com/seanox/virtual-environment/releases 46 | 47 | # Settings 48 | For configuration the file `launcher.xml` (depending on the application name) 49 | in the working directory is used. If this file does not exist or is incorrect, 50 | the launcher aborts the start with an error message. 51 | 52 | Example of a configuration file: 53 | 54 | ```xml 55 | 56 | 57 | 62 | 63 | 64 | 1 + 27 65 | 66 | 67 | 99 68 | 69 | 25 70 | 71 | 10 72 | 73 | 4 74 | 75 | 76 | 95 77 | 78 | 83 | 84 | 85 | 86 | #000000 87 | 88 | #C8C8C8 89 | 90 | #313131 91 | 92 | #FAB400 93 | 94 | 95 | 9.75 96 | 97 | 98 | 99 | 100 | 40 101 | 102 | Detach 103 | 107 | %WINDIR%\system32\shell32.dll:27 108 | 109 | %PLATFORM_APP% 110 | 111 | %HOMEDRIVE% detach 112 | 113 | %PLATFORM_HOME% 114 | 115 | ... 116 | 117 | 118 | ``` 119 | 120 | # Changes 121 | ## 1.1.2 20240302 122 | CR: Project: Updated TargetFrameworkVersion to v4.8 123 | CR: Platform: Refactoring of the standard directory structure 124 | 125 | [Read more](https://raw.githubusercontent.com/seanox/virtual-environment/master/launcher/CHANGES) 126 | -------------------------------------------------------------------------------- /launcher/Resources/animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/launcher/Resources/animation.gif -------------------------------------------------------------------------------- /launcher/Sources/Control.Designer.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Windows.Forms; 3 | 4 | namespace VirtualEnvironment.Launcher 5 | { 6 | partial class Control 7 | { 8 | /// 9 | /// Required designer variable. 10 | /// 11 | private IContainer components = null; 12 | 13 | /// 14 | /// Clean up any resources being used. 15 | /// 16 | /// true if managed resources should be disposed; otherwise, false. 17 | protected override void Dispose(bool disposing) 18 | { 19 | if (disposing && (components != null)) 20 | { 21 | components.Dispose(); 22 | } 23 | 24 | base.Dispose(disposing); 25 | } 26 | 27 | #region Windows Form Designer generated code 28 | 29 | /// 30 | /// Required method for Designer support - do not modify 31 | /// the contents of this method with the code editor. 32 | /// 33 | private void InitializeComponent() 34 | { 35 | this.Message = new System.Windows.Forms.Label(); 36 | this.SuspendLayout(); 37 | // 38 | // Message 39 | // 40 | this.Message.BackColor = System.Drawing.Color.Transparent; 41 | this.Message.Location = new System.Drawing.Point(0, 0); 42 | this.Message.Name = "Message"; 43 | this.Message.TabIndex = 0; 44 | this.Message.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 45 | this.Message.Dock = DockStyle.Fill; 46 | this.Message.AutoSize = false; 47 | // 48 | // Control 49 | // 50 | this.AutoScaleDimensions = new System.Drawing.SizeF(0F, 0F); 51 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 52 | this.ControlBox = false; 53 | this.TopMost = true; 54 | this.Controls.Add(this.Message); 55 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; 56 | this.Name = "Control"; 57 | this.Opacity = 0.95D; 58 | this.ShowInTaskbar = false; 59 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 60 | this.WindowState = System.Windows.Forms.FormWindowState.Minimized; 61 | this.ResumeLayout(false); 62 | } 63 | 64 | private System.Windows.Forms.Label Message; 65 | 66 | #endregion 67 | } 68 | } -------------------------------------------------------------------------------- /launcher/Sources/Control.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 | -------------------------------------------------------------------------------- /launcher/Sources/Messages.cs: -------------------------------------------------------------------------------- 1 | // LICENSE TERMS - Seanox Software Solutions is an open source project, 2 | // hereinafter referred to as Seanox Software Solutions or Seanox for short. 3 | // This software is subject to version 2 of the Apache License. 4 | // 5 | // Virtual Environment Launcher 6 | // Program starter for the virtual environment. 7 | // Copyright (C) 2025 Seanox Software Solutions 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 10 | // use this file except in compliance with the License. You may obtain a copy of 11 | // the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | // License for the specific language governing permissions and limitations under 19 | // the License. 20 | 21 | using System; 22 | using System.Collections.Generic; 23 | using System.Linq; 24 | using System.Text; 25 | using System.Text.RegularExpressions; 26 | using System.Threading.Tasks; 27 | 28 | namespace VirtualEnvironment.Launcher 29 | { 30 | internal static class Messages 31 | { 32 | private static readonly HashSet _subscriptions; 33 | 34 | private static readonly object _lock; 35 | 36 | static Messages() 37 | { 38 | _subscriptions = new HashSet(); 39 | _lock = new object(); 40 | } 41 | 42 | internal static void Subscribe(ISubscriber recipient) 43 | { 44 | if (recipient is null) 45 | throw new ArgumentNullException(); 46 | lock (_lock) 47 | _subscriptions.Add(recipient); 48 | } 49 | 50 | internal static void Unsubscribe(ISubscriber recipient) 51 | { 52 | if (recipient is null) 53 | throw new ArgumentNullException(); 54 | lock (_lock) 55 | _subscriptions.Remove(recipient); 56 | } 57 | 58 | internal interface ISubscriber 59 | { 60 | void Receive(Message message); 61 | } 62 | 63 | internal static void Push(params Message[] messages) 64 | { 65 | List recipients; 66 | lock (_lock) 67 | recipients = _subscriptions.ToList(); 68 | 69 | Parallel.ForEach(messages, message => 70 | Parallel.ForEach(recipients, recipient => 71 | { 72 | try { recipient.Receive(message); } catch { } 73 | })); 74 | } 75 | 76 | internal static void Push(Type type, params string[] data) 77 | { 78 | Push(new Message(type, data)); 79 | } 80 | 81 | internal static void Push(Type type, string context, params string[] data) 82 | { 83 | Push(new Message(type, context, data)); 84 | } 85 | 86 | internal static void Push(Type type, object data) 87 | { 88 | Push(new Message(type, data)); 89 | } 90 | 91 | internal static void Push(Type type, string context, object data) 92 | { 93 | Push(new Message(type, context, data)); 94 | } 95 | 96 | internal enum Type 97 | { 98 | Error, 99 | Warning, 100 | Trace, 101 | Verbose, 102 | Data, 103 | Exit 104 | } 105 | 106 | internal readonly struct Message 107 | { 108 | internal Type Type { get; } 109 | internal string Context { get; } 110 | internal object Data { get; } 111 | 112 | internal Message(Type type, object data) 113 | : this(type, null, data) 114 | { 115 | } 116 | 117 | internal Message(Type type, string context, object data) 118 | { 119 | Type = type; 120 | if (!String.IsNullOrWhiteSpace(context)) 121 | context = Regex.Replace(context, @"[\r\n]+", " ").Trim(); 122 | Context = !String.IsNullOrWhiteSpace(context) ? context : null; 123 | if (data is IEnumerable lines) 124 | data = String.Join(System.Environment.NewLine, lines); 125 | Data = data; 126 | } 127 | 128 | internal Message ConvertTo(Type type) 129 | { 130 | return new Message(type, Context, Data); 131 | } 132 | 133 | public override string ToString() 134 | { 135 | var stringBuilder = new StringBuilder(Type.ToString().ToUpper()) 136 | .Append(" "); 137 | 138 | var content = Data; 139 | 140 | if (!String.IsNullOrWhiteSpace(Context)) 141 | stringBuilder.AppendLine(Context); 142 | 143 | if (Data is Exception exception) 144 | { 145 | stringBuilder.Append(exception.GetType().Name); 146 | if (!String.IsNullOrWhiteSpace(exception.Message)) 147 | stringBuilder.Append($": {exception.Message.Trim()}"); 148 | stringBuilder.AppendLine(); 149 | if (!(exception.StackTrace is null)) 150 | content = exception.StackTrace 151 | .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) 152 | .Select(line => Convert.ToString(line).Trim()); 153 | else content = null; 154 | } 155 | 156 | if (!(content is IEnumerable) 157 | && content is IEnumerable objects) 158 | content = objects 159 | .Where(line => !(line is null)) 160 | .Select(line => Convert.ToString(line).Trim()) 161 | .Where(line => !String.IsNullOrWhiteSpace(line)); 162 | 163 | if (content is IEnumerable strings) 164 | content = String.Join(Environment.NewLine, 165 | strings.Where(line => !String.IsNullOrWhiteSpace(line))); 166 | 167 | content = Convert.ToString(content).Trim(); 168 | if (!String.IsNullOrEmpty((string)content)) 169 | stringBuilder.Append(content); 170 | 171 | return stringBuilder.ToString().Trim(); 172 | } 173 | } 174 | } 175 | } -------------------------------------------------------------------------------- /launcher/Sources/Program.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/launcher/Sources/Program.ico -------------------------------------------------------------------------------- /launcher/Sources/Settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 25 | 8 + 27 26 | 27 | 28 | 101 29 | 30 | 25 31 | 32 | 10 33 | 34 | 4 35 | 36 | 37 | true 38 | 39 | 45 | 95 46 | 47 | 52 | 53 | 54 | 73 | 74 | 75 | 81 | 82 | 87 | 9.5 88 | 89 | 90 | 91 | 92 | 17 93 | 94 | hosts 95 | 99 | %WINDIR%\system32\inetcpl.cpl:26 100 | 101 | %WINDIR%\system32\notepad.exe 102 | 103 | %WINDIR%\System32\drivers\etc\hosts 104 | 105 | %WINDIR%\System32\drivers\etc 106 | 110 | 122 | 123 | 124 | 27 125 | Services 126 | %WINDIR%\system32\services.msc 127 | %HOMEDRIVE%%HOMEPATH% 128 | 129 | 130 | 28 131 | Settings 132 | %WINDIR%\system32\inetcpl.cpl:46 133 | %WINDIR%\system32\notepad.exe 134 | launcher.xml 135 | 136 | 137 | 31 138 | Terminal 139 | %ComSpec% 140 | %HOMEDRIVE%\ 141 | 142 | 143 | 39 144 | Documents 145 | %WINDIR%\system32\shell32.dll:126 146 | %WINDIR%\explorer.exe 147 | %HOMEDRIVE%%HOMEPATH% 148 | 149 | 150 | 40 151 | Exit 152 | %WINDIR%\system32\shell32.dll:27 153 | EXIT 154 | %PLATFORM_HOME% 155 | 156 | 157 | -------------------------------------------------------------------------------- /launcher/Sources/Tiles/MetaTile.cs: -------------------------------------------------------------------------------- 1 | // LICENSE TERMS - Seanox Software Solutions is an open source project, 2 | // hereinafter referred to as Seanox Software Solutions or Seanox for short. 3 | // This software is subject to version 2 of the Apache License. 4 | // 5 | // Virtual Environment Launcher 6 | // Program starter for the virtual environment. 7 | // Copyright (C) 2025 Seanox Software Solutions 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 10 | // use this file except in compliance with the License. You may obtain a copy of 11 | // the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | // License for the specific language governing permissions and limitations under 19 | // the License. 20 | 21 | using System; 22 | using System.Drawing; 23 | using System.IO; 24 | using System.Windows.Forms; 25 | 26 | namespace VirtualEnvironment.Launcher.Tiles 27 | { 28 | internal class MetaTile : IDisposable 29 | { 30 | internal readonly Settings.Tile Settings; 31 | 32 | internal readonly int Index; 33 | internal readonly int ScanCode; 34 | internal readonly string Symbol; 35 | internal readonly Rectangle Location; 36 | 37 | private readonly MetaTileGrid _metaTileGrid; 38 | 39 | private readonly Color _borderColor; 40 | private readonly Color _foregroundColor; 41 | private readonly Color _highlightColor; 42 | private readonly Font _textFont; 43 | private readonly Size _textMeasure; 44 | private readonly int _iconSpace; 45 | 46 | private Image _iconImage; 47 | private long _iconImageLastModified; 48 | 49 | private MetaTile(Screen screen, Settings settings, Settings.Tile tile) 50 | { 51 | Settings = tile; 52 | 53 | _metaTileGrid = MetaTileGrid.Create(settings); 54 | 55 | // The index for the configuration starts user-friendly with 1, 56 | // but internally it is technically started with 0. Therefore 57 | // the index in the configuration is different! 58 | Index = tile.Index - 1; 59 | 60 | // The following scan codes are used: 61 | // 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 62 | // 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 63 | // 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 64 | // 0x2C 0x2D 0x2E 0x2F 0x30 0x31 0x32 0x33 0x34 0x35 65 | // The ranges are 14 points apart. 66 | 67 | // A1: 0 68 | // B1: =(ROUNDDOWN(A1/10;0)*14) 69 | // C1: =B1/14 70 | // D1: =10*C1 71 | // E1: =A1-D1 72 | // F1: =E1+B1+2 73 | var radix = ((int)Math.Floor(Index / 10d)) * 14; 74 | ScanCode = radix + (Index - (10 * (radix / 14))) + 2; 75 | Symbol = Utilities.ScanCode.ToString(ScanCode); 76 | 77 | var screenRectangle = screen.Bounds; 78 | var tileMapLocation = new Point((screenRectangle.Width / 2) - (_metaTileGrid.Width / 2), 79 | (screenRectangle.Height / 2) - (_metaTileGrid.Height / 2)); 80 | 81 | var tileRasterColumn = Index % _metaTileGrid.Columns; 82 | var tileRasterRow = (int)Math.Floor((float)Index / _metaTileGrid.Columns); 83 | var tileStartX = tileRasterColumn * (_metaTileGrid.Size + _metaTileGrid.Gap); 84 | var tileStartY = tileRasterRow * (_metaTileGrid.Size + _metaTileGrid.Gap); 85 | Location = new Rectangle(tileStartX +tileMapLocation.X, tileStartY +tileMapLocation.Y, _metaTileGrid.Size, _metaTileGrid.Size); 86 | 87 | _borderColor = ColorTranslator.FromHtml(settings.BorderColor); 88 | _foregroundColor = ColorTranslator.FromHtml(settings.ForegroundColor); 89 | _highlightColor = ColorTranslator.FromHtml(settings.HighlightColor); 90 | 91 | _textFont = new Font(SystemFonts.DefaultFont.FontFamily, _metaTileGrid.FontSize, FontStyle.Regular); 92 | _textMeasure = TextRenderer.MeasureText($"{Environment.NewLine}", _textFont); 93 | _iconSpace = _metaTileGrid.Size - _textMeasure.Height; 94 | _iconImage = GetIconImage(_iconSpace -(3 * _metaTileGrid.Padding), Settings.IconFile, Settings.IconIndex); 95 | 96 | _iconImageLastModified = -1; 97 | if (File.Exists(Settings.IconFile)) 98 | _iconImageLastModified = File.GetLastWriteTime(Settings.IconFile).Ticks; 99 | } 100 | 101 | private static Image GetIconImage(int iconSize, string iconFile, int iconIndex) 102 | { 103 | var iconImage = Utilities.Graphics.ImageOf(iconFile, iconIndex); 104 | if (iconImage == null 105 | || iconSize < 16) 106 | return null; 107 | 108 | // For aesthetic reasons, the scaling of the icons depends on the 109 | // screen resolution. As a reference, WXGA HD (1366 x 768) is used 110 | // as the smallest usable resolution in IT. With increasing 111 | // resolution (total number of pixels) max. 25% scaling of the icon 112 | // size is calculated in relation to the screen resolution. 113 | 114 | var screenBounds = Screen.PrimaryScreen.Bounds; 115 | var scaleFactorMax = (float)screenBounds.Width * screenBounds.Height; 116 | scaleFactorMax = Math.Max(scaleFactorMax / (1366 * 768), 1); 117 | scaleFactorMax = (scaleFactorMax / 4) +1; 118 | 119 | var scaleFactor = Math.Max((float)iconSize / Math.Min(iconImage.Height, iconImage.Width), 1f); 120 | scaleFactor = Math.Min(Math.Max(scaleFactor, 1), scaleFactorMax); 121 | 122 | using (iconImage) 123 | return Utilities.Graphics.ImageResize(iconImage, (int)(iconImage.Width * scaleFactor), 124 | (int)(iconImage.Height * scaleFactor)); 125 | } 126 | 127 | internal static MetaTile Create(Screen screen, Settings settings, Settings.Tile tile) 128 | { 129 | return new MetaTile(screen, settings, tile); 130 | } 131 | 132 | internal void Draw(Graphics graphics) 133 | { 134 | using (var rectanglePen = new Pen(new SolidBrush(_borderColor))) 135 | Utilities.Graphics.DrawRectangleRounded(graphics, rectanglePen, 136 | new Rectangle(Location.X, Location.Y, _metaTileGrid.Size - 1, _metaTileGrid.Size - 1), _metaTileGrid.Radius); 137 | 138 | try 139 | { 140 | var iconImageLastModified = File.Exists(Settings.IconFile) ? File.GetLastWriteTime(Settings.IconFile).Ticks : -1; 141 | if (iconImageLastModified != _iconImageLastModified) 142 | _iconImage = GetIconImage(_iconSpace -(2 * _metaTileGrid.Padding), Settings.IconFile, Settings.IconIndex); 143 | _iconImageLastModified = iconImageLastModified; 144 | } 145 | catch (Exception) 146 | { 147 | } 148 | 149 | if (_iconImage != null) 150 | graphics.DrawImage(_iconImage, Location.X + (_metaTileGrid.Size /2) -(_iconImage.Width /2), 151 | Location.Y + Math.Max((_iconSpace /2) -(_iconImage.Height /2), _metaTileGrid.Padding)); 152 | 153 | var stringFormat = new StringFormat(); 154 | stringFormat.Alignment = StringAlignment.Center; 155 | stringFormat.LineAlignment = StringAlignment.Center; 156 | 157 | var titleRectangle = new Rectangle(Location.X + _metaTileGrid.Padding, Location.Y + _metaTileGrid.Size -_metaTileGrid.Padding -_textMeasure.Height, 158 | _metaTileGrid.Size - (2 * _metaTileGrid.Padding), _textMeasure.Height); 159 | using (var foregroundColorBrush = new SolidBrush(_foregroundColor)) 160 | graphics.DrawString(Settings.Title, _textFont, foregroundColorBrush, titleRectangle, stringFormat); 161 | 162 | using (var highlightColorBrush = new SolidBrush(_highlightColor)) 163 | graphics.DrawString(Symbol.ToUpper(), _textFont, highlightColorBrush, 164 | new Point(Location.X + (_metaTileGrid.Padding /2), Location.Y + (_metaTileGrid.Padding /2))); 165 | } 166 | 167 | public void Dispose() 168 | { 169 | _textFont?.Dispose(); 170 | _iconImage?.Dispose(); 171 | } 172 | } 173 | } -------------------------------------------------------------------------------- /launcher/Sources/Tiles/MetaTileGrid.cs: -------------------------------------------------------------------------------- 1 | // LICENSE TERMS - Seanox Software Solutions is an open source project, 2 | // hereinafter referred to as Seanox Software Solutions or Seanox for short. 3 | // This software is subject to version 2 of the Apache License. 4 | // 5 | // Virtual Environment Launcher 6 | // Program starter for the virtual environment. 7 | // Copyright (C) 2025 Seanox Software Solutions 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 10 | // use this file except in compliance with the License. You may obtain a copy of 11 | // the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | // License for the specific language governing permissions and limitations under 19 | // the License. 20 | 21 | using System; 22 | using System.Windows.Forms; 23 | 24 | namespace VirtualEnvironment.Launcher.Tiles 25 | { 26 | internal class MetaTileGrid 27 | { 28 | internal readonly int Columns = 10; 29 | internal readonly int Rows = 4; 30 | 31 | internal readonly int Size; 32 | internal readonly int Gap; 33 | internal readonly int Padding; 34 | internal readonly int Radius; 35 | 36 | internal readonly float FontSize; 37 | 38 | internal int Count => Columns * Rows; 39 | internal int Height => ((Size + Gap) * Rows) - Gap; 40 | internal int Width => ((Size + Gap) * Columns) - Gap; 41 | 42 | private MetaTileGrid(Settings settings) 43 | { 44 | var scaleFactor = 1f; 45 | if (settings.AutoScale) 46 | { 47 | var scaleMinOffset = settings.GridGap * 6; 48 | var scaleMinHeight = ((settings.GridSize + settings.GridGap) * Rows) - Gap; 49 | var scaleMinWidth = ((settings.GridSize + settings.GridGap) * Columns) - Gap; 50 | 51 | var scaleMaxOffset = (settings.GridSize + settings.GridGap) * 2; 52 | var scaleMaxHeight = scaleMinHeight + scaleMaxOffset; 53 | var scaleMaxWidth = scaleMinWidth + scaleMaxOffset; 54 | 55 | var screenBounds = Screen.PrimaryScreen.Bounds; 56 | if (screenBounds.Height >= scaleMaxHeight 57 | && screenBounds.Width >= scaleMaxWidth) 58 | { 59 | var scaleFactorHeight = (float)screenBounds.Height / scaleMaxHeight; 60 | var scaleFactorWidth = (float)screenBounds.Width / scaleMaxWidth; 61 | scaleFactor = Math.Min(scaleFactorHeight, scaleFactorWidth); 62 | } 63 | else 64 | { 65 | var scaleFactorHeight = (float)screenBounds.Height / (scaleMinHeight + scaleMinOffset); 66 | var scaleFactorWidth = (float)screenBounds.Width / (scaleMinWidth + scaleMinOffset); 67 | scaleFactor = Math.Min(scaleFactorHeight, scaleFactorWidth); 68 | } 69 | } 70 | 71 | Func ScaleNumber = (number) => 72 | { 73 | var scaleNumberValue = Math.Floor(number * scaleFactor); 74 | if (number % 2 == 0 75 | && scaleNumberValue % 2 != 0) 76 | return scaleNumberValue + 1; 77 | if (number % 2 != 0 78 | && scaleNumberValue % 2 == 0) 79 | return scaleNumberValue + 1; 80 | return scaleNumberValue; 81 | }; 82 | 83 | Size = (int)ScaleNumber(settings.GridSize); 84 | Gap = (int)ScaleNumber(settings.GridGap); 85 | Padding = (int)ScaleNumber(settings.GridPadding); 86 | 87 | Radius = Math.Min(Math.Max(settings.GridCornerRadius, 0), Size /2); 88 | 89 | FontSize = settings.FontSize * scaleFactor; 90 | } 91 | 92 | internal static MetaTileGrid Create(Settings settings) 93 | { 94 | return new MetaTileGrid(settings); 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /launcher/Sources/Tiles/MetaTileScreen.cs: -------------------------------------------------------------------------------- 1 | // LICENSE TERMS - Seanox Software Solutions is an open source project, 2 | // hereinafter referred to as Seanox Software Solutions or Seanox for short. 3 | // This software is subject to version 2 of the Apache License. 4 | // 5 | // Virtual Environment Launcher 6 | // Program starter for the virtual environment. 7 | // Copyright (C) 2025 Seanox Software Solutions 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 10 | // use this file except in compliance with the License. You may obtain a copy of 11 | // the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | // License for the specific language governing permissions and limitations under 19 | // the License. 20 | 21 | using System; 22 | using System.Drawing; 23 | using System.Drawing.Imaging; 24 | using System.Windows.Forms; 25 | 26 | namespace VirtualEnvironment.Launcher.Tiles 27 | { 28 | internal class MetaTileScreen : IDisposable 29 | { 30 | private readonly MetaTile[] _metaTiles; 31 | private readonly Screen _screen; 32 | 33 | private readonly Image _activeBorderImage; 34 | private readonly Image _passiveBorderImage; 35 | private readonly Image _backgroundImage; 36 | 37 | private MetaTile _selection; 38 | 39 | private MetaTileScreen(Screen screen, Settings settings, params MetaTile[] metaTiles) 40 | { 41 | _metaTiles = metaTiles; 42 | _screen = screen; 43 | 44 | var metaTileGrid = MetaTileGrid.Create(settings); 45 | var borderColor = ColorTranslator.FromHtml(settings.BorderColor); 46 | var highlightColor = ColorTranslator.FromHtml(settings.HighlightColor); 47 | 48 | _passiveBorderImage = new Bitmap(metaTileGrid.Size, metaTileGrid.Size, PixelFormat.Format32bppPArgb); 49 | using (var passiveBorderImageGraphics = Graphics.FromImage(_passiveBorderImage)) 50 | Utilities.Graphics.DrawRectangleRounded(passiveBorderImageGraphics, new Pen(new SolidBrush(borderColor)), 51 | new Rectangle(0, 0, metaTileGrid.Size - 1, metaTileGrid.Size - 1), metaTileGrid.Radius); 52 | 53 | _activeBorderImage = new Bitmap(metaTileGrid.Size, metaTileGrid.Size, PixelFormat.Format32bppPArgb); 54 | using (var activeBorderImageGraphics = Graphics.FromImage(_activeBorderImage)) 55 | Utilities.Graphics.DrawRectangleRounded(activeBorderImageGraphics, new Pen(new SolidBrush(highlightColor)), 56 | new Rectangle(0, 0, metaTileGrid.Size - 1, metaTileGrid.Size - 1), metaTileGrid.Radius); 57 | 58 | if (!String.IsNullOrWhiteSpace(settings.BackgroundImage)) 59 | using (var backgroundImage = Utilities.Graphics.ImageOf(settings.BackgroundImage)) 60 | if (backgroundImage != null) 61 | _backgroundImage = Utilities.Graphics.ImageScale(backgroundImage, _screen.Bounds.Width, _screen.Bounds.Height); 62 | } 63 | 64 | internal static MetaTileScreen Create(Screen screen, Settings settings, params MetaTile[] metaTiles) 65 | { 66 | return new MetaTileScreen(screen, settings, metaTiles); 67 | } 68 | 69 | internal MetaTile Locate(string symbol) 70 | { 71 | return Array.Find(_metaTiles, 72 | metaTile => "" + metaTile.Symbol == symbol); 73 | } 74 | 75 | internal MetaTile Locate(Point point) 76 | { 77 | return Array.Find(_metaTiles, metaTile => 78 | point.X >= metaTile.Location.Left 79 | && point.X <= metaTile.Location.Right 80 | && point.Y >= metaTile.Location.Top 81 | && point.Y <= metaTile.Location.Bottom); 82 | } 83 | 84 | internal void Select(Graphics graphics, MetaTile metaTile, bool force = false) 85 | { 86 | if ((metaTile == _selection && !force) 87 | || metaTile == null) 88 | return; 89 | if (_selection != null) 90 | graphics.DrawImage(_passiveBorderImage, new Point(_selection.Location.X, _selection.Location.Y)); 91 | _selection = metaTile; 92 | graphics.DrawImage(_activeBorderImage, new Point(_selection.Location.X, _selection.Location.Y)); 93 | } 94 | 95 | private static Rectangle ImageCenter(Rectangle rectangle, Image image) 96 | { 97 | return new Rectangle((rectangle.Width - image.Width) / 2, 98 | (rectangle.Height - image.Height) / 2, image.Width, image.Height); 99 | } 100 | 101 | internal void Draw(Graphics graphics) 102 | { 103 | if (_backgroundImage != null) 104 | graphics.DrawImage(_backgroundImage, ImageCenter(_screen.Bounds, _backgroundImage)); 105 | foreach (var metaTile in _metaTiles) 106 | metaTile.Draw(graphics); 107 | Select(graphics, _selection, true); 108 | } 109 | 110 | public void Dispose() 111 | { 112 | _activeBorderImage?.Dispose(); 113 | _passiveBorderImage?.Dispose(); 114 | _backgroundImage?.Dispose(); 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /launcher/Sources/Utilities/ScanCode.cs: -------------------------------------------------------------------------------- 1 | // LICENSE TERMS - Seanox Software Solutions is an open source project, 2 | // hereinafter referred to as Seanox Software Solutions or Seanox for short. 3 | // This software is subject to version 2 of the Apache License. 4 | // 5 | // Virtual Environment Launcher 6 | // Program starter for the virtual environment. 7 | // Copyright (C) 2025 Seanox Software Solutions 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 10 | // use this file except in compliance with the License. You may obtain a copy of 11 | // the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | // License for the specific language governing permissions and limitations under 19 | // the License. 20 | 21 | using System; 22 | using System.Runtime.InteropServices; 23 | using System.Text; 24 | 25 | namespace VirtualEnvironment.Launcher.Utilities 26 | { 27 | internal static class ScanCode 28 | { 29 | [DllImport("user32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] 30 | private static extern int ToUnicodeEx(uint wVirtKey, uint wScanCode, byte[] lpKeyState, 31 | StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl); 32 | 33 | [DllImport("user32.dll", ExactSpelling = true)] 34 | private static extern IntPtr GetKeyboardLayout(uint threadId); 35 | 36 | private enum MapType : uint 37 | { 38 | MapvkVkToVsc = 0x0, 39 | MapvkVscToVk = 0x1, 40 | MapvkVkToChar = 0x2, 41 | MapvkVscToVkEx = 0x3, 42 | } 43 | 44 | [DllImport("user32.dll")] 45 | private static extern uint MapVirtualKey(uint uCode, MapType uMapType); 46 | 47 | internal static string ToString(int scanCode) 48 | { 49 | var stringBuilder = new StringBuilder(10); 50 | var virtualKey = MapVirtualKey((uint)scanCode, MapType.MapvkVscToVk); 51 | ToUnicodeEx(virtualKey, (uint)scanCode, new byte[256], stringBuilder, stringBuilder.Capacity, 0, 52 | GetKeyboardLayout(0)); 53 | return stringBuilder.ToString().Trim(); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /platform/.gitignore: -------------------------------------------------------------------------------- 1 | # Use the parent .gitignore 2 | -------------------------------------------------------------------------------- /platform/CHANGES: -------------------------------------------------------------------------------- 1 | 3.6.0 20250701 2 | BF: Review: Optimization and corrections 3 | - Message Bus (Publisher + Subscriber) 4 | - Resource for text output 5 | - Logging improved output structure 6 | - Settings uses the Windows API to read the INI file 7 | - Build uses AssemblyInfo.cs for version and build number 8 | - Build uses conditional PropertyGroup 9 | BF: Settings: Correction to ignore invalid paths in section [FILES] 10 | Previously, the replacement of the placeholders was terminated without error 11 | after the first incorrect path and the initialization of the platform 12 | continued. 13 | BF: Platform: Names of environment variables are case-sensitive 14 | CR: Platform: Omission of the steps recorder (deprecated by Microsoft) 15 | CR: Platform: Simplification of the terminal action 16 | CR: Platform: Optimization for resumption if the drive already exists 17 | If the drive is recognized as attached, it is used directly instead of the 18 | error message that the drive already exists and the ejection. This usually 19 | concerns the situation after shutting down and logging off if the virtual 20 | environment has not been closed beforehand. 21 | CR: Platform: Optimization for shutdown and session ending 22 | CR: Platform: Reorganization of the environment variables 23 | - Variables with the prefix OS_ now use the prefix HOST_ 24 | HOST_APPDATA -> HOST_APPDATA 25 | HOST_LOCALAPPDATA -> HOST_LOCALAPPDATA 26 | HOST_HOMEPATH -> HOST_HOMEPATH 27 | HOST_PATH -> HOST_PATH 28 | HOST_PUBLIC -> HOST_PUBLIC 29 | HOST_TEMP -> HOST_TEMP 30 | HOST_TMP -> HOST_TMP 31 | HOST_USERPROFILE -> HOST_USERPROFILE 32 | - Variables with the prefix VT_ now use the prefix PLATFORM_ 33 | VT_APPDATA -> PLATFORM_APPDATA 34 | VT_APPSPATH -> PLATFORM_APPSPATH 35 | VT_HOMEDRIVE -> PLATFORM_HOMEDRIVE 36 | VT_HOMEPATH -> PLATFORM_HOMEPATH 37 | VT_LOCALAPPDATA -> PLATFORM_LOCALAPPDATA 38 | VT_PUBLIC -> PLATFORM_PUBLIC 39 | VT_TEMP -> PLATFORM_TEMP 40 | VT_USERPROFILE -> PLATFORM_USERPROFILE 41 | - Variables with the prefix PLATFORM_ are retained 42 | PLATFORM_APP, 43 | PLATFORM_DISK 44 | PLATFORM_HOME 45 | PLATFORM_NAME 46 | CR: Settings: Refactoring and optimization 47 | - New names of the sections 48 | SETTINGS -> ENVIRONMENT 49 | FILES -> CUSTOMIZATION 50 | - New sections 51 | FILESYSTEM for automatically created symlinks in the host system 52 | REGISTRY for temporary registry entries in the host system 53 | Details are described in the INI file! 54 | - The suffix of the template files that are created when filling the 55 | placeholders has been changed from -settings to -template. 56 | THE FILES MUST BE RENAMED WHEN THE PLATFORM IS UPDATED. 57 | CR: Platform: Update of platform tools 58 | - /Programs/Platform/inventory.exe 59 | - /Programs/Platform/launcher.exe 60 | - /Programs/Platform/platform.dll 61 | - /Programs/Platform/startup.exe 62 | 63 | 3.5.0 20240706 64 | BF: DiskPart: Optimization of attach 65 | - Name of the volume is no longer relevant 66 | BF: DiskPart: Optimization of detach if an error occurs 67 | BF: DiskPart: Optimization of compact 68 | BF: Platform: Correction if no platform.ini file exists 69 | - Caused an ArgumentNullException during attachment 70 | CR: Platform: Optimization of output/logging 71 | - If an error occurs 72 | - Batch processes (startup / exit) is output in the log file 73 | 74 | 3.4.0 20240302 75 | BF: Review: Optimization and corrections 76 | BF: DiskPart: Optimization when attaching disks with the same label 77 | BF: DiskPart: Correction when creating with Windows 11 78 | CR: DiskPart: Optimization of detach if an error occurs 79 | CR: Macros: Optimization of the use of WORKDIR 80 | CR: Macros: Usable as direct short commands 81 | CR: Project: Updated TargetFrameworkVersion to v4.8 82 | CR: Platform: Refactoring of the standard directory structure 83 | - Spaces in the path have been omitted 84 | - Formerly Database is now part of Storage 85 | - Formerly Install is now part of Resources 86 | - Core components of the platform are located in /Programs/Platform 87 | + Documents 88 | + Music 89 | + Pictures 90 | + Videos 91 | + Programs 92 | + Macros 93 | + macros 94 | + Platform 95 | + Resources 96 | + Settings 97 | + Storage 98 | + Temp 99 | 100 | 3.3.0 20230710 101 | BF: Settings: Spaces at the end of values are now ignored 102 | BF: Launcher: Correction/optimization of the output if the HotKey cannot be registered 103 | CR: Build: Releases are now only available on the release page 104 | CR: Macros: Added to temporarily change the command line configuration 105 | Create your own macros as cmd-file in Program Portables/Macros/macros. 106 | Call: 'macro [macro]' or 'macros [macro]' on the command line. 107 | CR: Platform: Added batch processing freeze detection 108 | Detects freezing script on attach and detach the platform and causes 109 | error instead of freezing itself. 110 | CR: ShiftDown: Omission of ShiftDown as standard tool 111 | CR: ShiftDown: Renaming in Balancer 112 | CR: ShiftDown: Outsourcing as a separate project 113 | 114 | 3.2.0 20220625 115 | BF: Build: Correction of the release info process 116 | BF: Launcher: Correction of the behavior when the screen resolution changes 117 | Triggers the update of the user interface. 118 | BF: Platform: Existing shortcuts are now overwritten 119 | CR: Platform: Optimization when detaching / process termination 120 | Killing of processes can be blocked by system protection. 121 | It is tried up to three times and then ignored. 122 | CR: Platform: Integrated settings as a core component 123 | The key values of the settings are part of the environment variables of 124 | the virtual environment. 125 | CR: Launcher: Scaling of icons depending on screen resolution (aesthetic reasons) 126 | CR: Launcher: Increase from the default value of OPACITY (95) 127 | CR: Launcher: Added option AutoScale (default true) 128 | Scales the view according to the screen resolution ot the primary screen 129 | CR: ShiftDown: Change the location to /Program Portables/ShiftDown 130 | 131 | 3.1.0 20220401 132 | BF: Platform: Correction of settings template synchronization 133 | If the target file is newer than the template, the template will be updated. 134 | BF: Platform Create: Correction of settings directory 135 | Has been moved from \Documents\Settings to \Settings. 136 | BF: Platform: Compact per DiskPart was not executed 137 | BF: Platform: Optimization and corrections 138 | BF: Platform: Optimization and corrections of the texts 139 | CR: Platform: Optimization / enhancement of function compact 140 | CR: Platform: Optimization of notification message output 141 | CR: Platform: Unification of namespace / platform icon / (sub) project structure 142 | CR: Platform: Added build script/process via Ant 143 | CR: Platform: Optimization of error logging 144 | CR: Platform: Added console as default command line prompt 145 | CR: Platform: Added launcher as default launcher to keep the environment alive 146 | CR: Platform: Added shiftdown as optional service to shift down the process priority 147 | The service automatically downgrades the process priority of CPU-intensive processes. 148 | For older Intel generations that suffer from the update of Windows and Intel. 149 | 150 | 3.0.0 20211126 151 | CR: Platform: Added function shortcuts 152 | Creates the usual calls as shortcuts. 153 | e.g. platform.exe B: shortcuts 154 | CR: Settings: Added for placeholder replacement in files 155 | This simplifies the personalization , distribution, migrations and updates. 156 | 157 | 2.5.0 2019xxxx 158 | CR: Added support for VHDX and BitLocker 159 | NT: No public release 160 | NT: More details have been lost 161 | 162 | 2.0.0 2015xxxx 163 | CR: Change from SUBST to virtual disk VHD 164 | NT: No public release 165 | NT: More details have been lost 166 | 167 | 1.0.0 20xxxxxx 168 | NT: No public release 169 | NT: More details have been lost 170 | NT: Release is available 171 | -------------------------------------------------------------------------------- /platform/Platform.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {ACCC1BBB-2740-490D-BEBA-CBF027A57B4B} 6 | Debug 7 | AnyCPU 8 | WinExe 9 | VirtualEnvironment.Platform 10 | Platform 11 | v4.8 12 | 512 13 | Properties\App.manifest 14 | Sources\Program.ico 15 | 16 | 17 | Library 18 | 19 | 20 | AnyCPU 21 | true 22 | full 23 | false 24 | Target\bin\Debug\ 25 | Target\obj\Debug\ 26 | Target\obj\Debug\ 27 | DEBUG;TRACE 28 | prompt 29 | 4 30 | false 31 | 32 | 33 | AnyCPU 34 | pdbonly 35 | true 36 | Target\bin\Release\ 37 | Target\obj\Release\ 38 | Target\obj\Release\ 39 | prompt 40 | 4 41 | false 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | {F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} 59 | 1 60 | 0 61 | 0 62 | tlbimp 63 | False 64 | True 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | ResXFileCodeGenerator 74 | Resources.Designer.cs 75 | 76 | 77 | True 78 | True 79 | Resources.resx 80 | 81 | 82 | False 83 | False 84 | Resources.resx 85 | 86 | 87 | 88 | 89 | Worker.cs 90 | 91 | 92 | Form 93 | 94 | 95 | Worker.cs 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 | -------------------------------------------------------------------------------- /platform/Platform.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Version 17 3 | VisualStudioVersion = 17.0.31903.59 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Platform", "Platform.csproj", "{ACCC1BBB-2740-490D-BEBA-CBF027A57B4B}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {ACCC1BBB-2740-490D-BEBA-CBF027A57B4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {ACCC1BBB-2740-490D-BEBA-CBF027A57B4B}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {ACCC1BBB-2740-490D-BEBA-CBF027A57B4B}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {ACCC1BBB-2740-490D-BEBA-CBF027A57B4B}.Release|Any CPU.Build.0 = Release|Any CPU 17 | EndGlobalSection 18 | GlobalSection(SolutionProperties) = preSolution 19 | HideSolutionNode = FALSE 20 | EndGlobalSection 21 | GlobalSection(ExtensibilityGlobals) = postSolution 22 | SolutionGuid = {2C64A535-DF9A-4522-80B8-D05DA1300D86} 23 | EndGlobalSection 24 | EndGlobal -------------------------------------------------------------------------------- /platform/Properties/App.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | true/PM 14 | 15 | 16 | -------------------------------------------------------------------------------- /platform/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Seanox Virtual Environment")] 8 | [assembly: AssemblyDescription("Creates, starts and controls a virtual environment.")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Seanox Software Solutions")] 11 | [assembly: AssemblyProduct("Platform")] 12 | [assembly: AssemblyCopyright("Copyright © 0000 Seanox Software Solutions")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("accc1bbb-2740-490d-beba-cbf027a57b4b")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("0.0.0")] 35 | [assembly: AssemblyFileVersion("0.0.0")] 36 | [assembly: AssemblyMetadata("Build", "00000000")] 37 | -------------------------------------------------------------------------------- /platform/README.md: -------------------------------------------------------------------------------- 1 | # Platform 2 | Platform is a tool for the initial creation, use and management of the virtual 3 | environment and modules that then automatically download tools and programs 4 | from the Internet, configure them and integrated them in the virtual 5 | environment. 6 | 7 | __The module concept is implemented and usable, but no modules have been 8 | released yet because there is currently not enough time to maintain the 9 | packages -- your support is welcome :-)__ 10 | 11 | # Usage 12 | - Rename __platform.exe__ to the name that will be used for the environment and 13 | drive 14 | 15 | When the virtual environment is created in the form of the VHDX file, it can be 16 | used as follows. 17 | 18 | `usage: platform.exe A-Z: [create|attach|detach|compact|shortcuts] ` 19 | 20 | Example 21 | - `seanox.exe B: create` to create the initial environment as VHDX 22 | - `seanox.exe B: shortcuts` to create the usual calls as shortcuts 23 | - `seanox.exe B: attach` to attach the environment 24 | 25 | Configure __Startup.cmd__ in the root directory of the virtual environment and 26 | add the desired programs and services. It is recommended to use a launcher so 27 | that the environment variables are available to the called programs. Detach 28 | should also be started via the launcher if programs and services are terminated 29 | when detaching and the environment variables are needed for this. 30 | 31 | - `seanox.exe B: detach` to detach the environment 32 | - `seanox.exe B: compact` to compact the virtual disk 33 | 34 | __Module integration will come later, but will be similar.__ 35 | 36 | # System Requirement 37 | - Microsoft Windows 10 or higher 38 | - Microsoft .NET 4.8.x or higher (for runtime) 39 | - [Microsoft .NET 4.8.x Developer Pack or higher]( 40 | https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48) (for development only) 41 | 42 | # Download 43 | Platform is [part of the virtual environment]( 44 | https://github.com/seanox/virtual-environment/tree/main/platform) 45 | but can also be downloaded and used separately. 46 | 47 | https://github.com/seanox/virtual-environment/releases 48 | 49 | # Changes 50 | ## 3.5.0 20240706 51 | BF: DiskPart: Optimization of attach 52 | BF: DiskPart: Optimization of detach if an error occurs 53 | BF: DiskPart: Optimization of compact 54 | BF: Platform: Correction if no platform.ini file exists 55 | CR: Platform: Optimization of output/logging 56 | 57 | [Read more](https://raw.githubusercontent.com/seanox/virtual-environment/master/platform/CHANGES) 58 | -------------------------------------------------------------------------------- /platform/Resources/diskpart/attach: -------------------------------------------------------------------------------- 1 | select vdisk file="#[file]" 2 | attach vdisk 3 | select partition 2 4 | assign letter=#[drive] 5 | exit 6 | -------------------------------------------------------------------------------- /platform/Resources/diskpart/compact: -------------------------------------------------------------------------------- 1 | select vdisk file="#[file]" 2 | attach vdisk readonly 3 | compact vdisk 4 | detach vdisk 5 | exit 6 | -------------------------------------------------------------------------------- /platform/Resources/diskpart/create: -------------------------------------------------------------------------------- 1 | create vdisk file="#[file]" type=#[type] maximum=#[size] 2 | select vdisk file="#[file]" 3 | attach vdisk 4 | convert #[style] 5 | create partition primary 6 | format QUICK FS=NTFS LABEL="#[name]" COMPRESS 7 | detach vdisk 8 | exit 9 | -------------------------------------------------------------------------------- /platform/Resources/diskpart/detach: -------------------------------------------------------------------------------- 1 | select vdisk file="#[file]" 2 | detach vdisk 3 | exit 4 | -------------------------------------------------------------------------------- /platform/Resources/platform/AutoRun.inf: -------------------------------------------------------------------------------- 1 | [AutoRun] 2 | Label = #[name] #[version] 3 | Icon = .\Resources\platform.ico -------------------------------------------------------------------------------- /platform/Resources/platform/Programs/Macros/macro.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | SET WORKDIR=%cd% 4 | SET HOMEDIR=%~dp0 5 | SET MACRO=%1 6 | SET MACRO=%MACRO:"=%.cmd 7 | SET MACROSDIR=%HOMEDIR%\macros 8 | 9 | IF NOT EXIST "%MACROSDIR%" MKDIR "%MACROSDIR%" 10 | 11 | IF NOT [%1] == [] ( 12 | IF EXIST "%MACROSDIR%\%MACRO%" ( 13 | PUSHD "%MACROSDIR%" & "%MACRO%" & POPD 14 | ENDLOCAL 15 | GOTO:EOF 16 | ) 17 | ) 18 | 19 | SETLOCAL ENABLEEXTENSIONS 20 | 21 | ECHO Virtual Environment Macros [Version 1.0.0 20230125] 22 | ECHO Copyright (C) 2023 Seanox Software Solutions 23 | ECHO Custom command line extensions 24 | ECHO. 25 | 26 | ECHO usage: %~nx0 [macro] 27 | ECHO. 28 | 29 | SET MACROSEXISTS=0 30 | FOR %%f IN ("%MACROSDIR%\*.cmd") DO ( 31 | IF NOT [%%~nxf] == [%~nx0] ( 32 | SET MACROSEXISTS=1 33 | ) 34 | ) 35 | IF [%MACROSEXISTS%] == [1] ( 36 | ECHO available macros: 37 | FOR %%f IN ("%MACROSDIR%\*.cmd") DO ( 38 | IF NOT [%%~nxf] == [%~nx0] ( 39 | ECHO %%~nf 40 | ) 41 | ) 42 | ) ELSE ( 43 | ECHO no macros available 44 | ) 45 | 46 | ENDLOCAL 47 | -------------------------------------------------------------------------------- /platform/Resources/platform/Programs/Macros/macros.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | SET WORKDIR=%cd% 4 | SET HOMEDIR=%~dp0 5 | SET MACRO=%1 6 | SET MACRO=%MACRO:"=%.cmd 7 | SET MACROSDIR=%HOMEDIR%\macros 8 | 9 | IF NOT EXIST "%MACROSDIR%" MKDIR "%MACROSDIR%" 10 | 11 | IF NOT [%1] == [] ( 12 | IF EXIST "%MACROSDIR%\%MACRO%" ( 13 | PUSHD "%MACROSDIR%" & "%MACRO%" & POPD 14 | ENDLOCAL 15 | GOTO:EOF 16 | ) 17 | ) 18 | 19 | SETLOCAL ENABLEEXTENSIONS 20 | 21 | ECHO Virtual Environment Macros [Version 1.0.0 20230125] 22 | ECHO Copyright (C) 2023 Seanox Software Solutions 23 | ECHO Custom command line extensions 24 | ECHO. 25 | 26 | ECHO usage: %~nx0 [macro] 27 | ECHO. 28 | 29 | SET MACROSEXISTS=0 30 | FOR %%f IN ("%MACROSDIR%\*.cmd") DO ( 31 | IF NOT [%%~nxf] == [%~nx0] ( 32 | SET MACROSEXISTS=1 33 | ) 34 | ) 35 | IF [%MACROSEXISTS%] == [1] ( 36 | ECHO available macros: 37 | FOR %%f IN ("%MACROSDIR%\*.cmd") DO ( 38 | IF NOT [%%~nxf] == [%~nx0] ( 39 | ECHO %%~nf 40 | ) 41 | ) 42 | ) ELSE ( 43 | ECHO no macros available 44 | ) 45 | 46 | ENDLOCAL 47 | -------------------------------------------------------------------------------- /platform/Resources/platform/Programs/Platform/inventory.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/platform/Resources/platform/Programs/Platform/inventory.exe -------------------------------------------------------------------------------- /platform/Resources/platform/Programs/Platform/launcher.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/platform/Resources/platform/Programs/Platform/launcher.exe -------------------------------------------------------------------------------- /platform/Resources/platform/Programs/Platform/launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 25 | 8 + 27 26 | 27 | 28 | 101 29 | 30 | 25 31 | 32 | 10 33 | 34 | 4 35 | 36 | 37 | true 38 | 39 | 45 | 95 46 | 47 | 52 | 53 | 54 | 73 | 74 | 75 | 81 | 82 | 87 | 9.5 88 | 89 | 99 | 100 | 101 | 102 | 103 | 40 104 | 105 | Detach 106 | 110 | %WINDIR%\system32\shell32.dll:27 111 | 112 | %PLATFORM_APP% 113 | 114 | %HOMEDRIVE% detach 115 | 116 | %PLATFORM_HOME% 117 | 118 | 119 | 17 120 | hosts 121 | %WINDIR%\system32\inetcpl.cpl:26 122 | %WINDIR%\system32\notepad.exe 123 | %WINDIR%\System32\drivers\etc\hosts 124 | %WINDIR%\System32\drivers\etc 125 | 126 | 127 | 27 128 | Services 129 | %WINDIR%\system32\services.msc 130 | %HOMEDRIVE%%HOMEPATH% 131 | 132 | 133 | 28 134 | Settings 135 | %WINDIR%\system32\inetcpl.cpl:46 136 | %WINDIR%\system32\notepad.exe 137 | %APPSPATH%\Platform\launcher.xml 138 | %APPSPATH%\Platform 139 | 140 | 141 | 31 142 | Terminal 143 | %WINDIR%\System32\cmd.exe 144 | %APPSPATH%\Platform\console.cmd 145 | %HOMEDRIVE% 146 | 147 | 148 | 38 149 | Steps Recorder 150 | %WINDIR%\System32\psr.exe 151 | %WINDIR%\System32 152 | 153 | 154 | 39 155 | Documents 156 | %WINDIR%\system32\shell32.dll:126 157 | %WINDIR%\explorer.exe 158 | %HOMEDRIVE%%HOMEPATH% 159 | 160 | 161 | -------------------------------------------------------------------------------- /platform/Resources/platform/Programs/Platform/platform.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/platform/Resources/platform/Programs/Platform/platform.dll -------------------------------------------------------------------------------- /platform/Resources/platform/Programs/Platform/startup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/platform/Resources/platform/Programs/Platform/startup.exe -------------------------------------------------------------------------------- /platform/Resources/platform/Resources/manual.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Since about 2010, there has been a project for a virtual environment with a 4 | modular structure targeting developers and users, enabling them to work in a 5 | fully pre-configured environment with all programs, tools, and services—without 6 | modifying the host environment or requiring additional dedicated virtualization 7 | resources. 8 | 9 | Short setup times, uniform tools with standardized configurations, consistent 10 | file system paths, centralized maintenance, and easy distribution and updates 11 | are just some of the benefits. The environment is highly customizable, can be 12 | quickly adapted for different projects, and can be seamlessly transferred to 13 | other machines to continue ongoing work. 14 | 15 | The project includes a platform—a tool for the initial creation, use, and 16 | management of the virtual environment—and a module concept for the automatic 17 | integration and configuration of tools and programs from any source on the 18 | Internet. The module concept is a successful proof of concept envisioned as a 19 | possible future extension of the platform, but it is not currently the focus of 20 | development. 21 | 22 | 23 | 24 | # Usage 25 | 26 | The program is initially started via the command line and serves as a central 27 | tool for creating, managing, and starting the platform. Although the platform is 28 | primarily used as a Windows application, initial control is provided through 29 | command line commands. 30 | 31 | 32 | 33 | ## 1. Creating a New Environment 34 | 35 | - Use a directory where the virtual environment will be created. 36 | - Copy the `platform.exe` file into this directory. 37 | - Rename `platform.exe` to the name of the virtual environment you want to create 38 | e.g. `ren platform.exe seanox.exe` 39 | - Create the virtual environment for drive B: 40 | e.g., `seanox.exe B: create` 41 | 42 | A VHDX file is created in the current directory with the name derived from the 43 | platform program. The virtual drive also uses this name. 44 | 45 | The drive can be mounted temporarily—either manually or using the platform 46 | program. When you open the virtual drive, a recommended directory structure is 47 | already present; however, it can be rearranged individually. 48 | 49 | It is important to note that the platform program will run the `Startup.cmd` 50 | located in the root directory when the virtual environment is started. Other 51 | configurations may be modified as needed. 52 | 53 | 54 | 55 | ## 2. Creating Shortcuts for Common Tasks 56 | 57 | This step is optional and convenient. 58 | 59 | - Create shortcuts, for example: 60 | `seanox.exe B: shortcuts` 61 | 62 | This command creates shortcuts in the current directory for attaching, 63 | detaching, and compacting the virtual environment. The file name of the platform 64 | application is also used _seanox.attach.lnk_, _seanox.detach.lnk_ an 65 | _seanox.compact.lnk_. 66 | 67 | 68 | 69 | ## 3. Attaching and Starting the Virtual Environment 70 | 71 | - Start the virtual environment 72 | e.g. `seanox.exe B: attach` 73 | 74 | When attaching the virtual environment, `Startup.cmd` is executed. This process 75 | installs, configures, and starts the environment along with its contained 76 | programs. It is controlled exclusively via the environment variables of the 77 | platform. 78 | 79 | 80 | 81 | ## 4. Installation of Programs and Services 82 | 83 | The virtual environment is presented as a real drive with its own drive letter 84 | and file system. By default, the user profile and application data are 85 | redirected to the Settings directory in the root. 86 | 87 | Programs can be installed in the usual manner; however, using portable versions 88 | is recommended and generally simpler. 89 | 90 | Good sources are: 91 | - https://portableapps.com 92 | - https://portapps.io 93 | 94 | Many manufacturers also offer portable versions or portable usage of their 95 | software. 96 | 97 | With both attachment and detachment of the virtual environment, `Startup.cmd` is 98 | invoked. This enables the environment to be configured and allows programs to be 99 | installed, configured, started, stopped, or uninstalled— all driven by the 100 | environment variables of the virtual platform. 101 | 102 | 103 | 104 | ## 5. Stopping and Detaching the Virtual Environment 105 | 106 | If programs and services rely on the virtual platform’s environment variables, 107 | they should also be started within the virtual environment. Detachment should be 108 | performed in a manner that ensures all programs are properly terminated and, 109 | if necessary, uninstalled. 110 | 111 | __How does it work?__ 112 | 113 | When the virtual environment is attached, a child process is created that 114 | inherits the specific environment variables of the virtual environment as its 115 | context. This child process automatically executes `Startup.cmd` and launches a 116 | dedicated launcher, which keeps the child process continuously active. All 117 | programs within the virtual environment are then started via this launcher, 118 | ensuring they run with the defined environment context. 119 | 120 | Detachment can be initiated either via environment variables: 121 | 122 | `%PLATFORM_APP% %HOMEDRIVE% detach` 123 | 124 | Or by using the platform program 125 | 126 | e.g. `seanox.exe B: detach` 127 | 128 | When detaching, _Startup.cmd_ is called with the parameter 'exit' and then all 129 | programs launched from the virtual environment are first terminated gracefully; 130 | if necessary, a forced termination follows. 131 | 132 | __About security__ 133 | 134 | __The platform is started with administrator privileges, although this 135 | potentially carries an increased risk, it is quite common in development and 136 | testing environments to run applications with administrative or elevated user 137 | rights. Many tools and programs require these rights in order to fully utilize 138 | all the necessary system functionalities. Nevertheless, the use of 139 | administrative privileges should always be applied consciously—with appropriate 140 | security measures in place within controlled environments—to minimize potential 141 | risks as much as possible without unnecessarily hindering operations.__ 142 | 143 | 144 | 145 | ## 6. Personalization of the Virtual Environment 146 | 147 | Even though a virtual environment can be extensively configured, there are 148 | scenarios where additional user, system, and environment data is required. For 149 | this purpose, the virtual environment incorporates an INI-based settings 150 | component. The INI file, located in the working directory of the virtual 151 | environment, defines settings for environment variables, file system access, 152 | registry management, and placeholder replacement within the environment. Each 153 | section outlines structured rules to ensure consistent behavior when attaching 154 | or detaching the environment. 155 | 156 | More details and descriptions can be found in the INI file in the working 157 | directory of the virtual environment. 158 | 159 | 160 | 161 | ## 7. Compacting the Virtual Environment 162 | 163 | The virtual environment utilizes a virtual disk with a dynamic size. During use, 164 | this file will grow, but it will not be automatically compacted. However, the 165 | size of the virtual hard disk can be optimized manually. 166 | 167 | - Stop and detach the virtual environment. 168 | - Initiate the optimization process 169 | e.g. `seanox.exe B: compact` 170 | 171 | For optimization, the virtual disk is attached without executing _Startup.cmd_. 172 | If a temp directory exists in the root directory, it is emptied. Subsequently, 173 | the virtual disk is compacted by eliminating unused space. 174 | 175 | 176 | 177 | ## 8. Standard and Error Output 178 | 179 | The user interface is minimalistic, reflecting a novel approach. Due to limited 180 | space for extended explanations, a log file is generated. This log file contains 181 | both error outputs and extended trace outputs, which assist in diagnostics. 182 | 183 | 184 | 185 | __That's it -- have fun with it!__ 186 | -------------------------------------------------------------------------------- /platform/Resources/platform/Resources/platform.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/platform/Resources/platform/Resources/platform.ico -------------------------------------------------------------------------------- /platform/Resources/platform/Resources/platform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/platform/Resources/platform/Resources/platform.png -------------------------------------------------------------------------------- /platform/Resources/platform/Startup.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Environment termination 4 | REM ---- 5 | IF "%1" == "exit" ( 6 | 7 | REM All the commands required to unmount the virtual environment are 8 | REM inserted here. In particular, stop all temporary services and remove 9 | REM them from the system. The environment itself will then gently or, if 10 | REM unsuccessful, hard terminate all programs that were started from the 11 | REM virtual drive and are still running. 12 | 13 | REM ---- Launcher 14 | 15 | REM Part of the concept: The environment is based on a command line with 16 | REM customized standard environment variables for Windows and the 17 | REM applications. This command line is kept alive by the launcher, as it can 18 | REM start the programs on the basis of its command line and thus on the 19 | REM basis of the environment variables available there. The launcher 20 | REM therefore has no implemented function for terminating and must be 21 | REM terminated hard via taskkill on detach, which the platform does itself. 22 | 23 | REM ---- Custom 24 | 25 | REM Placeholder for automatic module integration 26 | REM INSERT DETACH 27 | 28 | GOTO:EOF 29 | ) 30 | 31 | 32 | 33 | 34 | 35 | REM Environment configuration 36 | REM ---- 37 | 38 | SET HOST_APPDATA=%APPDATA% 39 | SET HOST_LOCALAPPDATA=%LOCALAPPDATA% 40 | SET HOST_HOMEPATH=%HOMEPATH% 41 | SET HOST_PATH=%PATH% 42 | SET HOST_PUBLIC=%PUBLIC% 43 | SET HOST_TEMP=%TEMP% 44 | SET HOST_TMP=%TMP% 45 | SET HOST_USERPROFILE=%USERPROFILE% 46 | 47 | REM Following environment variables are set at startup: 48 | REM - PLATFORM_NAME Name of the environment, derived from the virtual disk 49 | REM - PLATFORM_HOME Home directory of the virtual disk 50 | REM - PLATFORM_DISK Path of the virtual disc 51 | REM - PLATFORM_APP Path from the environment startup program 52 | REM - PLATFORM_HOMEDRIVE Root directory of the started virtual environment 53 | 54 | SET PLATFORM_HOMEPATH=\Documents 55 | SET PLATFORM_USERPROFILE=%PLATFORM_HOMEDRIVE%\Settings 56 | SET PLATFORM_APPDATA=%PLATFORM_USERPROFILE%\Roaming 57 | SET PLATFORM_LOCALAPPDATA=%PLATFORM_USERPROFILE%\Local 58 | SET PLATFORM_PUBLIC=%PLATFORM_HOMEDRIVE%\Documents\Public 59 | SET PLATFORM_APPSPATH=%PLATFORM_HOMEDRIVE%\Programs 60 | SET PLATFORM_TEMP=%PLATFORM_HOMEDRIVE%\Temp 61 | 62 | REM Relevant system variables are rewritten 63 | REM Be careful with changing USERPROFILE, it can cause unexpected results. 64 | SET APPDATA=%PLATFORM_APPDATA% 65 | SET APPSPATH=%PLATFORM_APPSPATH% 66 | SET APPSSETTINGS=%PLATFORM_HOMEDRIVE%\Settings 67 | SET HOME=%APPSSETTINGS% 68 | SET HOMEDRIVE=%PLATFORM_HOMEDRIVE% 69 | SET HOMEPATH=%PLATFORM_HOMEPATH% 70 | SET LOCALAPPDATA=%PLATFORM_LOCALAPPDATA% 71 | SET PUBLIC=%PLATFORM_PUBLIC% 72 | SET TEMP=%PLATFORM_TEMP% 73 | SET TMP=%PLATFORM_TMP% 74 | 75 | SET PLATFORM_NAME=%PLATFORM_PLATFORM_NAME% 76 | SET PLATFORM_HOME=%PLATFORM_PLATFORM_HOME% 77 | SET PLATFORM_DISK=%PLATFORM_PLATFORM_DISK% 78 | SET PLATFORM_APP=%PLATFORM_PLATFORM_APP% 79 | 80 | REM Further environment variables are inserted here. 81 | REM Please do not set program starts here, that will come later. 82 | 83 | REM Changes the platform name to uppercase, e.g. as a prefix for services. 84 | REM for /f "usebackq delims=" %%I in (`powershell "\"%PLATFORM_NAME%\".toUpper()"`) do set "PLATFORM_NAME=%%~I" 85 | 86 | REM ---- Platform 87 | SET PATH=%APPSPATH%\Platform;%PATH% 88 | 89 | REM ---- Macros 90 | SET PATH=%APPSPATH%\Macros;%PATH%;%APPSPATH%\Macros\macros 91 | 92 | REM Placeholder for automatic module integration 93 | REM INSERT COMMONS 94 | 95 | 96 | 97 | 98 | 99 | REM Environment preparation 100 | REM ---- 101 | 102 | REM Programs and service are configured and initialized here, but not started. 103 | 104 | REM Placeholder for automatic module integration 105 | REM INSERT ATTACH 106 | 107 | 108 | 109 | 110 | 111 | REM Environment starting 112 | REM ---- 113 | 114 | REM Programs and services are finally started here. 115 | REM It is important that the programs start in such a way that the startup 116 | REM script does not block, because the startup program of the virtual 117 | REM environment waits for the end of the startup script. 118 | 119 | REM Basically, a launcher or start menu should be started so that the programs 120 | REM can later use the virtual environment and the required environment 121 | REM variables. This is also important so that detaching works properly. 122 | 123 | REM ---- Launcher (to keep the environment alive) 124 | pushd "%APPSPATH%\Platform" 125 | start launcher.exe 126 | popd 127 | 128 | REM Placeholder for automatic module integration 129 | REM INSERT STARTUP 130 | -------------------------------------------------------------------------------- /platform/Resources/platform/Storage/registry.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/platform/Resources/platform/Storage/registry.data -------------------------------------------------------------------------------- /platform/Resources/settings.ini: -------------------------------------------------------------------------------- 1 | ; Configuration file for the virtual environment 2 | ; 3 | ; This INI file defines settings for environment variables, file system access, 4 | ; registry management, and placeholder replacement within the virtual 5 | ; environment. Each section provides structured rules to ensure consistent 6 | ; behavior when attaching or detaching the environment. 7 | ; 8 | ; MODIFY WITH CAUTION, AS INCORRECT VALUES MAY IMPACT FUNCTIONALITY. 9 | 10 | 11 | 12 | ; The ENVIRONMENT section defines keys and values for environment variables. 13 | ; Keys start with a letter or an underscore, followed by alphanumeric 14 | ; characters, a hyphen, an underscore, or a dot, and end alphanumerically or 15 | ; with an underscore. Keys and values are separated by an equal sign. Spaces 16 | ; before or after the equal sign are optional. If a key is defined multiple 17 | ; times, the last assigned value is always used; previous values are 18 | ; overwritten. 19 | ; 20 | ; The environment variables defined here can be used as placeholders in the 21 | ; following configuration in the format #[name]. 22 | ; 23 | ; Following system environment variables are not changeable: 24 | ; PLATFORM_NAME, PLATFORM_HOME, PLATFORM_DISK, PLATFORM_APP, 25 | ; PLATFORM_HOMEDRIVE 26 | [ENVIRONMENT] 27 | 28 | 29 | 30 | ; The FILESYSTEM section is used when applications in the virtual environment 31 | ; need to access specific data from the host system, such as user profile or 32 | ; ProgramData directories. For this purpose, the virtual environment provides a 33 | ; dedicated storage directory. When attaching the virtual environment, the 34 | ; relevant files and directories are selectively linked to the host system via 35 | ; Symlinks (symbolic links), without integrating the entire filesystem of the 36 | ; virtual environment. When detaching the virtual environment, these Symlinks 37 | ; are removed from the host system again. 38 | ; 39 | ; This section expects and processes absolute paths with drive letters. It is 40 | ; recommended to define paths using system environment variables, as this 41 | ; increases flexibility and reduces dependencies on user accounts. 42 | ; 43 | ; %ALLUSERSPROFILE%, %APPDATA%, %COMMONPROGRAMFILES%, 44 | ; %COMMONPROGRAMFILES(X86)%, %COMMONPROGRAMW6432%, %HOMEPATH%, 45 | ; %LOCALAPPDATA%, %PROGRAMFILES%, %PROGRAMFILES%, %PROGRAMFILES(X86)%, 46 | ; %PUBLIC%, %SYSTEMDRIVE%, %SYSTEMROOT%, %USERPROFILE%, %WINDIR%, ... 47 | 48 | ; If the target drive does not exist, the corresponding path is skipped, and the 49 | ; process continues without error. 50 | [FILESYSTEM] 51 | 52 | 53 | 54 | ; The REGISTRY section is used when applications in the virtual environment need 55 | ; access to specific areas of the Windows Registry in the host system, such as 56 | ; HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE. For this purpose, the virtual 57 | ; environment provides a dedicated storage directory along with the 58 | ; registry.data file to store registry entries. 59 | 60 | ; When attaching the virtual environment, the relevant registry entries are 61 | ; temporarily added to the Windows Registry of the host system. When detaching, 62 | ; changes from the virtual environment are saved to registry.data before the 63 | ; temporary registry entries are removed. Pre-existing registry entries in the 64 | ; host system remain unchanged. 65 | ; 66 | ; This section lists the paths of the registry entries that refer to the entries 67 | ; in the registry.data file. Paths for registry keys and registry keys with a 68 | ; value are supported. The value is specified at the end of the path separated 69 | ; by a colon. 70 | [REGISTRY] 71 | 72 | 73 | 74 | ; The CUSTOMS section represents a list of file paths in whose content 75 | ; placeholders in the format #[name] are replaced by variables from the section 76 | ; ENVIRONMENT and/or by system environment variables that correspond to the 77 | ; name. The replacement is designed in such a way that the places with the 78 | ; placeholders are updated each time the virtual environment is attached. The 79 | ; file paths must begin with a slash or a backslash. Paths that start with a 80 | ; drive letter are not supported, as the drive of the virtual environment is 81 | ; always used. When attached the virtual environment, all paths that do not meet 82 | ; these requirements are automatically ignored. 83 | [CUSTOMS] 84 | -------------------------------------------------------------------------------- /platform/Sources/Messages.cs: -------------------------------------------------------------------------------- 1 | // LICENSE TERMS - Seanox Software Solutions is an open source project, 2 | // hereinafter referred to as Seanox Software Solutions or Seanox for short. 3 | // This software is subject to version 2 of the Apache License. 4 | // 5 | // Virtual Environment Platform 6 | // Program starter for the virtual environment. 7 | // Copyright (C) 2025 Seanox Software Solutions 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 10 | // use this file except in compliance with the License. You may obtain a copy of 11 | // the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | // License for the specific language governing permissions and limitations under 19 | // the License. 20 | 21 | using System; 22 | using System.Collections.Generic; 23 | using System.Linq; 24 | using System.Text; 25 | using System.Text.RegularExpressions; 26 | using System.Threading.Tasks; 27 | 28 | namespace VirtualEnvironment.Platform 29 | { 30 | internal static class Messages 31 | { 32 | private static readonly HashSet _subscriptions; 33 | 34 | private static readonly object _lock; 35 | 36 | static Messages() 37 | { 38 | _subscriptions = new HashSet(); 39 | _lock = new object(); 40 | } 41 | 42 | internal static void Subscribe(ISubscriber recipient) 43 | { 44 | if (recipient == null) 45 | throw new ArgumentNullException(); 46 | lock (_lock) 47 | _subscriptions.Add(recipient); 48 | } 49 | 50 | internal static void Unsubscribe(ISubscriber recipient) 51 | { 52 | if (recipient == null) 53 | throw new ArgumentNullException(); 54 | lock (_lock) 55 | _subscriptions.Remove(recipient); 56 | } 57 | 58 | internal interface ISubscriber 59 | { 60 | void Receive(Message message); 61 | } 62 | 63 | internal static void Push(params Message[] messages) 64 | { 65 | List recipients; 66 | lock (_lock) 67 | recipients = _subscriptions.ToList(); 68 | 69 | Parallel.ForEach(messages, message => 70 | Parallel.ForEach(recipients, recipient => 71 | { 72 | try { recipient.Receive(message); } 73 | catch { } 74 | })); 75 | } 76 | 77 | internal static void Push(Type type, params string[] data) 78 | { 79 | Push(new Message(type, data)); 80 | } 81 | 82 | internal static void Push(Type type, string context, params string[] data) 83 | { 84 | Push(new Message(type, context, data)); 85 | } 86 | 87 | internal static void Push(Type type, object data) 88 | { 89 | Push(new Message(type, data)); 90 | } 91 | 92 | internal static void Push(Type type, string context, object data) 93 | { 94 | Push(new Message(type, context, data)); 95 | } 96 | 97 | internal enum Type 98 | { 99 | Error, 100 | Warning, 101 | Trace, 102 | Verbose, 103 | Data, 104 | Exit 105 | } 106 | 107 | internal readonly struct Message 108 | { 109 | internal Type Type { get; } 110 | internal string Context { get; } 111 | internal object Data { get; } 112 | 113 | internal Message(Type type, object data) 114 | : this(type, null, data) 115 | { 116 | } 117 | 118 | internal Message(Type type, string context, object data) 119 | { 120 | Type = type; 121 | if (!String.IsNullOrWhiteSpace(context)) 122 | context = Regex.Replace(context, @"[\r\n]+", " ").Trim(); 123 | Context = !String.IsNullOrWhiteSpace(context) ? context : null; 124 | if (data is IEnumerable lines) 125 | data = String.Join(Environment.NewLine, lines); 126 | Data = data; 127 | } 128 | 129 | internal Message ConvertTo(Type type) 130 | { 131 | return new Message(type, Context, Data); 132 | } 133 | 134 | public override string ToString() 135 | { 136 | var stringBuilder = new StringBuilder(Type.ToString().ToUpper()) 137 | .Append(" "); 138 | 139 | var content = Data; 140 | 141 | if (!String.IsNullOrWhiteSpace(Context)) 142 | stringBuilder.AppendLine(Context); 143 | 144 | if (Data is Exception exception) 145 | { 146 | stringBuilder.Append(exception.GetType().Name); 147 | if (!String.IsNullOrWhiteSpace(exception.Message)) 148 | stringBuilder.Append($": {exception.Message.Trim()}"); 149 | stringBuilder.AppendLine(); 150 | if (!(exception.StackTrace is null)) 151 | content = exception.StackTrace 152 | .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) 153 | .Select(line => Convert.ToString(line).Trim()); 154 | else content = null; 155 | } 156 | 157 | if (!(content is IEnumerable) 158 | && content is IEnumerable objects) 159 | content = objects 160 | .Where(line => line != null) 161 | .Select(Convert.ToString); 162 | 163 | if (content is IEnumerable strings) 164 | content = String.Join(Environment.NewLine, strings); 165 | 166 | content = Convert.ToString(content).Trim(); 167 | content = Regex.Replace( 168 | (string)content, 169 | "((\r\n)|(\n\r)|[\r\n])", 170 | Environment.NewLine); 171 | content = Regex.Replace( 172 | (string)content, 173 | "((\r\n)|(\n\r)|[\r\n]){3,}", 174 | $"{Environment.NewLine}{Environment.NewLine}"); 175 | if (!String.IsNullOrEmpty((string)content)) 176 | stringBuilder.Append(content); 177 | 178 | return stringBuilder.ToString().Trim(); 179 | } 180 | } 181 | } 182 | } -------------------------------------------------------------------------------- /platform/Sources/Program.cs: -------------------------------------------------------------------------------- 1 | // LICENSE TERMS - Seanox Software Solutions is an open source project, 2 | // hereinafter referred to as Seanox Software Solutions or Seanox for short. 3 | // This software is subject to version 2 of the Apache License. 4 | // 5 | // Virtual Environment Platform 6 | // Creates, starts and controls a virtual environment. 7 | // Copyright (C) 2025 Seanox Software Solutions 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 10 | // use this file except in compliance with the License. You may obtain a copy of 11 | // the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | // License for the specific language governing permissions and limitations under 19 | // the License. 20 | 21 | using System; 22 | using System.Collections.Generic; 23 | using System.IO; 24 | using System.Linq; 25 | using System.Reflection; 26 | using System.Text; 27 | using System.Text.RegularExpressions; 28 | using System.Windows.Forms; 29 | 30 | namespace VirtualEnvironment.Platform 31 | { 32 | internal static class Program 33 | { 34 | [STAThread] 35 | private static void Main (params string[] arguments) 36 | { 37 | Application.EnableVisualStyles(); 38 | Application.SetCompatibleTextRenderingDefault(false); 39 | 40 | if (arguments == null) 41 | arguments = new string[] {}; 42 | var task = (arguments.ElementAtOrDefault(1) ?? String.Empty).ToLower(); 43 | var drive = (arguments.ElementAtOrDefault(0) ?? String.Empty).ToUpper(); 44 | if (!new Regex("^[A-Z]:$").IsMatch(drive)) 45 | task = String.Empty; 46 | 47 | if (Assembly.GetExecutingAssembly() != Assembly.GetEntryAssembly() 48 | && !new Regex("^(compact|attach|detach|shortcuts)$", RegexOptions.IgnoreCase).IsMatch(task)) 49 | throw new InvalidOperationException("Requires a drive letter (A-Z) and a method: [compact|attach|detach|shortcuts]."); 50 | 51 | AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; 52 | 53 | Messages.Subscribe(new Subscription()); 54 | 55 | var applicationPath = Assembly.GetExecutingAssembly().Location; 56 | var diskFile = Path.Combine(Path.GetDirectoryName(applicationPath), 57 | Path.GetFileNameWithoutExtension(applicationPath) + ".vhdx"); 58 | var workerTask = Worker.Task.Usage; 59 | switch (task) 60 | { 61 | case "create": 62 | workerTask = Worker.Task.Create; 63 | break; 64 | case "compact": 65 | workerTask = Worker.Task.Compact; 66 | break; 67 | case "attach": 68 | workerTask = Worker.Task.Attach; 69 | break; 70 | case "detach": 71 | workerTask = Worker.Task.Detach; 72 | break; 73 | case "shortcuts": 74 | workerTask = Worker.Task.Shortcuts; 75 | break; 76 | } 77 | 78 | // In the case that the main method is called as a DLL. If a window 79 | // from the calling program already exists, no new one should or may 80 | // be established as an application, as this will otherwise cause an 81 | // InvalidOperationException. 82 | 83 | if (!Application.MessageLoop 84 | && Application.OpenForms.Count <= 0) 85 | { 86 | Application.EnableVisualStyles(); 87 | Application.SetCompatibleTextRenderingDefault(false); 88 | Application.Run(new Worker(workerTask, drive, diskFile)); 89 | } 90 | else new Worker(workerTask, drive, diskFile).Show(); 91 | } 92 | 93 | private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs exceptionEvent) 94 | { 95 | Messages.Push(Messages.Type.Error, exceptionEvent.ExceptionObject); 96 | } 97 | 98 | private class Subscription : Messages.ISubscriber 99 | { 100 | private string _context; 101 | 102 | private bool _continue; 103 | 104 | private static readonly HashSet MESSAGE_TYPE_LIST = new HashSet() 105 | { 106 | Messages.Type.Error, 107 | Messages.Type.Warning, 108 | Messages.Type.Trace 109 | }; 110 | 111 | public void Receive(Messages.Message message) 112 | { 113 | if (!MESSAGE_TYPE_LIST.Contains(message.Type) 114 | || message.Data is null) 115 | return; 116 | 117 | var content = message.ToString().Trim(); 118 | if (String.IsNullOrWhiteSpace(content)) 119 | return; 120 | 121 | try 122 | { 123 | var applicationPath = Assembly.GetExecutingAssembly().Location; 124 | var logfilePath = Path.Combine(Path.GetDirectoryName(applicationPath), 125 | Path.GetFileNameWithoutExtension(applicationPath) + ".log"); 126 | 127 | if (!_continue) 128 | { 129 | var assembly = Assembly.GetExecutingAssembly(); 130 | var copyright = assembly.GetCustomAttribute().Copyright; 131 | var version = assembly.GetName().Version; 132 | var build = assembly.GetCustomAttributes() 133 | .FirstOrDefault(attribute => attribute.Key == "Build")?.Value; 134 | var banner = new StringBuilder() 135 | .AppendLine(String.Format(Resources.ApplicationVersion, version, build)) 136 | .AppendLine($"{copyright.Replace("©", "(C)")}") 137 | .ToString(); 138 | 139 | if (!File.Exists(logfilePath) 140 | || new FileInfo(logfilePath).Length <= 0) 141 | File.AppendAllText(logfilePath, banner); 142 | 143 | File.AppendAllText(logfilePath, Environment.NewLine); 144 | } 145 | 146 | _continue = true; 147 | 148 | var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); 149 | var lines = message.ToString() 150 | .Split(new[] { Environment.NewLine }, StringSplitOptions.None) 151 | .ToArray(); 152 | 153 | Action logfileWriteLine = (line, followup) => 154 | { 155 | line = followup ? $" ... {line}" : line; 156 | File.AppendAllLines(logfilePath, new[] { $"{timestamp} {line}" }); 157 | }; 158 | 159 | if (lines.Length > 0) 160 | { 161 | if (lines[0] != _context) 162 | logfileWriteLine(lines[0], false); 163 | _context = lines[0]; 164 | for (var index = 1; index < lines.Length; index++) 165 | logfileWriteLine(lines[index], true); 166 | } 167 | } 168 | catch (Exception) 169 | { 170 | } 171 | } 172 | } 173 | } 174 | } -------------------------------------------------------------------------------- /platform/Sources/Program.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/platform/Sources/Program.ico -------------------------------------------------------------------------------- /platform/Sources/Resources.Extension.cs: -------------------------------------------------------------------------------- 1 | // LICENSE TERMS - Seanox Software Solutions is an open source project, 2 | // hereinafter referred to as Seanox Software Solutions or Seanox for short. 3 | // This software is subject to version 2 of the Apache License. 4 | // 5 | // Virtual Environment Platform 6 | // Creates, starts and controls a virtual environment. 7 | // Copyright (C) 2025 Seanox Software Solutions 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 10 | // use this file except in compliance with the License. You may obtain a copy of 11 | // the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | // License for the specific language governing permissions and limitations under 19 | // the License. 20 | 21 | using System.IO; 22 | using System.Reflection; 23 | using System.Text; 24 | using System.Text.RegularExpressions; 25 | 26 | namespace VirtualEnvironment.Platform 27 | { 28 | internal partial class Resources 29 | { 30 | internal static ResourceFiles Files { get; } = new ResourceFiles(); 31 | internal static ResourceTexts Texts { get; } = new ResourceTexts(); 32 | 33 | private static byte[] GetResource(string resourceName) 34 | { 35 | resourceName = $"{typeof(Resources).Namespace}.Resources.{resourceName}"; 36 | resourceName = new Regex("[\\./\\\\]+").Replace(resourceName, "."); 37 | resourceName = new Regex("\\s").Replace(resourceName, "_"); 38 | var assembly = Assembly.GetExecutingAssembly(); 39 | using (var stream = assembly.GetManifestResourceStream(resourceName)) 40 | using (var memoryStream = new MemoryStream()) 41 | { 42 | stream.CopyTo(memoryStream); 43 | return memoryStream.ToArray(); 44 | } 45 | } 46 | 47 | internal class ResourceFiles 48 | { 49 | internal byte[] this[string resourceName] => 50 | GetResource(resourceName); 51 | } 52 | 53 | internal class ResourceTexts 54 | { 55 | internal string this[string resourceName] => 56 | Encoding.UTF8.GetString(GetResource(resourceName)); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /platform/Sources/Settings.cs: -------------------------------------------------------------------------------- 1 | // LICENSE TERMS - Seanox Software Solutions is an open source project, 2 | // hereinafter referred to as Seanox Software Solutions or Seanox for short. 3 | // This software is subject to version 2 of the Apache License. 4 | // 5 | // Virtual Environment Platform 6 | // Creates, starts and controls a virtual environment. 7 | // Copyright (C) 2025 Seanox Software Solutions 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 10 | // use this file except in compliance with the License. You may obtain a copy of 11 | // the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | // License for the specific language governing permissions and limitations under 19 | // the License. 20 | 21 | using System; 22 | using System.Collections; 23 | using System.Collections.Generic; 24 | using System.IO; 25 | using System.Linq; 26 | using System.Reflection; 27 | using System.Runtime.InteropServices; 28 | using System.Text; 29 | using System.Text.RegularExpressions; 30 | 31 | namespace VirtualEnvironment.Platform 32 | { 33 | internal static class Settings 34 | { 35 | [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 36 | private static extern uint GetPrivateProfileString( 37 | string lpAppName, 38 | string lpKeyName, 39 | string lpDefault, 40 | StringBuilder lpReturnedString, 41 | uint nSize, 42 | string lpFileName); 43 | 44 | [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 45 | private static extern uint GetPrivateProfileSection( 46 | string lpAppName, 47 | StringBuilder lpReturnedString, 48 | uint nSize, 49 | string lpFileName); 50 | 51 | internal static readonly Dictionary Environment; 52 | 53 | internal static readonly HashSet Filesystem; 54 | 55 | internal static readonly HashSet Registry; 56 | 57 | internal static readonly HashSet Customs; 58 | 59 | private const string SECTION_ENVIRONMENT = "ENVIRONMENT"; 60 | private const string SECTION_FILESYSTEM = "FILESYSTEM"; 61 | private const string SECTION_REGISTRY = "REGISTRY"; 62 | private const string SECTION_CUSTOMS = "CUSTOMS"; 63 | 64 | private static readonly Regex PATTERN_PLACEHOLDER = 65 | new Regex(@"#\[\s*([a-z_](?:[\w\.\-]*[a-z0-9_])?)\s*\]", RegexOptions.IgnoreCase); 66 | 67 | static Settings() 68 | { 69 | Environment = new Dictionary(StringComparer.OrdinalIgnoreCase); 70 | foreach (DictionaryEntry entry in System.Environment.GetEnvironmentVariables()) 71 | Environment[(string)entry.Key] = (string)entry.Value; 72 | Filesystem = new HashSet(StringComparer.OrdinalIgnoreCase); 73 | Registry = new HashSet(StringComparer.OrdinalIgnoreCase); 74 | Customs = new HashSet(StringComparer.OrdinalIgnoreCase); 75 | 76 | var applicationPath = Assembly.GetExecutingAssembly().Location; 77 | var iniFilePath = Path.Combine(Path.GetDirectoryName(applicationPath), 78 | Path.GetFileNameWithoutExtension(applicationPath) + ".ini"); 79 | var iniFile = new FileInfo(iniFilePath); 80 | if (!iniFile.Exists) 81 | return; 82 | 83 | // With the exception of FILESYSTEM, placeholders and system 84 | // environment variables are replaced in the configuration values. 85 | // With FILESYSTEM, the environment variables remain unchanged as 86 | // they are required in the path for the storage. This serves both 87 | // to reduce the path length and to mask the drive letter. 88 | 89 | foreach (var key in GetSectionKeys(iniFile, SECTION_ENVIRONMENT)) 90 | Environment.Add(key, NormalizeValue(GetSectionKey(iniFile, SECTION_ENVIRONMENT, key))); 91 | foreach (var line in GetSectionLines(iniFile, SECTION_FILESYSTEM)) 92 | Filesystem.Add(NormalizeValuePlaceholder(line)); 93 | foreach (var line in GetSectionLines(iniFile, SECTION_REGISTRY)) 94 | Registry.Add(NormalizeValue(line)); 95 | foreach (var line in GetSectionLines(iniFile, SECTION_CUSTOMS)) 96 | Customs.Add(NormalizeValue(line)); 97 | } 98 | 99 | private static IEnumerable GetSectionKeys(FileInfo file, string section) 100 | { 101 | if (!file.Exists) 102 | return Array.Empty(); 103 | var buffer = new StringBuilder((int)file.Length); 104 | GetPrivateProfileString(section, null, null, buffer, (uint)buffer.Capacity, file.FullName); 105 | return buffer.ToString().Split(new[] { '\0' }, StringSplitOptions.RemoveEmptyEntries); 106 | } 107 | 108 | private static string GetSectionKey(FileInfo file, string section, string key, string defaultValue = "") 109 | { 110 | var result = new StringBuilder((int)file.Length); 111 | GetPrivateProfileString(section, key, defaultValue, result, (uint)result.Capacity, file.FullName); 112 | return result.ToString(); 113 | } 114 | 115 | private static IEnumerable GetSectionLines(FileInfo file, string section) 116 | { 117 | if (!file.Exists) 118 | return Array.Empty(); 119 | var buffer = new StringBuilder((int)file.Length); 120 | GetPrivateProfileSection(section, buffer, (uint)buffer.Capacity, file.FullName); 121 | return buffer.ToString() 122 | .Split(new[] { '\0' }, StringSplitOptions.RemoveEmptyEntries) 123 | .Select(line => line.Trim()) 124 | .Where(line => 125 | !String.IsNullOrEmpty(line) 126 | && !line.StartsWith(";")); 127 | } 128 | 129 | private static string NormalizeValuePlaceholder(string value) 130 | { 131 | return PATTERN_PLACEHOLDER.Replace(value, match => 132 | Environment.TryGetValue(match.Groups[1].Value, value: out var expression) 133 | ? expression : match.ToString()).Trim(); 134 | } 135 | 136 | private static string NormalizeValue(string value) 137 | { 138 | value = NormalizeValuePlaceholder(value); 139 | value = System.Environment.ExpandEnvironmentVariables(value).Trim(); 140 | return value; 141 | } 142 | } 143 | } -------------------------------------------------------------------------------- /platform/Sources/Worker.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualEnvironment.Platform 2 | { 3 | partial class Worker 4 | { 5 | private System.ComponentModel.IContainer components = null; 6 | 7 | protected override void Dispose(bool disposing) 8 | { 9 | if (disposing && (components != null)) 10 | { 11 | components.Dispose(); 12 | } 13 | base.Dispose(disposing); 14 | } 15 | 16 | #region Vom Windows Form-Designer generierter Code 17 | 18 | /// 19 | /// Required method for Designer support - do not modify 20 | /// the contents of this method with the code editor. 21 | /// 22 | private void InitializeComponent() 23 | { 24 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Worker)); 25 | this.PictureBox = new System.Windows.Forms.PictureBox(); 26 | this.Output = new System.Windows.Forms.Label(); 27 | this.Label = new System.Windows.Forms.Label(); 28 | this.Progress = new System.Windows.Forms.Label(); 29 | ((System.ComponentModel.ISupportInitialize)(this.PictureBox)).BeginInit(); 30 | this.SuspendLayout(); 31 | // 32 | // PictureBox 33 | // 34 | this.PictureBox.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("PictureBox.BackgroundImage"))); 35 | this.PictureBox.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; 36 | this.PictureBox.Location = new System.Drawing.Point(13, 13); 37 | this.PictureBox.Margin = new System.Windows.Forms.Padding(0); 38 | this.PictureBox.Name = "PictureBox"; 39 | this.PictureBox.Size = new System.Drawing.Size(72, 72); 40 | this.PictureBox.TabIndex = 0; 41 | this.PictureBox.TabStop = false; 42 | // 43 | // Output 44 | // 45 | this.Output.Location = new System.Drawing.Point(91, 13); 46 | this.Output.Margin = new System.Windows.Forms.Padding(0); 47 | this.Output.Name = "Output"; 48 | this.Output.Size = new System.Drawing.Size(300, 72); 49 | this.Output.TabIndex = 1; 50 | this.Output.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 51 | // 52 | // Label 53 | // 54 | this.Label.AutoSize = true; 55 | this.Label.ForeColor = System.Drawing.SystemColors.GrayText; 56 | this.Label.Location = new System.Drawing.Point(332, 79); 57 | this.Label.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); 58 | this.Label.Name = "Label"; 59 | this.Label.Size = new System.Drawing.Size(77, 17); 60 | this.Label.TabIndex = 2; 61 | this.Label.Text = "seanox.com"; 62 | this.Label.TextAlign = System.Drawing.ContentAlignment.MiddleRight; 63 | // 64 | // Progress 65 | // 66 | this.Progress.BackColor = System.Drawing.SystemColors.ControlDark; 67 | this.Progress.Location = new System.Drawing.Point(24, 85); 68 | this.Progress.Margin = new System.Windows.Forms.Padding(0); 69 | this.Progress.Name = "Progress"; 70 | this.Progress.Size = new System.Drawing.Size(50, 3); 71 | this.Progress.TabIndex = 3; 72 | this.Progress.Visible = false; 73 | // 74 | // Worker 75 | // 76 | this.AllowDrop = true; 77 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); 78 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 79 | this.BackColor = System.Drawing.SystemColors.Control; 80 | this.ClientSize = new System.Drawing.Size(400, 98); 81 | this.ControlBox = false; 82 | this.Controls.Add(this.Progress); 83 | this.Controls.Add(this.Label); 84 | this.Controls.Add(this.Output); 85 | this.Controls.Add(this.PictureBox); 86 | this.Font = new System.Drawing.Font("", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 87 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; 88 | this.Margin = new System.Windows.Forms.Padding(4); 89 | this.MaximizeBox = false; 90 | this.MinimizeBox = false; 91 | this.Name = "Worker"; 92 | this.ShowIcon = false; 93 | this.ShowInTaskbar = false; 94 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 95 | this.TopMost = true; 96 | ((System.ComponentModel.ISupportInitialize)(this.PictureBox)).EndInit(); 97 | this.ResumeLayout(false); 98 | this.PerformLayout(); 99 | } 100 | 101 | #endregion 102 | 103 | private System.Windows.Forms.PictureBox PictureBox; 104 | private System.Windows.Forms.Label Output; 105 | private System.Windows.Forms.Label Label; 106 | private System.Windows.Forms.Label Progress; 107 | } 108 | } -------------------------------------------------------------------------------- /resources/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/resources/example.gif -------------------------------------------------------------------------------- /resources/usage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/resources/usage.gif -------------------------------------------------------------------------------- /shiftdown/README.md: -------------------------------------------------------------------------------- 1 |

2 | 7 | 11 | 14 | 17 |

18 | 19 | __The tool was outsourced to a separate project. Please use 20 | https://github.com/seanox/process-balancer!__ 21 | 22 | 23 | 24 | # Process Balancer (formerly ShiftDown) 25 | 26 | My computer with i5 3rd generation (i5 3320M) suffers from the updates from 27 | Intel and Windows since Meltdown and Spectre were fixed. When the CPU is loaded, 28 | various IO interfaces have problems, e.g. access to USB devices and sound 29 | stutters. 30 | 31 | What helps is to reduce the priority of the processes that generate the load. 32 | 33 | With this in mind, I tried numerous prio tools and process managers, but none 34 | convinced me. 35 | 36 | Here now another attempt, which convinces at least me :-) 37 | 38 | The program does not need to be configured, as the functionality is very simple 39 | -- but you can configure it. 40 | 41 | There is a threshold (default value is 25%) for the maximum CPU load of the 42 | processes. If any processes exceed this threshold, their priority is first 43 | reduced to Idle and later increased to BelowNormal when the CPU load falls below 44 | the threshold -- the procedure has worked for me. 45 | 46 | If the program is ended, the original priority is restored. 47 | 48 | __Against to expectations, the program does not make the computer faster, but 49 | tries to improve multitasking so that all programs get enough CPU time, without 50 | application focus and bells and whistles, it's just to improve the work -- but I 51 | also got and considered your wishes.__ 52 | 53 | 54 | # Features 55 | - Threshold-based two-level down-prioritization of processes 56 | - Expanding down-prioritization to processes with the same name 57 | - Restoration of prioritization when the service is ended 58 | - Optional configuration of processes when prioritization is suspended 59 | - Optional configuration of processes that should always be prioritized down 60 | - Fast analysis and measurement of the cpu load of all processes 61 | - Low additional cpu load due to the service itself 62 | - Includes command line functions to install and uninstall the service, to 63 | start, pause, continue and stop the service 64 | - Logging for the Windows Event Viewer 65 | 66 | 67 | # System Requirement 68 | - Microsoft Windows 10 or higher 69 | - Microsoft .NET 4.8 or higher 70 | - [Microsoft .NET 4.8.x Developer Pack or higher]( 71 | https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48) (for development only) 72 | 73 | 74 | # Download 75 | [Seanox Process Balancer 1.3.3](https://github.com/seanox/process-balancer/releases/download/1.3.3/seanox-balancer-1.3.3.zip) 76 | 77 | 78 | # Usage 79 | The program is installed as a service, which requires administration privileges. 80 | 81 | ``` 82 | balancer.exe install 83 | balancer.exe uninstall 84 | ``` 85 | 86 | To update the program: Stop the service, replace the program file (exe) and then 87 | start the service again. 88 | 89 | The service supports start, pause, continue and stop. 90 | 91 | ``` 92 | balancer.exe start 93 | balancer.exe pause 94 | balancer.exe continue 95 | balancer.exe stop 96 | ``` 97 | 98 | When the program ends, the priority of the changed processes will be restored. 99 | 100 | 101 | # Configuration 102 | The program can optionally be configured via the enclosed XML file, which also 103 | describes the details. 104 | 105 | 106 | # Changes 107 | ## 1.3.3 20240218 108 | BF: Review: Optimization and corrections 109 | CR: Build: Releases are now only available on the release page 110 | CR: Project: Renaming in Balancer 111 | CR: Project: Outsourcing as a separate project 112 | CR: Project: Update TargetFrameworkVersion to v4.8 113 | 114 | [Read more](https://raw.githubusercontent.com/seanox/process-balancer/master/CHANGES) 115 | -------------------------------------------------------------------------------- /startup/.gitignore: -------------------------------------------------------------------------------- 1 | # Use the parent .gitignore 2 | -------------------------------------------------------------------------------- /startup/Build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Following targets are available: 5 | 6 | changes Synchronizes README.md with CHANGES 7 | 8 | release Builds the complete release 9 | Synchronizes the version in README.md 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 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 | 109 | 110 | 111 | 112 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 129 | 130 | 131 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 160 | 161 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /startup/CHANGES: -------------------------------------------------------------------------------- 1 | 1.2.4 20250701 2 | BF: StartUp: Optimization and corrections 3 | 4 | 1.2.3 20240302 5 | CR: Project: Updated TargetFrameworkVersion to v4.8 6 | CR: Platform: Refactoring of the standard directory structure 7 | 8 | 1.2.2 20220625 9 | BF: Build: Correction of the release info process 10 | 11 | 1.2.1 20220401 12 | BF: StartUp: Optimization and corrections 13 | CR: StartUp: Unification of namespace / platform icon / (sub) project structure 14 | CR: StartUp: Added build script/process via Ant 15 | 16 | 1.2.0 20211126 17 | CR: License: Changed to Apache License Version 2.0 18 | CR: Project: Change to .NET 19 | 20 | 1.1.0 20xxxxxx 21 | NT: No public release 22 | NT: More details have been lost 23 | 24 | 1.0.0 20xxxxxx 25 | NT: No public release 26 | NT: More details have been lost 27 | NT: Release is available 28 | -------------------------------------------------------------------------------- /startup/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Startup for Seanox Virtual Environment")] 8 | [assembly: AssemblyDescription("Starts batch scripts without a console window.")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Seanox Software Solutions")] 11 | [assembly: AssemblyProduct("Startup")] 12 | [assembly: AssemblyCopyright("Copyright © 0000 Seanox Software Solutions")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("131df921-4d19-4cdb-a6e0-784447653e7b")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("0.0.0")] 35 | [assembly: AssemblyFileVersion("0.0.0")] 36 | [assembly: AssemblyMetadata("Build", "00000000")] 37 | -------------------------------------------------------------------------------- /startup/README.md: -------------------------------------------------------------------------------- 1 | # Startup 2 | Startup is a simple background launcher for batch scripts. 3 | 4 | The program expects in the current working directory or in the program directory 5 | a batch file of the same name with the file extension cmd that it starts with a 6 | hidden console window and then waits until the end of the batch script. 7 | 8 | Renaming the startup program also changes the expected name of the batch script. 9 | 10 | Command-line arguments are supported and passed to the batch script. 11 | 12 | # System Requirement 13 | - Microsoft Windows 10 or higher 14 | - Microsoft .NET 4.8.x or higher (for runtime) 15 | - [Microsoft .NET 4.8.x Developer Pack or higher]( 16 | https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48) (for development only) 17 | 18 | # Download 19 | Startup is [part of the virtual environment](https://github.com/seanox/virtual-environment/tree/main/platform/Resources/platform/Programs/Platform) 20 | but can also be downloaded and used separately. 21 | 22 | https://github.com/seanox/virtual-environment/releases 23 | 24 | # Changes 25 | ## 1.2.3 20240302 26 | CR: Project: Updated TargetFrameworkVersion to v4.8 27 | CR: Platform: Refactoring of the standard directory structure 28 | 29 | [Read more](https://raw.githubusercontent.com/seanox/virtual-environment/master/startup/CHANGES) 30 | -------------------------------------------------------------------------------- /startup/Sources/Program.cs: -------------------------------------------------------------------------------- 1 | // LIZENZBEDINGUNGEN - Seanox Software Solutions ist ein Open-Source-Projekt, im 2 | // Folgenden Seanox Software Solutions oder kurz Seanox genannt. 3 | // Diese Software unterliegt der Version 2 der Apache License. 4 | // 5 | // Virtual Environment Startup 6 | // Starts a batch script with the same name minimized. 7 | // Copyright (C) 2025 Seanox Software Solutions 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 10 | // use this file except in compliance with the License. You may obtain a copy of 11 | // the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 17 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 18 | // License for the specific language governing permissions and limitations under 19 | // the License. 20 | 21 | using System; 22 | using System.Diagnostics; 23 | using System.IO; 24 | using System.Linq; 25 | using System.Reflection; 26 | using System.Windows.Forms; 27 | 28 | namespace VirtualEnvironment.Startup 29 | { 30 | internal static class Program 31 | { 32 | [STAThread] 33 | private static void Main(string[] arguments) 34 | { 35 | Application.EnableVisualStyles(); 36 | Application.SetCompatibleTextRenderingDefault(false); 37 | 38 | var applicationPath = Assembly.GetExecutingAssembly().Location; 39 | var applicationDirectory = Path.GetDirectoryName(applicationPath); 40 | var applicationName = Path.GetFileNameWithoutExtension(applicationPath); 41 | 42 | var scriptName = Path.GetFileNameWithoutExtension(applicationPath) + ".cmd"; 43 | var scriptFile = Path.Combine(applicationDirectory, scriptName); 44 | if (!File.Exists(scriptFile)) 45 | { 46 | MessageBox.Show($"The required {scriptName} file was not found", 47 | applicationName, 48 | MessageBoxButtons.OK, 49 | MessageBoxIcon.Stop); 50 | return; 51 | } 52 | 53 | if (new FileInfo(scriptFile).Length <= 0) 54 | return; 55 | 56 | var processStartInfo = new ProcessStartInfo() 57 | { 58 | UseShellExecute = true, 59 | CreateNoWindow = true, 60 | 61 | WindowStyle = ProcessWindowStyle.Hidden, 62 | 63 | FileName = scriptFile, 64 | WorkingDirectory = applicationDirectory, 65 | 66 | RedirectStandardError = false, 67 | RedirectStandardOutput = false, 68 | }; 69 | 70 | if (arguments?.Length > 0) 71 | processStartInfo.Arguments = String.Join(" ", 72 | arguments.Select(argument => argument.Replace("\"", "\"\"\""))); 73 | 74 | try 75 | { 76 | var process = new Process(); 77 | process.StartInfo = processStartInfo; 78 | process.Start(); 79 | } 80 | catch (Exception exception) 81 | { 82 | MessageBox.Show($"Program start has failed{System.Environment.NewLine}{exception.Message}", 83 | applicationName, 84 | MessageBoxButtons.OK, 85 | MessageBoxIcon.Error); 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /startup/Sources/Program.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seanox/virtual-environment/e2e5a953cd24ca0d511284392672a85ab62e4d5a/startup/Sources/Program.ico -------------------------------------------------------------------------------- /startup/Startup.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {131DF921-4D19-4CDB-A6E0-784447653E7B} 8 | WinExe 9 | VirtualEnvironment.Startup 10 | Startup 11 | v4.8 12 | 512 13 | true 14 | true 15 | Sources\Program.ico 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | Target\bin\Debug\ 23 | Target\obj\Debug\ 24 | Target\obj\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | false 29 | 30 | 31 | AnyCPU 32 | pdbonly 33 | true 34 | Target\bin\Release\ 35 | Target\obj\Release\ 36 | Target\obj\Release\ 37 | prompt 38 | 4 39 | false 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /startup/Startup.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Startup", "Startup.csproj", "{131DF921-4D19-4CDB-A6E0-784447653E7B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {131DF921-4D19-4CDB-A6E0-784447653E7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {131DF921-4D19-4CDB-A6E0-784447653E7B}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {131DF921-4D19-4CDB-A6E0-784447653E7B}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {131DF921-4D19-4CDB-A6E0-784447653E7B}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {B5BCA874-C6CA-458A-BB5F-31E09A1D56F3} 24 | EndGlobalSection 25 | EndGlobal 26 | --------------------------------------------------------------------------------