From 3402261d67a39b5c031dc1cf7c476e532afb213f Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Sat, 12 Jul 2025 16:54:17 +0800 Subject: [PATCH 01/14] halfway --- Program.cs | 219 +++++++++++++++++++++++-------------- Properties/AssemblyInfo.cs | 36 ------ WinToLinux.csproj | 95 +++------------- WinToLinux.sln | 25 ----- WinToLinux.slnx | 3 + packages.config | 4 - 6 files changed, 156 insertions(+), 226 deletions(-) delete mode 100644 Properties/AssemblyInfo.cs delete mode 100644 WinToLinux.sln create mode 100644 WinToLinux.slnx delete mode 100644 packages.config diff --git a/Program.cs b/Program.cs index 287e0db..a81cbcb 100644 --- a/Program.cs +++ b/Program.cs @@ -17,12 +17,13 @@ public static void Main() } private readonly NotifyIcon trayIcon; - private readonly ContextMenu trayMenu; + // TODO ContextMenu is no longer supported. Use ContextMenuStrip instead. For more details see https://docs.microsoft.com/en-us/dotnet/core/compatibility/winforms#removed-controls + private readonly ContextMenuStrip trayMenu; private readonly string appName = "WinToLinux"; List uefi = new List(); List uuid = new List(); - string bootsequence; + string bootSequence; string currentValue; int shift; readonly Regex regexUUID = new Regex("^(\\{){0,1}[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}(\\}){0,1}$"); @@ -31,46 +32,54 @@ public SysTrayApp() { GetMenuItems(); - currentValue = bootsequence ?? uuid.First(); + currentValue = bootSequence ?? uuid.First(); shift = uuid.Count() - uefi.Count(); // Create a simple tray menu with only one item. - trayMenu = new ContextMenu(); - trayMenu.MenuItems.Add("Settings").Enabled = false; - trayMenu.MenuItems.Add("-"); - trayMenu.MenuItems.Add("Start with system", OnRegisterInStartup).Checked = isTaskEnable(); - trayMenu.MenuItems.Add("-"); - trayMenu.MenuItems.Add("Reboot to...").Enabled = false; - trayMenu.MenuItems.Add("-"); + trayMenu = new ContextMenuStrip(); + trayMenu.Items.Add("Settings").Enabled = false; + trayMenu.Items.Add("-"); + + var startButton = new ToolStripMenuItem("Start with system"); + startButton.Checked = IsTaskEnabled(); + startButton.Click += OnRegisterInStartup; + trayMenu.Items.Add(startButton); + + trayMenu.Items.Add("-"); + trayMenu.Items.Add("Reboot to...").Enabled = false; + trayMenu.Items.Add("-"); foreach (var pos in uefi.Select((value, i) => new { i, value })) { - MenuItem item = new MenuItem - { - Checked = uuid[pos.i + shift] == currentValue, - Tag = uuid[pos.i + shift], + var item = new ToolStripMenuItem { + CheckOnClick = true, + Tag = pos.i + shift < uuid.Count ? uuid[pos.i + shift] : string.Empty, Text = pos.value }; item.Click += OnMenuClick; - trayMenu.MenuItems.Add(item); + trayMenu.Items.Add(item); } - trayMenu.MenuItems.Add("-"); - trayMenu.MenuItems.Add("Reboot system", OnReboot); - trayMenu.MenuItems.Add("-"); - trayMenu.MenuItems.Add("Exit", OnExit); + // Set the initial radio button selection + SetRadioButtonSelection(currentValue); + + trayMenu.Items.Add("-"); + trayMenu.Items.Add("Reboot system", null, OnReboot); + trayMenu.Items.Add("-"); + trayMenu.Items.Add("Exit", null, OnExit); // Create a tray icon. In this example we use a // standard system icon for simplicity, but you // can of course use your own custom icon too. + // TODO ContextMenu is no longer supported. Use ContextMenuStrip instead. For more details see https://docs.microsoft.com/en-us/dotnet/core/compatibility/winforms#removed-controls trayIcon = new NotifyIcon { Text = "Reboot to Linux", Icon = WinToLinux.Properties.Resources.WtL, // Add menu to tray icon and show it. - ContextMenu = trayMenu, + ContextMenuStrip = trayMenu, Visible = true }; } @@ -83,30 +92,64 @@ private void OnExit(object sender, EventArgs e) private void OnMenuClick(object sender, EventArgs e) { - string UUID = (sender as MenuItem).Tag.ToString(); - string command = "/C bcdedit.exe /set {fwbootmgr} bootsequence " + UUID + " /addfirst"; + if (sender is not ToolStripMenuItem clickedItem || clickedItem.Tag is not string uuid) + return; + + // Set the boot sequence + string command = $"/C bcdedit.exe /set {{fwbootmgr}} bootsequence {uuid} /addfirst"; Console.WriteLine(command); LaunchCMD(command); - uuid = new List(); - uefi = new List(); + // Update the radio button selection + SetRadioButtonSelection(uuid); - LaunchCMD("/C bcdedit /enum firmware"); + // Update the current value + currentValue = uuid; + } + private void SetRadioButtonSelection(string selectedUuid) + { + // First, uncheck all boot option menu items + for (int i = 6; i < trayMenu.Items.Count - 3; i++) // Skip fixed items at start and end + { + if (trayMenu.Items[i] is ToolStripMenuItem item && item.Tag is string) + { + item.Checked = false; + } + } - currentValue = bootsequence ?? uuid.First(); - shift = uuid.Count() - uefi.Count(); - foreach (var pos in uefi.Select((value, i) => new { i, value })) + // Then check the selected item + for (int i = 6; i < trayMenu.Items.Count - 3; i++) { - trayMenu.MenuItems[pos.i + 6].Checked = uuid[pos.i + shift] == currentValue; + if (trayMenu.Items[i] is ToolStripMenuItem item && + item.Tag is string itemUUID && + itemUUID == selectedUuid + ) + { + item.Checked = true; + break; + } } } + private void RefreshMenuItems() + { + uuid.Clear(); + uefi.Clear(); + LaunchCMD("/C bcdedit /enum firmware"); + + currentValue = bootSequence ?? (uuid.Count > 0 ? uuid.First() : string.Empty); + shift = uuid.Count - uefi.Count; + + // Update radio button selection + SetRadioButtonSelection(currentValue); + } private void CreateTask() { - using (TaskService ts = new TaskService()) + try { - TaskDefinition td = ts.NewTask(); + using var ts = new TaskService(); + var td = ts.NewTask(); td.RegistrationInfo.Description = "WinToLinux. Start on boot"; td.Triggers.Add(new LogonTrigger()); @@ -120,38 +163,41 @@ private void CreateTask() ts.RootFolder.RegisterTaskDefinition(appName, td); } + catch (Exception ex) + { + MessageBox.Show($"Error creating startup task: {ex.Message}", "Error", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } } private void DeleteTask() { - using (TaskService ts = new TaskService()) + using var ts = new TaskService(); + if (ts.GetTask(appName) != null) { - if (ts.GetTask(appName) != null) - { - ts.RootFolder.DeleteTask(appName); - } + ts.RootFolder.DeleteTask(appName); } } - private bool isTaskEnable() + private bool IsTaskEnabled() { - using (TaskService ts = new TaskService()) - { - return (ts.GetTask(appName) != null); - } + using var ts = new TaskService(); + return ts.GetTask(appName) != null; } private void OnRegisterInStartup(object sender, EventArgs e) { - if (isTaskEnable()) + if (IsTaskEnabled()) { DeleteTask(); - trayMenu.MenuItems[2].Checked = false; + if (trayMenu.Items[2] is ToolStripMenuItem item) + item.Checked = false; } else { CreateTask(); - trayMenu.MenuItems[2].Checked = true; + if (trayMenu.Items[2] is ToolStripMenuItem item) + item.Checked = true; } } @@ -167,50 +213,60 @@ private void GetMenuItems() private void LaunchCMD(string command) { - Process build = new Process(); - build.StartInfo.Arguments = command; - build.StartInfo.FileName = "cmd.exe"; - - build.StartInfo.UseShellExecute = false; - build.StartInfo.RedirectStandardOutput = true; - build.StartInfo.RedirectStandardError = true; - build.StartInfo.CreateNoWindow = true; - build.ErrorDataReceived += Build_ErrorAndDataReceived; - build.OutputDataReceived += Build_ErrorAndDataReceived; - build.EnableRaisingEvents = true; - build.Start(); - build.BeginOutputReadLine(); - build.BeginErrorReadLine(); - build.WaitForExit(); + try + { + using var process = new Process(); + process.StartInfo.Arguments = command; + process.StartInfo.FileName = "cmd.exe"; + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.CreateNoWindow = true; + + process.ErrorDataReceived += Build_ErrorAndDataReceived; + process.OutputDataReceived += Build_ErrorAndDataReceived; + process.EnableRaisingEvents = true; + + process.Start(); + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + process.WaitForExit(); + } + catch (Exception ex) + { + Console.WriteLine($"Error executing command: {ex.Message}"); + } } void Build_ErrorAndDataReceived(object sender, DataReceivedEventArgs e) { - if (e.Data != null && e.Data != "") - { - string strMessage = e.Data; - string[] splited = strMessage.Split(' '); - splited = splited.Where(address => !string.IsNullOrWhiteSpace(address)).ToArray(); - Match match = regexUUID.Match(splited.Last()); + if (string.IsNullOrEmpty(e.Data)) + return; - if (splited[0] == "description") - { - splited = splited.Where(w => w != splited[0]).ToArray(); - Console.WriteLine(String.Join(" ", splited)); - uefi.Add(String.Join(" ", splited)); - } + string strMessage = e.Data; + string[] splitMsg = strMessage.Split(' ', StringSplitOptions.RemoveEmptyEntries); - if (splited[0] == "bootsequence") - { - Console.Write(splited.Last()); - bootsequence = splited.Last(); - } + if (splitMsg.Length == 0) + return; - if (splited[0] != "resumeobject" && splited[0] != "bootsequence" && match.Success || splited.Last() == "{bootmgr}") - { - Console.Write(splited.Last()); - uuid.Add(splited.Last()); - } + var match = regexUUID.Match(splitMsg.Last()); + + if (splitMsg[0] == "description") + { + var description = string.Join(" ", splitMsg.Skip(1)); + Console.WriteLine(description); + uefi.Add(description); + } + else if (splitMsg[0] == "bootsequence") + { + Console.Write(splitMsg.Last()); + bootSequence = splitMsg.Last(); + } + else if (splitMsg[0] != "resumeobject" && splitMsg[0] != "bootsequence" && + (match.Success || splitMsg.Last() == "{bootmgr}")) + { + Console.Write(splitMsg.Last()); + uuid.Add(splitMsg.Last()); } } @@ -230,6 +286,7 @@ protected override void Dispose(bool isDisposing) { // Release the icon resource. trayIcon.Dispose(); + trayMenu?.Dispose(); } base.Dispose(isDisposing); diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs deleted file mode 100644 index 686a265..0000000 --- a/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// Общие сведения об этой сборке предоставляются следующим набором -// набора атрибутов. Измените значения этих атрибутов для изменения сведений, -// связанных со сборкой. -[assembly: AssemblyTitle("WinToLinux")] -[assembly: AssemblyDescription("Reboot to Linux easier than ever")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Toxblh")] -[assembly: AssemblyProduct("WinToLinux")] -[assembly: AssemblyCopyright("Anton Palgunov. Copyright © 2020 - 2023")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми -// для компонентов COM. Если необходимо обратиться к типу в этой сборке через -// COM, следует установить атрибут ComVisible в TRUE для этого типа. -[assembly: ComVisible(false)] - -// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM -[assembly: Guid("50553123-481b-42c7-a1de-0666bac41e0f")] - -// Сведения о версии сборки состоят из указанных ниже четырех значений: -// -// Основной номер версии -// Дополнительный номер версии -// Номер сборки -// Редакция -// -// Можно задать все значения или принять номера сборки и редакции по умолчанию -// используя "*", как показано ниже: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.1.0")] -[assembly: AssemblyFileVersion("1.1.0")] diff --git a/WinToLinux.csproj b/WinToLinux.csproj index 321396a..661ebf4 100644 --- a/WinToLinux.csproj +++ b/WinToLinux.csproj @@ -1,17 +1,7 @@ - - - + - Debug - AnyCPU - {50553123-481B-42C7-A1DE-0666BAC41E0F} + net8.0-windows10.0.26100.0 WinExe - WinToLinux - WinToLinux - v4.8 - 512 - true - false publish\ true @@ -27,77 +17,17 @@ 1.0.0.%2a false true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - + true + true app.manifest - - - - - + WtL.ico + 7.0 + README.md - - - packages\TaskScheduler.2.10.1\lib\net452\Microsoft.Win32.TaskScheduler.dll - - - - - - - - - - - - Form - - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - + + @@ -109,5 +39,10 @@ false - + + + True + \ + + \ No newline at end of file diff --git a/WinToLinux.sln b/WinToLinux.sln deleted file mode 100644 index 57f05d6..0000000 --- a/WinToLinux.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29613.14 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinToLinux", "WinToLinux.csproj", "{50553123-481B-42C7-A1DE-0666BAC41E0F}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {50553123-481B-42C7-A1DE-0666BAC41E0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {50553123-481B-42C7-A1DE-0666BAC41E0F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {50553123-481B-42C7-A1DE-0666BAC41E0F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {50553123-481B-42C7-A1DE-0666BAC41E0F}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {B79D4238-CC1B-439A-85DC-AB7783E95213} - EndGlobalSection -EndGlobal diff --git a/WinToLinux.slnx b/WinToLinux.slnx new file mode 100644 index 0000000..56e37c5 --- /dev/null +++ b/WinToLinux.slnx @@ -0,0 +1,3 @@ + + + diff --git a/packages.config b/packages.config deleted file mode 100644 index 82f3e90..0000000 --- a/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From 7df03c374ac8a6733f9adf5587a03b97bed92066 Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Sat, 12 Jul 2025 17:13:20 +0800 Subject: [PATCH 02/14] high dpi in csproj theme --- Program.cs | 11 +++-- Program.resx | 120 ++++++++++++++++++++++++++++++++++++++++++++++ WinToLinux.csproj | 21 ++++---- app.config | 3 -- app.manifest | 30 ++---------- 5 files changed, 140 insertions(+), 45 deletions(-) create mode 100644 Program.resx delete mode 100644 app.config diff --git a/Program.cs b/Program.cs index a81cbcb..0a4fe3e 100644 --- a/Program.cs +++ b/Program.cs @@ -13,6 +13,7 @@ public class SysTrayApp : Form [STAThread] public static void Main() { + Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.Run(new SysTrayApp()); } @@ -21,11 +22,11 @@ public static void Main() private readonly ContextMenuStrip trayMenu; private readonly string appName = "WinToLinux"; - List uefi = new List(); - List uuid = new List(); - string bootSequence; - string currentValue; - int shift; + private List uefi = new List(); + private List uuid = new List(); + private string bootSequence; + private string currentValue; + private int shift; readonly Regex regexUUID = new Regex("^(\\{){0,1}[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}(\\}){0,1}$"); public SysTrayApp() diff --git a/Program.resx b/Program.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Program.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/WinToLinux.csproj b/WinToLinux.csproj index 661ebf4..41a4870 100644 --- a/WinToLinux.csproj +++ b/WinToLinux.csproj @@ -19,27 +19,26 @@ true true true - app.manifest - - WtL.ico 7.0 README.md + WtL.ico + app.manifest + SystemAware + 1.1.0 + LICENSE - + - - False - .NET Framework 3.5 SP1 - false - - - + + True + \ + True \ diff --git a/app.config b/app.config deleted file mode 100644 index 3e0e37c..0000000 --- a/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app.manifest b/app.manifest index 0c57e86..d1d3524 100644 --- a/app.manifest +++ b/app.manifest @@ -1,20 +1,13 @@  - + - @@ -43,22 +36,8 @@ - - - - - - - true - - - + - - - + From d3cb6871764d206f2ead2a941428f4eb3be58288 Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Sat, 12 Jul 2025 17:51:41 +0800 Subject: [PATCH 03/14] remove TODOs --- Program.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Program.cs b/Program.cs index 0a4fe3e..a73a5e8 100644 --- a/Program.cs +++ b/Program.cs @@ -13,12 +13,12 @@ public class SysTrayApp : Form [STAThread] public static void Main() { + Application.EnableVisualStyles(); Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.Run(new SysTrayApp()); } private readonly NotifyIcon trayIcon; - // TODO ContextMenu is no longer supported. Use ContextMenuStrip instead. For more details see https://docs.microsoft.com/en-us/dotnet/core/compatibility/winforms#removed-controls private readonly ContextMenuStrip trayMenu; private readonly string appName = "WinToLinux"; @@ -27,7 +27,7 @@ public static void Main() private string bootSequence; private string currentValue; private int shift; - readonly Regex regexUUID = new Regex("^(\\{){0,1}[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}(\\}){0,1}$"); + private readonly Regex regexUUID = new Regex("^(\\{){0,1}[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}(\\}){0,1}$"); public SysTrayApp() { @@ -73,7 +73,6 @@ public SysTrayApp() // standard system icon for simplicity, but you // can of course use your own custom icon too. - // TODO ContextMenu is no longer supported. Use ContextMenuStrip instead. For more details see https://docs.microsoft.com/en-us/dotnet/core/compatibility/winforms#removed-controls trayIcon = new NotifyIcon { Text = "Reboot to Linux", From ac7b93b18c47b6fc1cbca45c6264ff70e3e7ecd9 Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Sat, 12 Jul 2025 17:55:40 +0800 Subject: [PATCH 04/14] remove LaunchCMD, use ProcessStartInfo bcdedit, fix GetMenuItems --- Program.cs | 60 +++++++++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/Program.cs b/Program.cs index a73a5e8..a12ec48 100644 --- a/Program.cs +++ b/Program.cs @@ -96,10 +96,14 @@ private void OnMenuClick(object sender, EventArgs e) return; // Set the boot sequence - string command = $"/C bcdedit.exe /set {{fwbootmgr}} bootsequence {uuid} /addfirst"; - Console.WriteLine(command); - - LaunchCMD(command); + string args = $"/Set {{fwbootmgr}} BootSequence {uuid} /AddFirst"; + var psi = new ProcessStartInfo { + FileName = "bcdedit", + Arguments = args, + CreateNoWindow = true + }; + Process.Start(psi); + Console.WriteLine("bcdedit" + args); // Update the radio button selection SetRadioButtonSelection(uuid); @@ -136,7 +140,7 @@ private void RefreshMenuItems() uuid.Clear(); uefi.Clear(); - LaunchCMD("/C bcdedit /enum firmware"); + GetMenuItems(); currentValue = bootSequence ?? (uuid.Count > 0 ? uuid.First() : string.Empty); shift = uuid.Count - uefi.Count; @@ -203,42 +207,28 @@ private void OnRegisterInStartup(object sender, EventArgs e) private void OnReboot(object sender, EventArgs e) { - LaunchCMD("/C shutdown /r /t 0"); + var psi = new ProcessStartInfo("shutdown", "/s /t 0"); + psi.CreateNoWindow = true; + Process.Start(psi); } private void GetMenuItems() { - LaunchCMD("/C bcdedit /enum firmware"); - } - - private void LaunchCMD(string command) - { - try - { - using var process = new Process(); - process.StartInfo.Arguments = command; - process.StartInfo.FileName = "cmd.exe"; - process.StartInfo.UseShellExecute = false; - process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.RedirectStandardError = true; - process.StartInfo.CreateNoWindow = true; - - process.ErrorDataReceived += Build_ErrorAndDataReceived; - process.OutputDataReceived += Build_ErrorAndDataReceived; - process.EnableRaisingEvents = true; - - process.Start(); - process.BeginOutputReadLine(); - process.BeginErrorReadLine(); - process.WaitForExit(); - } - catch (Exception ex) - { - Console.WriteLine($"Error executing command: {ex.Message}"); - } + var psi = new ProcessStartInfo { + FileName = "bcdedit", + Arguments = "/enum firmware", + RedirectStandardOutput = true, + CreateNoWindow = true, + UseShellExecute = false + }; + using var process = new Process { StartInfo = psi }; + process.OutputDataReceived += ParseBCDEditOutput; + process.Start(); + process.BeginOutputReadLine(); + process.WaitForExit(); } - void Build_ErrorAndDataReceived(object sender, DataReceivedEventArgs e) + void ParseBCDEditOutput(object sender, DataReceivedEventArgs e) { if (string.IsNullOrEmpty(e.Data)) return; From 09d2d166d4c30250f525784b65b34d033548b884 Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Sun, 13 Jul 2025 21:18:16 +0800 Subject: [PATCH 05/14] SettingsSingleFileGenerator & ResXFileCodeGenerator --- App.config | 3 +++ Properties/Resources.Designer.cs | 26 +++++++++++++------------- Properties/Settings.Designer.cs | 10 +++++----- WinToLinux.csproj | 24 +++++++++++++++++++++++- 4 files changed, 44 insertions(+), 19 deletions(-) create mode 100644 App.config diff --git a/App.config b/App.config new file mode 100644 index 0000000..49cc43e --- /dev/null +++ b/App.config @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs index 06999b9..5171c12 100644 --- a/Properties/Resources.Designer.cs +++ b/Properties/Resources.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// Этот код создан программой. -// Исполняемая версия:4.0.30319.42000 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // -// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае -// повторной генерации кода. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -13,12 +13,12 @@ namespace WinToLinux.Properties { /// - /// Класс ресурса со строгой типизацией для поиска локализованных строк и т.д. + /// A strongly-typed resource class, for looking up localized strings, etc. /// - // Этот класс создан автоматически классом StronglyTypedResourceBuilder - // с помощью такого средства, как ResGen или Visual Studio. - // Чтобы добавить или удалить член, измените файл .ResX и снова запустите ResGen - // с параметром /str или перестройте свой проект VS. + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] @@ -33,7 +33,7 @@ internal Resources() { } /// - /// Возвращает кэшированный экземпляр ResourceManager, использованный этим классом. + /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { @@ -47,8 +47,8 @@ internal Resources() { } /// - /// Перезаписывает свойство CurrentUICulture текущего потока для всех - /// обращений к ресурсу с помощью этого класса ресурса со строгой типизацией. + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { @@ -61,7 +61,7 @@ internal Resources() { } /// - /// Поиск локализованного ресурса типа System.Drawing.Icon, аналогичного (Значок). + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). /// internal static System.Drawing.Icon WtL { get { diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs index 11c7080..7a1a2ad 100644 --- a/Properties/Settings.Designer.cs +++ b/Properties/Settings.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// Этот код создан программой. -// Исполняемая версия:4.0.30319.42000 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // -// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае -// повторной генерации кода. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -12,7 +12,7 @@ namespace WinToLinux.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/WinToLinux.csproj b/WinToLinux.csproj index 41a4870..96ef4d1 100644 --- a/WinToLinux.csproj +++ b/WinToLinux.csproj @@ -1,6 +1,6 @@  - net8.0-windows10.0.26100.0 + net8.0-windows WinExe false publish\ @@ -34,11 +34,33 @@ + + + True + True + Resources.resx + + + True + True + Settings.settings + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + True \ + + SettingsSingleFileGenerator + Settings.Designer.cs + True \ From d779004ff5cadd0e244e8ff015f4f67c6ed4991e Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Sun, 13 Jul 2025 21:48:09 +0800 Subject: [PATCH 06/14] metadata --- WinToLinux.csproj | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/WinToLinux.csproj b/WinToLinux.csproj index 96ef4d1..f156106 100644 --- a/WinToLinux.csproj +++ b/WinToLinux.csproj @@ -19,13 +19,15 @@ true true true - 7.0 README.md WtL.ico app.manifest - SystemAware - 1.1.0 - LICENSE + SystemAware + LICENSE + 1.2.0 + https://github.com/Toxblh/WinToLinux + Anton Palgunov & Contributors. Copyright © 2020 - 2025 + Reboot to Linux easier than ever! From 0bff38d2d41a735a9a7ac46005e03f05402a0311 Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Mon, 14 Jul 2025 11:55:58 +0800 Subject: [PATCH 07/14] syntax refresh & GeneratedRegex --- Program.cs | 97 +++++++++++++++++++++++------------------------------- 1 file changed, 41 insertions(+), 56 deletions(-) diff --git a/Program.cs b/Program.cs index a12ec48..d329050 100644 --- a/Program.cs +++ b/Program.cs @@ -8,7 +8,7 @@ namespace MyTrayApp { - public class SysTrayApp : Form + public partial class SysTrayApp : Form { [STAThread] public static void Main() @@ -20,53 +20,41 @@ public static void Main() private readonly NotifyIcon trayIcon; private readonly ContextMenuStrip trayMenu; - private readonly string appName = "WinToLinux"; + private const string appName = "WinToLinux"; - private List uefi = new List(); - private List uuid = new List(); + private readonly List uefi = []; + private readonly List uuid = []; + private readonly List bootOptions = []; private string bootSequence; private string currentValue; private int shift; - private readonly Regex regexUUID = new Regex("^(\\{){0,1}[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}(\\}){0,1}$"); - public SysTrayApp() - { - GetMenuItems(); + private readonly ToolStripMenuItem startButton = new("Start with system"); - currentValue = bootSequence ?? uuid.First(); - shift = uuid.Count() - uefi.Count(); + [GeneratedRegex("^(\\{){0,1}[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}(\\}){0,1}$")] + private static partial Regex UUIDRegEx(); + public SysTrayApp() + { // Create a simple tray menu with only one item. trayMenu = new ContextMenuStrip(); trayMenu.Items.Add("Settings").Enabled = false; - trayMenu.Items.Add("-"); + trayMenu.Items.Add(new ToolStripSeparator()); - var startButton = new ToolStripMenuItem("Start with system"); startButton.Checked = IsTaskEnabled(); startButton.Click += OnRegisterInStartup; trayMenu.Items.Add(startButton); - trayMenu.Items.Add("-"); + trayMenu.Items.Add(new ToolStripSeparator()); trayMenu.Items.Add("Reboot to...").Enabled = false; - trayMenu.Items.Add("-"); - - foreach (var pos in uefi.Select((value, i) => new { i, value })) - { - var item = new ToolStripMenuItem { - CheckOnClick = true, - Tag = pos.i + shift < uuid.Count ? uuid[pos.i + shift] : string.Empty, - Text = pos.value - }; - item.Click += OnMenuClick; - trayMenu.Items.Add(item); - } + trayMenu.Items.Add(new ToolStripSeparator()); - // Set the initial radio button selection - SetRadioButtonSelection(currentValue); + RefreshMenuItems(); + bootOptions.ForEach(item => trayMenu.Items.Add(item)); - trayMenu.Items.Add("-"); + trayMenu.Items.Add(new ToolStripSeparator()); trayMenu.Items.Add("Reboot system", null, OnReboot); - trayMenu.Items.Add("-"); + trayMenu.Items.Add(new ToolStripSeparator()); trayMenu.Items.Add("Exit", null, OnExit); // Create a tray icon. In this example we use a @@ -111,27 +99,14 @@ private void OnMenuClick(object sender, EventArgs e) // Update the current value currentValue = uuid; } - private void SetRadioButtonSelection(string selectedUuid) + private void SetRadioButtonSelection(string selectedUUID) { // First, uncheck all boot option menu items - for (int i = 6; i < trayMenu.Items.Count - 3; i++) // Skip fixed items at start and end + foreach (var item in bootOptions) { - if (trayMenu.Items[i] is ToolStripMenuItem item && item.Tag is string) + if (item.Tag is string itemUUID) { - item.Checked = false; - } - } - - // Then check the selected item - for (int i = 6; i < trayMenu.Items.Count - 3; i++) - { - if (trayMenu.Items[i] is ToolStripMenuItem item && - item.Tag is string itemUUID && - itemUUID == selectedUuid - ) - { - item.Checked = true; - break; + item.Checked = (itemUUID == selectedUUID); } } } @@ -142,13 +117,25 @@ private void RefreshMenuItems() GetMenuItems(); - currentValue = bootSequence ?? (uuid.Count > 0 ? uuid.First() : string.Empty); + currentValue = bootSequence ?? uuid.FirstOrDefault(string.Empty); shift = uuid.Count - uefi.Count; + foreach (var (value, i) in uefi.Select((value, i) => (value, i))) + { + var item = new ToolStripMenuItem + { + CheckOnClick = true, + Tag = i + shift < uuid.Count ? uuid[i + shift] : string.Empty, + Text = value + }; + item.Click += OnMenuClick; + bootOptions.Add(item); + } + // Update radio button selection SetRadioButtonSelection(currentValue); } - private void CreateTask() + private static void CreateTask() { try { @@ -174,7 +161,7 @@ private void CreateTask() } } - private void DeleteTask() + private static void DeleteTask() { using var ts = new TaskService(); if (ts.GetTask(appName) != null) @@ -183,25 +170,23 @@ private void DeleteTask() } } - private bool IsTaskEnabled() + private static bool IsTaskEnabled() { using var ts = new TaskService(); return ts.GetTask(appName) != null; } - private void OnRegisterInStartup(object sender, EventArgs e) + private void OnRegisterInStartup(object _, EventArgs e) { if (IsTaskEnabled()) { DeleteTask(); - if (trayMenu.Items[2] is ToolStripMenuItem item) - item.Checked = false; + startButton.Checked = false; } else { CreateTask(); - if (trayMenu.Items[2] is ToolStripMenuItem item) - item.Checked = true; + startButton.Checked = true; } } @@ -239,7 +224,7 @@ void ParseBCDEditOutput(object sender, DataReceivedEventArgs e) if (splitMsg.Length == 0) return; - var match = regexUUID.Match(splitMsg.Last()); + var match = UUIDRegEx().Match(splitMsg.Last()); if (splitMsg[0] == "description") { From 4e7fed247392da0741a5c5c90a862615d0164f4d Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Mon, 14 Jul 2025 20:13:17 +0800 Subject: [PATCH 08/14] actually reboot --- Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Program.cs b/Program.cs index d329050..7497b21 100644 --- a/Program.cs +++ b/Program.cs @@ -192,7 +192,7 @@ private void OnRegisterInStartup(object _, EventArgs e) private void OnReboot(object sender, EventArgs e) { - var psi = new ProcessStartInfo("shutdown", "/s /t 0"); + var psi = new ProcessStartInfo("shutdown", "/r /t 0"); psi.CreateNoWindow = true; Process.Start(psi); } From ecaa33bea1ee4b5a86eef4715e7b06fe93044bd4 Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:03:05 +0800 Subject: [PATCH 09/14] add "Reboot now to" dropdown submenu --- Program.cs | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/Program.cs b/Program.cs index 7497b21..1d3243f 100644 --- a/Program.cs +++ b/Program.cs @@ -30,6 +30,7 @@ public static void Main() private int shift; private readonly ToolStripMenuItem startButton = new("Start with system"); + private readonly ToolStripMenuItem rebootToButton = new("Reboot now to..."); [GeneratedRegex("^(\\{){0,1}[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}(\\}){0,1}$")] private static partial Regex UUIDRegEx(); @@ -45,11 +46,12 @@ public SysTrayApp() startButton.Click += OnRegisterInStartup; trayMenu.Items.Add(startButton); + RefreshMenuItems(); + trayMenu.Items.Add(new ToolStripSeparator()); - trayMenu.Items.Add("Reboot to...").Enabled = false; + trayMenu.Items.Add(rebootToButton); trayMenu.Items.Add(new ToolStripSeparator()); - RefreshMenuItems(); bootOptions.ForEach(item => trayMenu.Items.Add(item)); trayMenu.Items.Add(new ToolStripSeparator()); @@ -57,9 +59,7 @@ public SysTrayApp() trayMenu.Items.Add(new ToolStripSeparator()); trayMenu.Items.Add("Exit", null, OnExit); - // Create a tray icon. In this example we use a - // standard system icon for simplicity, but you - // can of course use your own custom icon too. + // Create a tray icon. trayIcon = new NotifyIcon { @@ -78,7 +78,7 @@ private void OnExit(object sender, EventArgs e) Application.Exit(); } - private void OnMenuClick(object sender, EventArgs e) + private void SetNextBoot(object sender, EventArgs _) { if (sender is not ToolStripMenuItem clickedItem || clickedItem.Tag is not string uuid) return; @@ -114,6 +114,7 @@ private void RefreshMenuItems() { uuid.Clear(); uefi.Clear(); + rebootToButton.DropDownItems.Clear(); GetMenuItems(); @@ -122,14 +123,30 @@ private void RefreshMenuItems() foreach (var (value, i) in uefi.Select((value, i) => (value, i))) { - var item = new ToolStripMenuItem + string itemTag = i + shift < uuid.Count ? uuid[i + shift] : string.Empty; + + var bootItem = new ToolStripMenuItem { CheckOnClick = true, - Tag = i + shift < uuid.Count ? uuid[i + shift] : string.Empty, + Tag = itemTag, + Text = value + }; + bootItem.Click += SetNextBoot; + + bootOptions.Add(bootItem); + + var immediateItem = new ToolStripMenuItem + { + Tag = itemTag, Text = value }; - item.Click += OnMenuClick; - bootOptions.Add(item); + immediateItem.Click += (sender, _) => + { + SetNextBoot(sender, _); + OnReboot(sender, _); + }; + + rebootToButton.DropDownItems.Add(immediateItem); } // Update radio button selection From 8382ed3ee530e51499c58b87298f82dc3be399dc Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Tue, 15 Jul 2025 15:16:42 +0800 Subject: [PATCH 10/14] properly refresh context menu + code cleanup --- Program.cs | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/Program.cs b/Program.cs index 1d3243f..8e49f65 100644 --- a/Program.cs +++ b/Program.cs @@ -1,10 +1,10 @@ -using Microsoft.Win32.TaskScheduler; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; +using Microsoft.Win32.TaskScheduler; namespace MyTrayApp { @@ -28,6 +28,7 @@ public static void Main() private string bootSequence; private string currentValue; private int shift; + private readonly int bootOptionsTrayStartIndex; private readonly ToolStripMenuItem startButton = new("Start with system"); private readonly ToolStripMenuItem rebootToButton = new("Reboot now to..."); @@ -46,13 +47,12 @@ public SysTrayApp() startButton.Click += OnRegisterInStartup; trayMenu.Items.Add(startButton); - RefreshMenuItems(); - trayMenu.Items.Add(new ToolStripSeparator()); trayMenu.Items.Add(rebootToButton); trayMenu.Items.Add(new ToolStripSeparator()); - bootOptions.ForEach(item => trayMenu.Items.Add(item)); + bootOptionsTrayStartIndex = trayMenu.Items.Count; + RefreshMenuItems(); trayMenu.Items.Add(new ToolStripSeparator()); trayMenu.Items.Add("Reboot system", null, OnReboot); @@ -70,6 +70,10 @@ public SysTrayApp() ContextMenuStrip = trayMenu, Visible = true }; + trayIcon.ContextMenuStrip.Opening += (_, _) => + { + RefreshMenuItems(); + }; } @@ -85,7 +89,8 @@ private void SetNextBoot(object sender, EventArgs _) // Set the boot sequence string args = $"/Set {{fwbootmgr}} BootSequence {uuid} /AddFirst"; - var psi = new ProcessStartInfo { + var psi = new ProcessStartInfo + { FileName = "bcdedit", Arguments = args, CreateNoWindow = true @@ -114,7 +119,12 @@ private void RefreshMenuItems() { uuid.Clear(); uefi.Clear(); - rebootToButton.DropDownItems.Clear(); + if (bootOptions.Count > 0) + { + bootOptions.ForEach(item => trayMenu.Items.Remove(item)); + bootOptions.Clear(); + rebootToButton.DropDownItems.Clear(); + } GetMenuItems(); @@ -151,6 +161,10 @@ private void RefreshMenuItems() // Update radio button selection SetRadioButtonSelection(currentValue); + for (int i = 0; i < bootOptions.Count; i++) + { + trayMenu.Items.Insert(bootOptionsTrayStartIndex + i, bootOptions[i]); + } } private static void CreateTask() { @@ -216,7 +230,8 @@ private void OnReboot(object sender, EventArgs e) private void GetMenuItems() { - var psi = new ProcessStartInfo { + var psi = new ProcessStartInfo + { FileName = "bcdedit", Arguments = "/enum firmware", RedirectStandardOutput = true, From 890fcfa3b123a7d373197336f0ddb22be490e10d Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Tue, 15 Jul 2025 16:41:07 +0800 Subject: [PATCH 11/14] Update CI --- .github/workflows/build.yml | 21 +++++-------- .github/workflows/release.yml | 59 ++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 112c708..9131e6f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,5 @@ -name: MSBuild -on: [push] +name: Build +on: [push, pull_request, workflow_dispatch] jobs: build: @@ -7,16 +7,9 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@master - - - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1.1 - - - name: Setup NuGet - uses: NuGet/setup-nuget@v1.1.1 + - uses: actions/checkout@v4 - - name: Restore NuGet packages - run: nuget restore - - - name: Build app for release - run: msbuild WinToLinux.sln -p:Configuration=Release + - uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + - run: dotnet build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 62f0ae8..d591afa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,31 +11,46 @@ jobs: name: Upload Release Asset runs-on: windows-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v4 - - name: Setup MSBuild.exe - uses: warrenbuckley/Setup-MSBuild@v1 + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' - - name: MSBuild - run: msbuild WinToLinux.sln /property:Configuration=Release + - name: Build solution + run: dotnet build + + - name: Publish app + run: | + dotnet publish WinToLinux.slnx -p:PublishSingleFile=true -c Release --sc false --arch x64 + dotnet publish WinToLinux.slnx -p:PublishSingleFile=true -c Release --sc false --arch x86 + dotnet publish WinToLinux.slnx -p:PublishSingleFile=true -c Release --sc false --arch arm64 + + - name: Zip published output + run: | + Compress-Archive -Path ./bin/Release/*/win-x64/publish -DestinationPath WinToLinux_x64.zip + Compress-Archive -Path ./bin/Release/*/win-x86/publish -DestinationPath WinToLinux_x86.zip + Compress-Archive -Path ./bin/Release/*/win-arm64/publish -DestinationPath WinToLinux_arm64.zip + + - name: Rename .exe output + run: | + New-Item -ItemType Directory -Force -Path artifacts + Move-Item -Path ./bin/Release/*/win-x64/publish/WinToLinux.exe -Destination ./artifacts/WinToLinux-x64.exe + Move-Item -Path ./bin/Release/*/win-x86/publish/WinToLinux.exe -Destination ./artifacts/WinToLinux-x86.exe + Move-Item -Path ./bin/Release/*/win-arm64/publish/WinToLinux.exe -Destination ./artifacts/WinToLinux-arm64.exe + shell: pwsh - - name: Create Release - id: create_release - uses: actions/create-release@v1.0.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: Release ${{ github.ref }} - draft: false - prerelease: false - name: Upload Release Asset - id: upload-release-asset - uses: actions/upload-release-asset@v1.0.1 + uses: softprops/action-gh-release@v2 + with: + files: | + ./artifacts/WinToLinux-x64.exe + ./artifacts/WinToLinux-x86.exe + ./artifacts/WinToLinux-arm64.exe + WinToLinux_x64.zip + WinToLinux_x86.zip + WinToLinux_arm64.zip + generate_release_notes: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: ./bin/Release/WinToLinux.exe - asset_name: WinToLinux.exe - asset_content_type: application/octet-stream From 45573aa3a6634e4d22fe0627b1862146df088cce Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Tue, 15 Jul 2025 18:00:58 +0800 Subject: [PATCH 12/14] Remove ClickOnce options from .csproj --- WinToLinux.csproj | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/WinToLinux.csproj b/WinToLinux.csproj index f156106..fa64a6e 100644 --- a/WinToLinux.csproj +++ b/WinToLinux.csproj @@ -2,21 +2,6 @@ net8.0-windows WinExe - false - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true true true README.md @@ -24,10 +9,15 @@ app.manifest SystemAware LICENSE - 1.2.0 https://github.com/Toxblh/WinToLinux Anton Palgunov & Contributors. Copyright © 2020 - 2025 Reboot to Linux easier than ever! + + 1.2.0 + + $(VersionPrefix) + $(VersionPrefix) + $(VersionPrefix)$(VersionSuffix) From 3f916c9b02e273a714c2aa30ea4ac4473d92a508 Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Fri, 18 Jul 2025 16:41:59 +0800 Subject: [PATCH 13/14] delete redundant Program.resx, trigger task on logon of current user --- Program.cs | 3 +- Program.resx | 120 --------------------------------------------------- 2 files changed, 2 insertions(+), 121 deletions(-) delete mode 100644 Program.resx diff --git a/Program.cs b/Program.cs index 8e49f65..89cdf13 100644 --- a/Program.cs +++ b/Program.cs @@ -172,9 +172,10 @@ private static void CreateTask() { using var ts = new TaskService(); var td = ts.NewTask(); + string currentUser = $"{Environment.UserDomainName}\\{Environment.UserName}"; td.RegistrationInfo.Description = "WinToLinux. Start on boot"; - td.Triggers.Add(new LogonTrigger()); + td.Triggers.Add(new LogonTrigger() { UserId = currentUser }); td.Actions.Add(new ExecAction(Application.ExecutablePath, null, null)); td.Principal.RunLevel = TaskRunLevel.Highest; diff --git a/Program.resx b/Program.resx deleted file mode 100644 index 1af7de1..0000000 --- a/Program.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file From 1a47c354ee4516a9f7edf0566c772b82593b1893 Mon Sep 17 00:00:00 2001 From: wheeheee <104880306+wheeheee@users.noreply.github.com> Date: Sat, 19 Jul 2025 22:23:36 +0800 Subject: [PATCH 14/14] apply workaround for scaling issues --- Program.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Program.cs b/Program.cs index 89cdf13..ce66166 100644 --- a/Program.cs +++ b/Program.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Linq; +using System.Reflection; using System.Text.RegularExpressions; using System.Windows.Forms; using Microsoft.Win32.TaskScheduler; @@ -300,4 +302,23 @@ protected override void Dispose(bool isDisposing) base.Dispose(isDisposing); } } + public class ContextMenuStrip : System.Windows.Forms.ContextMenuStrip + { + private new void RescaleConstantsForDpi(int deviceDpiOld, int deviceDpiNew) + { + // Use reflection to invoke the internal ResetScaling method + var resetScalingMethod = typeof(System.Windows.Forms.ContextMenuStrip).GetMethod("ResetScaling", BindingFlags.NonPublic | BindingFlags.Instance); + resetScalingMethod?.Invoke(this, [deviceDpiNew]); + } + + public ContextMenuStrip(IContainer container) : base(container) + { + RescaleConstantsForDpi(96, DeviceDpi); + } + + public ContextMenuStrip() + { + RescaleConstantsForDpi(96, DeviceDpi); + } + } }