├── DeckyInstaller
├── app.manifest
├── DeckyInstaller.csproj
├── Program.cs
├── MainForm.Designer.cs
└── MainForm.cs
├── Decky-Loader-For-Windows.sln
├── README.md
└── PythonSetup.bat
/DeckyInstaller/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/DeckyInstaller/DeckyInstaller.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WinExe
6 | net7.0-windows
7 | enable
8 | true
9 | enable
10 | app.manifest
11 | Decky Loader Installer
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/DeckyInstaller/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Principal;
3 | using System.Windows.Forms;
4 |
5 | namespace DeckyInstaller
6 | {
7 | internal static class Program
8 | {
9 | [STAThread]
10 | static void Main()
11 | {
12 | // Check for admin privileges
13 | if (!IsAdministrator())
14 | {
15 | MessageBox.Show(
16 | "This application requires administrator privileges to create the required files.",
17 | "Administrator Rights Required",
18 | MessageBoxButtons.OK,
19 | MessageBoxIcon.Warning
20 | );
21 | return;
22 | }
23 |
24 | ApplicationConfiguration.Initialize();
25 | Application.Run(new MainForm());
26 | }
27 |
28 | private static bool IsAdministrator()
29 | {
30 | var identity = WindowsIdentity.GetCurrent();
31 | var principal = new WindowsPrincipal(identity);
32 | return principal.IsInRole(WindowsBuiltInRole.Administrator);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Decky-Loader-For-Windows.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.5.002.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeckyInstaller", "DeckyInstaller\DeckyInstaller.csproj", "{6D87E13D-7D09-473A-938D-F625D91AB709}"
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 | {6D87E13D-7D09-473A-938D-F625D91AB709}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {6D87E13D-7D09-473A-938D-F625D91AB709}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {6D87E13D-7D09-473A-938D-F625D91AB709}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {6D87E13D-7D09-473A-938D-F625D91AB709}.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 = {500B9C03-87F3-41AE-BB6D-A061C5BA77AC}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Decky Loader for Windows
2 |
3 | A Work-in-progress installer for Decky Loader on Windows. This tool automates the process of downloading and configuring Decky Loader - bringing the Steam Deck's popular plugin system to Windows.
4 |
5 | ## ⚠️ Disclaimer
6 |
7 | **This is an unofficial project and is not affiliated with, endorsed, or supported by the official Decky Loader team.**
8 | **No support will be provided by the Decky Loader team for any Windows Decky installations or Decky installations performed using this installer.**
9 |
10 | ## Featurer
11 |
12 | - 🚀 1-Click installation
13 | - 🔧 Configures Steam for plugin development (-dev arg)
14 | - 🏃♂️ Sets up autostart for PluginLoader
15 | - 📁 Creates proper homebrew directory structure
16 | - 💻 Installs console and GUI executables
17 |
18 | ## Working Plugins on Windows
19 |
20 | - Audio Loader
21 | - CSS Loader
22 | - IsThereAnyDeal For Deck
23 | - PlayCount
24 | - PlayTime
25 | - ProtonDB Badges
26 | - SteamGridDB
27 | - TabMaster
28 | - Web Browser
29 |
30 | ## Requirements
31 |
32 | - Windows 10/11
33 | - Steam installation
34 | - Internet connection
35 |
36 | ## Usage
37 |
38 | Download the latest release and run "Decky Loader Installer.exe",
39 |
40 | ## Millennium Project
41 |
42 |
43 |
44 | The `millennium` project is progressing nicely and works in conjunction with Decky Loader. It's definitely a project to keep an eye on!
45 |
--------------------------------------------------------------------------------
/PythonSetup.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | echo Checking dependencies for Decky Loader...
3 | echo.
4 |
5 | :: Check if Python is installed
6 | python --version >nul 2>&1
7 | if %errorlevel% neq 0 (
8 | echo Python is not installed. Downloading Python installer...
9 | curl -L "https://www.python.org/ftp/python/3.11.8/python-3.11.8-amd64.exe" --output "%temp%\python-installer.exe"
10 |
11 | :: Check if download was successful
12 | if not exist "%temp%\python-installer.exe" (
13 | echo Failed to download Python installer. Please check your internet connection and try again.
14 | pause
15 | exit /b 1
16 | )
17 |
18 | :: Check file size to ensure proper download
19 | for %%I in ("%temp%\python-installer.exe") do if %%~zI LSS 1000000 (
20 | echo Downloaded file seems too small. Download may have failed.
21 | del "%temp%\python-installer.exe"
22 | pause
23 | exit /b 1
24 | )
25 |
26 | echo Installing Python...
27 | "%temp%\python-installer.exe" /quiet InstallAllUsers=1 PrependPath=1 Include_test=0 Include_pip=1
28 |
29 | :: Wait a moment for installation to complete
30 | timeout /t 5 /nobreak > nul
31 |
32 | :: Clean up
33 | del "%temp%\python-installer.exe"
34 |
35 | :: Refresh environment variables using PowerShell
36 | echo Refreshing environment variables...
37 | powershell -Command "$env:Path = [System.Environment]::GetEnvironmentVariable('Path','Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path','User')"
38 |
39 | :: Also set for current session
40 | for /f "tokens=*" %%a in ('powershell -Command "[System.Environment]::GetEnvironmentVariable('Path','Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path','User')"') do set "PATH=%%a"
41 | ) else (
42 | echo Python is already installed.
43 | )
44 |
45 | :: Verify installations
46 | echo.
47 | echo Verifying installations...
48 | python --version
49 | if errorlevel 1 (
50 | echo Python installation may have failed or PATH is not updated.
51 | echo Please restart your computer and run this script again.
52 | ) else (
53 | echo Python installation successful!
54 | )
55 | echo.
56 | echo Setup complete! You can now run the Decky Loader installer.
57 | pause
--------------------------------------------------------------------------------
/DeckyInstaller/MainForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace DeckyInstaller
2 | {
3 | partial class MainForm
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 | private void InitializeComponent()
17 | {
18 | components = new System.ComponentModel.Container();
19 | btnInstall = new Button();
20 | progressBar = new ProgressBar();
21 | lblStatus = new Label();
22 | txtOutput = new TextBox();
23 | SuspendLayout();
24 |
25 | // Form-wide styles
26 | this.BackColor = Color.FromArgb(24, 24, 24);
27 | this.ForeColor = Color.FromArgb(240, 240, 240);
28 | this.Font = new Font("Segoe UI", 9.75F, FontStyle.Regular, GraphicsUnit.Point);
29 |
30 | // btnInstall
31 | btnInstall.BackColor = Color.FromArgb(0, 120, 215);
32 | btnInstall.FlatStyle = FlatStyle.Flat;
33 | btnInstall.FlatAppearance.BorderSize = 0;
34 | btnInstall.Font = new Font("Segoe UI", 10.2F, FontStyle.Bold, GraphicsUnit.Point);
35 | btnInstall.ForeColor = Color.White;
36 | btnInstall.Location = new Point(20, 20);
37 | btnInstall.Name = "btnInstall";
38 | btnInstall.Size = new Size(460, 45);
39 | btnInstall.TabIndex = 0;
40 | btnInstall.Text = "Install Decky Loader";
41 | btnInstall.UseVisualStyleBackColor = false;
42 | btnInstall.Cursor = Cursors.Hand;
43 | btnInstall.Click += btnInstall_Click;
44 |
45 | // progressBar
46 | progressBar.Location = new Point(20, 75);
47 | progressBar.Name = "progressBar";
48 | progressBar.Size = new Size(460, 5);
49 | progressBar.Style = ProgressBarStyle.Continuous;
50 | progressBar.TabIndex = 1;
51 | progressBar.ForeColor = Color.FromArgb(0, 120, 215);
52 | progressBar.BackColor = Color.FromArgb(45, 45, 45);
53 |
54 | // lblStatus
55 | lblStatus.AutoSize = true;
56 | lblStatus.Location = new Point(20, 90);
57 | lblStatus.Name = "lblStatus";
58 | lblStatus.Size = new Size(89, 17);
59 | lblStatus.TabIndex = 2;
60 | lblStatus.Text = "Ready to install...";
61 | lblStatus.ForeColor = Color.FromArgb(200, 200, 200);
62 |
63 | // txtOutput
64 | txtOutput.BackColor = Color.FromArgb(30, 30, 30);
65 | txtOutput.ForeColor = Color.FromArgb(220, 220, 220);
66 | txtOutput.Font = new Font("Cascadia Code", 9F, FontStyle.Regular, GraphicsUnit.Point);
67 | txtOutput.Location = new Point(20, 115);
68 | txtOutput.Multiline = true;
69 | txtOutput.Name = "txtOutput";
70 | txtOutput.ReadOnly = true;
71 | txtOutput.ScrollBars = ScrollBars.Both;
72 | txtOutput.Size = new Size(460, 215);
73 | txtOutput.TabIndex = 3;
74 | txtOutput.WordWrap = false;
75 | txtOutput.BorderStyle = BorderStyle.None;
76 | txtOutput.Padding = new Padding(5);
77 |
78 | // MainForm
79 | AutoScaleDimensions = new SizeF(7F, 17F);
80 | AutoScaleMode = AutoScaleMode.Font;
81 | ClientSize = new Size(500, 350);
82 | Controls.Add(txtOutput);
83 | Controls.Add(lblStatus);
84 | Controls.Add(progressBar);
85 | Controls.Add(btnInstall);
86 | FormBorderStyle = FormBorderStyle.FixedSingle;
87 | MaximizeBox = false;
88 | Name = "MainForm";
89 | StartPosition = FormStartPosition.CenterScreen;
90 | Text = "Decky Loader Installer";
91 | Load += MainForm_Load;
92 | Padding = new Padding(20);
93 | ResumeLayout(false);
94 | PerformLayout();
95 | }
96 |
97 | protected Button btnInstall;
98 | protected ProgressBar progressBar;
99 | protected Label lblStatus;
100 | protected TextBox txtOutput;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/DeckyInstaller/MainForm.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Net.Http;
3 | using Microsoft.Win32;
4 | using System.IO.Compression;
5 | using System.Text.RegularExpressions;
6 |
7 | namespace DeckyInstaller
8 | {
9 | public partial class MainForm : Form
10 | {
11 | private bool _isInstalling = false;
12 | private const string DOWNLOAD_URL = "https://nightly.link/SteamDeckHomebrew/decky-loader/workflows/build-win/main/PluginLoader%20Win.zip";
13 |
14 | private readonly HttpClient _httpClient;
15 |
16 | public MainForm()
17 | {
18 | InitializeComponent();
19 | _httpClient = new HttpClient();
20 | _httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
21 | }
22 |
23 | private void MainForm_Load(object sender, EventArgs e)
24 | {
25 | txtOutput.AppendText("Ready to install Decky Loader...\r\n");
26 | }
27 |
28 | private async void btnInstall_Click(object sender, EventArgs e)
29 | {
30 | if (_isInstalling) return;
31 | await StartInstallation();
32 | }
33 |
34 | public async Task StartInstallation()
35 | {
36 | _isInstalling = true;
37 | btnInstall.Enabled = false;
38 | progressBar.Value = 0;
39 | progressBar.Maximum = 6;
40 | txtOutput.Clear();
41 |
42 | try
43 | {
44 | // Kill any existing PluginLoader processes
45 | KillExistingPluginLoaders();
46 |
47 | // Step 1: Create .cef-enable-remote-debugging file
48 | UpdateStatus("Setting up Steam CEF debugging...");
49 | if (!await SetupSteamDebug())
50 | {
51 | throw new Exception("Failed to setup Steam CEF debugging");
52 | }
53 | progressBar.Value++;
54 |
55 | // Step 2: Create homebrew directories
56 | UpdateStatus("Creating homebrew directories...");
57 | if (!await CreateHomebrewDirectories())
58 | {
59 | throw new Exception("Failed to create homebrew directories");
60 | }
61 | progressBar.Value++;
62 |
63 | // Step 3: Download and extract
64 | UpdateStatus("Downloading latest build...");
65 | string zipPath = Path.Combine(Path.GetTempPath(), "PluginLoader.zip");
66 |
67 | // Download the zip file
68 | var zipBytes = await _httpClient.GetByteArrayAsync(DOWNLOAD_URL);
69 | await File.WriteAllBytesAsync(zipPath, zipBytes);
70 | progressBar.Value++;
71 |
72 | // Step 4: Extract files
73 | UpdateStatus("Extracting files...");
74 | string servicesDir = Path.Combine(
75 | Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
76 | "homebrew",
77 | "services"
78 | );
79 | ZipFile.ExtractToDirectory(zipPath, servicesDir, true);
80 | progressBar.Value++;
81 |
82 | // Step 5: Create Steam shortcut
83 | UpdateStatus("Creating Steam shortcut...");
84 | if (!CreateSteamShortcut())
85 | {
86 | throw new Exception("Failed to create Steam shortcut");
87 | }
88 | progressBar.Value++;
89 |
90 | // Step 6: Setup autostart
91 | UpdateStatus("Setting up autostart...");
92 | if (!SetupAutostart())
93 | {
94 | throw new Exception("Failed to setup autostart");
95 | }
96 | progressBar.Value++;
97 |
98 | // Cleanup
99 | try { File.Delete(zipPath); } catch { }
100 |
101 | UpdateStatus("Installation complete!");
102 | MessageBox.Show(
103 | "Decky Loader has been installed successfully!\n\n" +
104 | "1. Close Steam if it's running\n" +
105 | "2. Use the new Steam shortcut on your desktop to launch Steam\n" +
106 | "3. In Big Picture Mode, press the STEAM button + A to access the Decky menu",
107 | "Installation Complete",
108 | MessageBoxButtons.OK,
109 | MessageBoxIcon.Information
110 | );
111 | }
112 | catch (Exception ex)
113 | {
114 | UpdateStatus($"Error: {ex.Message}");
115 | MessageBox.Show(
116 | $"An error occurred: {ex.Message}",
117 | "Error",
118 | MessageBoxButtons.OK,
119 | MessageBoxIcon.Error
120 | );
121 | }
122 | finally
123 | {
124 | _isInstalling = false;
125 | btnInstall.Enabled = true;
126 | }
127 | }
128 |
129 | private bool CreateSteamShortcut()
130 | {
131 | try
132 | {
133 | string? steamPath = null;
134 | string steamExe;
135 |
136 | // Try to find Steam installation path from registry
137 | try
138 | {
139 | using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Valve\Steam");
140 | steamPath = key?.GetValue("InstallPath") as string;
141 | }
142 | catch
143 | {
144 | try
145 | {
146 | using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Valve\Steam");
147 | steamPath = key?.GetValue("InstallPath") as string;
148 | }
149 | catch { }
150 | }
151 |
152 | if (string.IsNullOrEmpty(steamPath))
153 | {
154 | steamPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Steam");
155 | }
156 |
157 | steamExe = Path.Combine(steamPath, "steam.exe");
158 | if (!File.Exists(steamExe))
159 | {
160 | throw new Exception("Steam executable not found");
161 | }
162 |
163 | // Create desktop shortcut using PowerShell
164 | string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
165 | string shortcutPath = Path.Combine(desktopPath, "Steam (Decky).lnk");
166 |
167 | string psCommand = $@"$WshShell = New-Object -ComObject WScript.Shell; " +
168 | $@"$Shortcut = $WshShell.CreateShortcut('{shortcutPath}'); " +
169 | $@"$Shortcut.TargetPath = '{steamExe}'; " +
170 | $@"$Shortcut.Arguments = '-dev'; " +
171 | $@"$Shortcut.WorkingDirectory = '{steamPath}'; " +
172 | $@"$Shortcut.Description = 'Launch Steam with Decky Loader'; " +
173 | "$Shortcut.Save()";
174 |
175 | var startInfo = new ProcessStartInfo
176 | {
177 | FileName = "powershell.exe",
178 | Arguments = $"-Command \"{psCommand}\"",
179 | UseShellExecute = false,
180 | RedirectStandardOutput = true,
181 | RedirectStandardError = true,
182 | CreateNoWindow = true
183 | };
184 |
185 | using var process = Process.Start(startInfo);
186 | process?.WaitForExit();
187 |
188 | if (process?.ExitCode == 0)
189 | {
190 | AppendOutput("Created Steam shortcut with -dev parameter");
191 | return true;
192 | }
193 | else
194 | {
195 | throw new Exception("Failed to create shortcut");
196 | }
197 | }
198 | catch (Exception ex)
199 | {
200 | AppendOutput($"Error creating Steam shortcut: {ex.Message}");
201 | return false;
202 | }
203 | }
204 |
205 | private bool SetupAutostart()
206 | {
207 | try
208 | {
209 | string servicesDir = Path.Combine(
210 | Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
211 | "homebrew",
212 | "services"
213 | );
214 | string pluginLoader = Path.Combine(servicesDir, "PluginLoader_noconsole.exe");
215 |
216 | if (!File.Exists(pluginLoader))
217 | {
218 | throw new Exception("PluginLoader_noconsole.exe not found");
219 | }
220 |
221 | // Create startup shortcut
222 | string startupFolder = Path.Combine(
223 | Environment.GetFolderPath(Environment.SpecialFolder.Startup)
224 | );
225 | string shortcutPath = Path.Combine(startupFolder, "Decky Loader.lnk");
226 |
227 | string psCommand = $@"$WshShell = New-Object -ComObject WScript.Shell; " +
228 | $@"$Shortcut = $WshShell.CreateShortcut('{shortcutPath}'); " +
229 | $@"$Shortcut.TargetPath = '{pluginLoader}'; " +
230 | $@"$Shortcut.WorkingDirectory = '{servicesDir}'; " +
231 | $@"$Shortcut.Description = 'Decky Loader Autostart'; " +
232 | "$Shortcut.Save()";
233 |
234 | var startInfo = new ProcessStartInfo
235 | {
236 | FileName = "powershell.exe",
237 | Arguments = $"-Command \"{psCommand}\"",
238 | UseShellExecute = false,
239 | RedirectStandardOutput = true,
240 | RedirectStandardError = true,
241 | CreateNoWindow = true
242 | };
243 |
244 | using var process = Process.Start(startInfo);
245 | process?.WaitForExit();
246 |
247 | if (process?.ExitCode == 0)
248 | {
249 | AppendOutput("Created autostart entry");
250 |
251 | // Start the process immediately
252 | var pluginLoaderProcess = new ProcessStartInfo
253 | {
254 | FileName = pluginLoader,
255 | WorkingDirectory = servicesDir,
256 | UseShellExecute = true
257 | };
258 | Process.Start(pluginLoaderProcess);
259 | AppendOutput("Started PluginLoader_noconsole.exe");
260 |
261 | return true;
262 | }
263 | else
264 | {
265 | throw new Exception("Failed to create autostart entry");
266 | }
267 | }
268 | catch (Exception ex)
269 | {
270 | AppendOutput($"Error setting up autostart: {ex.Message}");
271 | return false;
272 | }
273 | }
274 |
275 | private async Task SetupSteamDebug()
276 | {
277 | try
278 | {
279 | string? steamPath = null;
280 |
281 | // Try to find Steam installation path from registry
282 | try
283 | {
284 | using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Valve\Steam");
285 | steamPath = key?.GetValue("InstallPath") as string;
286 | }
287 | catch
288 | {
289 | try
290 | {
291 | using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Valve\Steam");
292 | steamPath = key?.GetValue("InstallPath") as string;
293 | }
294 | catch
295 | {
296 | AppendOutput("Steam installation not found in registry");
297 | }
298 | }
299 |
300 | if (string.IsNullOrEmpty(steamPath))
301 | {
302 | steamPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Steam");
303 | }
304 |
305 | if (!Directory.Exists(steamPath))
306 | {
307 | throw new Exception("Steam installation directory not found");
308 | }
309 |
310 | string debugFile = Path.Combine(steamPath, ".cef-enable-remote-debugging");
311 | File.WriteAllText(debugFile, "");
312 | AppendOutput("Created .cef-enable-remote-debugging file");
313 |
314 | return true;
315 | }
316 | catch (Exception ex)
317 | {
318 | AppendOutput($"Error setting up Steam debug: {ex.Message}");
319 | return false;
320 | }
321 | }
322 |
323 | private async Task CreateHomebrewDirectories()
324 | {
325 | try
326 | {
327 | string homebrewDir = Path.Combine(
328 | Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
329 | "homebrew"
330 | );
331 | string servicesDir = Path.Combine(homebrewDir, "services");
332 |
333 | Directory.CreateDirectory(homebrewDir);
334 | Directory.CreateDirectory(servicesDir);
335 |
336 | AppendOutput($"Created directory: {homebrewDir}");
337 | AppendOutput($"Created directory: {servicesDir}");
338 |
339 | return true;
340 | }
341 | catch (Exception ex)
342 | {
343 | AppendOutput($"Error creating directories: {ex.Message}");
344 | return false;
345 | }
346 | }
347 |
348 | private void KillExistingPluginLoaders()
349 | {
350 | try
351 | {
352 | foreach (var process in Process.GetProcessesByName("PluginLoader"))
353 | {
354 | try
355 | {
356 | process.Kill();
357 | AppendOutput("Terminated PluginLoader.exe process");
358 | }
359 | catch (Exception ex)
360 | {
361 | AppendOutput($"Warning: Could not terminate PluginLoader.exe: {ex.Message}");
362 | }
363 | }
364 |
365 | foreach (var process in Process.GetProcessesByName("PluginLoader_noconsole"))
366 | {
367 | try
368 | {
369 | process.Kill();
370 | AppendOutput("Terminated PluginLoader_noconsole.exe process");
371 | }
372 | catch (Exception ex)
373 | {
374 | AppendOutput($"Warning: Could not terminate PluginLoader_noconsole.exe: {ex.Message}");
375 | }
376 | }
377 | }
378 | catch (Exception ex)
379 | {
380 | AppendOutput($"Warning: Error while checking for existing processes: {ex.Message}");
381 | }
382 | }
383 |
384 | private void UpdateStatus(string message)
385 | {
386 | if (InvokeRequired)
387 | {
388 | Invoke(new Action(() => UpdateStatus(message)));
389 | return;
390 | }
391 |
392 | lblStatus.Text = message;
393 | lblStatus.Refresh();
394 | }
395 |
396 | private void AppendOutput(string text)
397 | {
398 | if (txtOutput.InvokeRequired)
399 | {
400 | txtOutput.Invoke(new Action(() => AppendOutput(text)));
401 | }
402 | else
403 | {
404 | txtOutput.AppendText($"{text}\r\n");
405 | txtOutput.SelectionStart = txtOutput.TextLength;
406 | txtOutput.ScrollToCaret();
407 | }
408 | }
409 | }
410 | }
411 |
--------------------------------------------------------------------------------