From 3da45b620d61dcd4cd700c6b545c3eb167bd7163 Mon Sep 17 00:00:00 2001 From: CodingWonders <101426328+CodingWonders@users.noreply.github.com> Date: Sat, 17 Oct 2026 23:09:38 +0200 Subject: [PATCH 1/3] Add regional support --- MicroWin/AppState.cs | 3 + MicroWin/Classes/Regional/GeoId.cs | 45 ++ MicroWin/Classes/Regional/ImageLanguage.cs | 50 ++ .../Classes/Regional/KeyboardIdentifier.cs | 65 ++ MicroWin/Classes/Regional/TimeOffset.cs | 55 ++ MicroWin/Classes/Regional/UserLocale.cs | 63 ++ MicroWin/MainForm.Designer.cs | 487 ++++++++----- MicroWin/MainForm.cs | 128 +++- MicroWin/MainForm.resx | 10 +- MicroWin/MicroWin.csproj | 13 + MicroWin/Resources/Regional/GeoId.xml | 270 +++++++ MicroWin/Resources/Regional/ImageLanguage.xml | 41 ++ .../Resources/Regional/KeyboardIdentifier.xml | 246 +++++++ MicroWin/Resources/Regional/TimeOffset.xml | 142 ++++ MicroWin/Resources/Regional/UserLocale.xml | 689 ++++++++++++++++++ .../ProgramResources/ResourceHelper.cs | 21 + .../functions/OSCDIMG/OscdimgUtilities.cs | 4 +- MicroWin/functions/dism/UnattendGenerator.cs | 56 ++ 18 files changed, 2205 insertions(+), 183 deletions(-) create mode 100644 MicroWin/Classes/Regional/GeoId.cs create mode 100644 MicroWin/Classes/Regional/ImageLanguage.cs create mode 100644 MicroWin/Classes/Regional/KeyboardIdentifier.cs create mode 100644 MicroWin/Classes/Regional/TimeOffset.cs create mode 100644 MicroWin/Classes/Regional/UserLocale.cs create mode 100644 MicroWin/Resources/Regional/GeoId.xml create mode 100644 MicroWin/Resources/Regional/ImageLanguage.xml create mode 100644 MicroWin/Resources/Regional/KeyboardIdentifier.xml create mode 100644 MicroWin/Resources/Regional/TimeOffset.xml create mode 100644 MicroWin/Resources/Regional/UserLocale.xml create mode 100644 MicroWin/functions/Helpers/ProgramResources/ResourceHelper.cs diff --git a/MicroWin/AppState.cs b/MicroWin/AppState.cs index fd854ae..76c9ae1 100755 --- a/MicroWin/AppState.cs +++ b/MicroWin/AppState.cs @@ -1,4 +1,5 @@ using MicroWin.Classes; +using MicroWin.Classes.Regional; using System.Collections.Generic; using System.IO; @@ -24,6 +25,8 @@ public static class AppState public static bool UseUEFICA23Bins { get; set; } = true; public static string? SaveISO { get; set; } public static string? WinUtilConfigPath { get; set; } + public static UserLocale? userLocale { get; set; } + public static TimeOffset? timeOffset { get; set; } public static string Version => "v2.1"; } diff --git a/MicroWin/Classes/Regional/GeoId.cs b/MicroWin/Classes/Regional/GeoId.cs new file mode 100644 index 0000000..f3528ff --- /dev/null +++ b/MicroWin/Classes/Regional/GeoId.cs @@ -0,0 +1,45 @@ +using MicroWin.functions.Helpers.ProgramResources; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +namespace MicroWin.Classes.Regional +{ + public class GeoId + { + [XmlAttribute("Id")] + public required string Id; + + [XmlAttribute("DisplayName")] + public required string DisplayName; + + public override string ToString() { + return $"GeoID {Id} -- {DisplayName}"; + } + + public static List LoadItems() { + List geoList = []; + + try { + XmlReaderSettings xs = new() { IgnoreWhitespace = true }; +#pragma warning disable CS8604 + using XmlReader reader = XmlReader.Create(ResourceHelper.GetProgramResourceStream("MicroWin.Resources.Regional.GeoId.xml"), xs); +#pragma warning restore CS8604 + while (reader.Read()) { + if (reader.NodeType == XmlNodeType.Element && reader.Name == "GeoId") { + geoList.Add(new() { Id = reader.GetAttribute("Id") ?? "", DisplayName = reader.GetAttribute("DisplayName") ?? "" }); + } + } + } catch (Exception ex) { + if (Debugger.IsAttached) + Debugger.Break(); + Debug.WriteLine(ex.Message); + } + + return geoList; + } + } +} diff --git a/MicroWin/Classes/Regional/ImageLanguage.cs b/MicroWin/Classes/Regional/ImageLanguage.cs new file mode 100644 index 0000000..c2c59c8 --- /dev/null +++ b/MicroWin/Classes/Regional/ImageLanguage.cs @@ -0,0 +1,50 @@ +using MicroWin.functions.Helpers.ProgramResources; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +namespace MicroWin.Classes.Regional +{ + public class ImageLanguage + { + [XmlAttribute("Id")] + public required string Id; + + [XmlAttribute("DisplayName")] + public required string DisplayName; + + public override string ToString() { + return $"Language {Id} -- {DisplayName}"; + } + + public static List LoadItems() { + List langList = []; + + try + { + XmlReaderSettings xs = new() { IgnoreWhitespace = true }; +#pragma warning disable CS8604 + using XmlReader reader = XmlReader.Create(ResourceHelper.GetProgramResourceStream("MicroWin.Resources.Regional.ImageLanguage.xml"), xs); +#pragma warning restore CS8604 + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element && reader.Name == "ImageLanguage") + { + langList.Add(new() { Id = reader.GetAttribute("Id") ?? "", DisplayName = reader.GetAttribute("DisplayName") ?? "" }); + } + } + } + catch (Exception ex) + { + if (Debugger.IsAttached) + Debugger.Break(); + Debug.WriteLine(ex.Message); + } + + return langList; + } + } +} diff --git a/MicroWin/Classes/Regional/KeyboardIdentifier.cs b/MicroWin/Classes/Regional/KeyboardIdentifier.cs new file mode 100644 index 0000000..84d045d --- /dev/null +++ b/MicroWin/Classes/Regional/KeyboardIdentifier.cs @@ -0,0 +1,65 @@ +using MicroWin.functions.Helpers.ProgramResources; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Xml; + +namespace MicroWin.Classes.Regional +{ + public class KeyboardIdentifier + { + + public required string Id; + + public required string DisplayName; + + public required string TypeString; + + public KeyboardType GetKeyboardType() + { + return TypeString switch + { + "Keyboard" => KeyboardType.Keyboard, + "IME" => KeyboardType.IME, + _ => KeyboardType.Unknown + }; + } + + public override string ToString() { + return $"Keyboard {Id} -- {DisplayName} -- {GetKeyboardType()}"; + } + + public static List LoadItems() { + List keyboardList = []; + + try + { + XmlReaderSettings xs = new() { IgnoreWhitespace = true }; +#pragma warning disable CS8604 + using XmlReader reader = XmlReader.Create(ResourceHelper.GetProgramResourceStream("MicroWin.Resources.Regional.KeyboardIdentifier.xml"), xs); +#pragma warning restore CS8604 + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element && reader.Name == "KeyboardIdentifier") + { + keyboardList.Add(new() { Id = reader.GetAttribute("Id") ?? "", DisplayName = reader.GetAttribute("DisplayName") ?? "", TypeString = reader.GetAttribute("Type") ?? "" }); + } + } + } + catch (Exception ex) + { + if (Debugger.IsAttached) + Debugger.Break(); + Debug.WriteLine(ex.Message); + } + return keyboardList; + } + } + + public enum KeyboardType : int { + Unknown = -1, + Keyboard = 0, + IME = 1 + } +} diff --git a/MicroWin/Classes/Regional/TimeOffset.cs b/MicroWin/Classes/Regional/TimeOffset.cs new file mode 100644 index 0000000..6a2ded0 --- /dev/null +++ b/MicroWin/Classes/Regional/TimeOffset.cs @@ -0,0 +1,55 @@ +using MicroWin.functions.Helpers.ProgramResources; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +namespace MicroWin.Classes.Regional +{ + public class TimeOffset + { + [XmlAttribute("Id")] + public required string Id; + + [XmlAttribute("DisplayName")] + public required string DisplayName; + + public override string ToString() { + return $"Time Offset {Id} -- {DisplayName}"; + } + + public static List LoadItems() { + List offsetList = []; + + try + { + XmlReaderSettings xs = new() { IgnoreWhitespace = true }; +#pragma warning disable CS8604 + using XmlReader reader = XmlReader.Create(ResourceHelper.GetProgramResourceStream("MicroWin.Resources.Regional.TimeOffset.xml"), xs); +#pragma warning restore CS8604 + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element && reader.Name == "TimeOffset") + { + offsetList.Add(new() { Id = reader.GetAttribute("Id") ?? "", DisplayName = reader.GetAttribute("DisplayName") ?? "" }); + } + } + } + catch (Exception ex) + { + if (Debugger.IsAttached) + Debugger.Break(); + Debug.WriteLine(ex.Message); + } + + return offsetList; + } + + public TimeOffset Clone() + { + return (TimeOffset)MemberwiseClone(); + } + } +} diff --git a/MicroWin/Classes/Regional/UserLocale.cs b/MicroWin/Classes/Regional/UserLocale.cs new file mode 100644 index 0000000..38bd212 --- /dev/null +++ b/MicroWin/Classes/Regional/UserLocale.cs @@ -0,0 +1,63 @@ +using MicroWin.functions.Helpers.ProgramResources; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +namespace MicroWin.Classes.Regional +{ + public class UserLocale + { + [XmlAttribute("Id")] + public required string Id; + [XmlAttribute("DisplayName")] + public required string DisplayName; + [XmlAttribute("LCID")] + public required string LCID; + [XmlAttribute("KeyboardLayout")] + public string? KeyboardLayout; + [XmlAttribute("GeoLocation")] + public string? GeoLocation; + + public override string ToString() + { + return $"User Locale {Id} -- {DisplayName} -- {LCID} -- {KeyboardLayout} -- {GeoLocation}"; + } + + public UserLocale Clone() { + return (UserLocale)MemberwiseClone(); + } + + public static List LoadItems() { + List localeList = []; + + try + { + XmlReaderSettings xs = new() { IgnoreWhitespace = true }; +#pragma warning disable CS8604 + using XmlReader reader = XmlReader.Create(ResourceHelper.GetProgramResourceStream("MicroWin.Resources.Regional.UserLocale.xml"), xs); +#pragma warning restore CS8604 + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element && reader.Name == "UserLocale") + { + localeList.Add(new() { Id = reader.GetAttribute("Id") ?? "", DisplayName = reader.GetAttribute("DisplayName") ?? "", + LCID = reader.GetAttribute("LCID") ?? "", KeyboardLayout = reader.GetAttribute("KeyboardLayout") ?? "", + GeoLocation = reader.GetAttribute("GeoLocation") ?? "" }); + } + } + } + catch (Exception ex) + { + if (Debugger.IsAttached) + Debugger.Break(); + Debug.WriteLine(ex.Message); + } + + return localeList; + } + + } +} diff --git a/MicroWin/MainForm.Designer.cs b/MicroWin/MainForm.Designer.cs index f377d50..abe24a9 100755 --- a/MicroWin/MainForm.Designer.cs +++ b/MicroWin/MainForm.Designer.cs @@ -36,6 +36,30 @@ private void InitializeComponent() Cancel_Button = new Button(); About_Button = new Button(); PageContainerPanel = new Panel(); + IsoSettingsPage = new Panel(); + label19 = new Label(); + UEFICA23CB = new CheckBox(); + DriverExportCombo = new ComboBox(); + label13 = new Label(); + UnattendCopyCB = new CheckBox(); + ReportToolCB = new CheckBox(); + label11 = new Label(); + label12 = new Label(); + winutilConfigLabel = new Label(); + winutilConfigTextBox = new TextBox(); + winutilConfigBrowseBtn = new Button(); + CopyVirtIODrivers = new CheckBox(); + gbRegionalOptions = new GroupBox(); + tableLayoutPanel4 = new TableLayoutPanel(); + comboOffset = new ComboBox(); + label24 = new Label(); + label23 = new Label(); + label22 = new Label(); + label21 = new Label(); + comboTimeFormat = new ComboBox(); + comboIme = new ComboBox(); + comboRegion = new ComboBox(); + label20 = new Label(); FinishPage = new Panel(); lnkViewCreationLogs = new LinkLabel(); lnkOpenIsoLoc = new LinkLabel(); @@ -54,19 +78,6 @@ private void InitializeComponent() logTB = new TextBox(); label14 = new Label(); label15 = new Label(); - IsoSettingsPage = new Panel(); - label19 = new Label(); - UEFICA23CB = new CheckBox(); - DriverExportCombo = new ComboBox(); - label13 = new Label(); - UnattendCopyCB = new CheckBox(); - ReportToolCB = new CheckBox(); - label11 = new Label(); - label12 = new Label(); - winutilConfigLabel = new Label(); - winutilConfigTextBox = new TextBox(); - winutilConfigBrowseBtn = new Button(); - CopyVirtIODrivers = new CheckBox(); UserAccountsPage = new Panel(); panel1 = new Panel(); tableLayoutPanel3 = new TableLayoutPanel(); @@ -118,11 +129,13 @@ private void InitializeComponent() ButtonPanel.SuspendLayout(); TableLayoutPanel1.SuspendLayout(); PageContainerPanel.SuspendLayout(); + IsoSettingsPage.SuspendLayout(); + gbRegionalOptions.SuspendLayout(); + tableLayoutPanel4.SuspendLayout(); FinishPage.SuspendLayout(); panel4.SuspendLayout(); IsoCreationPage.SuspendLayout(); pnlProgress.SuspendLayout(); - IsoSettingsPage.SuspendLayout(); UserAccountsPage.SuspendLayout(); panel1.SuspendLayout(); tableLayoutPanel3.SuspendLayout(); @@ -214,9 +227,9 @@ private void InitializeComponent() // // PageContainerPanel // + PageContainerPanel.Controls.Add(IsoSettingsPage); PageContainerPanel.Controls.Add(FinishPage); PageContainerPanel.Controls.Add(IsoCreationPage); - PageContainerPanel.Controls.Add(IsoSettingsPage); PageContainerPanel.Controls.Add(UserAccountsPage); PageContainerPanel.Controls.Add(ImageChooserPage); PageContainerPanel.Controls.Add(IsoChooserPage); @@ -228,6 +241,284 @@ private void InitializeComponent() PageContainerPanel.Size = new Size(1264, 641); PageContainerPanel.TabIndex = 3; // + // IsoSettingsPage + // + IsoSettingsPage.Controls.Add(label19); + IsoSettingsPage.Controls.Add(UEFICA23CB); + IsoSettingsPage.Controls.Add(DriverExportCombo); + IsoSettingsPage.Controls.Add(label13); + IsoSettingsPage.Controls.Add(UnattendCopyCB); + IsoSettingsPage.Controls.Add(ReportToolCB); + IsoSettingsPage.Controls.Add(label11); + IsoSettingsPage.Controls.Add(label12); + IsoSettingsPage.Controls.Add(winutilConfigLabel); + IsoSettingsPage.Controls.Add(winutilConfigTextBox); + IsoSettingsPage.Controls.Add(winutilConfigBrowseBtn); + IsoSettingsPage.Controls.Add(CopyVirtIODrivers); + IsoSettingsPage.Controls.Add(gbRegionalOptions); + IsoSettingsPage.Dock = DockStyle.Fill; + IsoSettingsPage.Location = new Point(0, 0); + IsoSettingsPage.Name = "IsoSettingsPage"; + IsoSettingsPage.Size = new Size(1264, 641); + IsoSettingsPage.TabIndex = 6; + // + // label19 + // + label19.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + label19.AutoEllipsis = true; + label19.Location = new Point(101, 504); + label19.Name = "label19"; + label19.Size = new Size(1084, 89); + label19.TabIndex = 14; + label19.Text = resources.GetString("label19.Text"); + label19.Visible = false; + // + // UEFICA23CB + // + UEFICA23CB.AutoSize = true; + UEFICA23CB.Checked = true; + UEFICA23CB.CheckState = CheckState.Checked; + UEFICA23CB.Location = new Point(83, 399); + UEFICA23CB.Name = "UEFICA23CB"; + UEFICA23CB.Size = new Size(380, 19); + UEFICA23CB.TabIndex = 10; + UEFICA23CB.Text = "Use Windows UEFI CA 2023 boot binaries, if available on the ISO file"; + UEFICA23CB.UseVisualStyleBackColor = true; + UEFICA23CB.CheckedChanged += UEFICA23CB_CheckedChanged; + // + // DriverExportCombo + // + DriverExportCombo.FormattingEnabled = true; + DriverExportCombo.Items.AddRange(new object[] { "Don't export drivers", "Export essential drivers (Storage Controllers and Network Adapters)", "Export all drivers" }); + DriverExportCombo.Location = new Point(83, 370); + DriverExportCombo.Name = "DriverExportCombo"; + DriverExportCombo.Size = new Size(412, 23); + DriverExportCombo.TabIndex = 9; + DriverExportCombo.SelectedIndexChanged += DriverExportCombo_SelectedIndexChanged; + // + // label13 + // + label13.AutoSize = true; + label13.Location = new Point(80, 349); + label13.Name = "label13"; + label13.Size = new Size(111, 15); + label13.TabIndex = 8; + label13.Text = "Driver export mode:"; + // + // UnattendCopyCB + // + UnattendCopyCB.AutoSize = true; + UnattendCopyCB.Location = new Point(83, 322); + UnattendCopyCB.Name = "UnattendCopyCB"; + UnattendCopyCB.Size = new Size(412, 19); + UnattendCopyCB.TabIndex = 7; + UnattendCopyCB.Text = "Make a copy of the unattended answer file that I can use on other images"; + UnattendCopyCB.UseVisualStyleBackColor = true; + UnattendCopyCB.CheckedChanged += UnattendCopyCB_CheckedChanged; + // + // ReportToolCB + // + ReportToolCB.AutoSize = true; + ReportToolCB.Checked = true; + ReportToolCB.CheckState = CheckState.Checked; + ReportToolCB.Location = new Point(83, 297); + ReportToolCB.Name = "ReportToolCB"; + ReportToolCB.Size = new Size(218, 19); + ReportToolCB.TabIndex = 7; + ReportToolCB.Text = "Add a shortcut for the reporting tool"; + ReportToolCB.UseVisualStyleBackColor = true; + ReportToolCB.CheckedChanged += ReportToolCB_CheckedChanged; + // + // label11 + // + label11.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + label11.AutoEllipsis = true; + label11.Location = new Point(17, 64); + label11.Name = "label11"; + label11.Size = new Size(1233, 52); + label11.TabIndex = 6; + label11.Text = "Configure additional settings for your customized image."; + // + // label12 + // + label12.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + label12.AutoEllipsis = true; + label12.Font = new Font("Segoe UI", 18F, FontStyle.Regular, GraphicsUnit.Point, 0); + label12.Location = new Point(14, 12); + label12.Name = "label12"; + label12.Size = new Size(1236, 45); + label12.TabIndex = 5; + label12.Text = "Specify additional settings for the image"; + // + // winutilConfigLabel + // + winutilConfigLabel.AutoSize = true; + winutilConfigLabel.Location = new Point(80, 429); + winutilConfigLabel.Name = "winutilConfigLabel"; + winutilConfigLabel.Size = new Size(127, 15); + winutilConfigLabel.TabIndex = 11; + winutilConfigLabel.Text = "WinUtil Config (JSON):"; + // + // winutilConfigTextBox + // + winutilConfigTextBox.Location = new Point(83, 450); + winutilConfigTextBox.Name = "winutilConfigTextBox"; + winutilConfigTextBox.Size = new Size(293, 23); + winutilConfigTextBox.TabIndex = 12; + winutilConfigTextBox.TextChanged += winutilConfigTextBox_TextChanged; + // + // winutilConfigBrowseBtn + // + winutilConfigBrowseBtn.FlatStyle = FlatStyle.System; + winutilConfigBrowseBtn.Location = new Point(382, 449); + winutilConfigBrowseBtn.Name = "winutilConfigBrowseBtn"; + winutilConfigBrowseBtn.Size = new Size(80, 23); + winutilConfigBrowseBtn.TabIndex = 13; + winutilConfigBrowseBtn.Text = "Browse..."; + winutilConfigBrowseBtn.UseVisualStyleBackColor = true; + winutilConfigBrowseBtn.Click += winutilConfigBrowseBtn_Click; + // + // CopyVirtIODrivers + // + CopyVirtIODrivers.AutoSize = true; + CopyVirtIODrivers.Location = new Point(83, 482); + CopyVirtIODrivers.Name = "CopyVirtIODrivers"; + CopyVirtIODrivers.Size = new Size(125, 19); + CopyVirtIODrivers.TabIndex = 7; + CopyVirtIODrivers.Text = "Copy VirtIO drivers"; + CopyVirtIODrivers.UseVisualStyleBackColor = true; + CopyVirtIODrivers.CheckedChanged += CopyVirtIODrivers_CheckedChanged; + // + // gbRegionalOptions + // + gbRegionalOptions.Controls.Add(tableLayoutPanel4); + gbRegionalOptions.Controls.Add(label20); + gbRegionalOptions.Location = new Point(80, 133); + gbRegionalOptions.Name = "gbRegionalOptions"; + gbRegionalOptions.Size = new Size(738, 158); + gbRegionalOptions.TabIndex = 15; + gbRegionalOptions.TabStop = false; + gbRegionalOptions.Text = "Regional Settings"; + // + // tableLayoutPanel4 + // + tableLayoutPanel4.ColumnCount = 2; + tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 23.2240429F)); + tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 76.7759552F)); + tableLayoutPanel4.Controls.Add(comboOffset, 1, 3); + tableLayoutPanel4.Controls.Add(label24, 0, 3); + tableLayoutPanel4.Controls.Add(label23, 0, 2); + tableLayoutPanel4.Controls.Add(label22, 0, 1); + tableLayoutPanel4.Controls.Add(label21, 0, 0); + tableLayoutPanel4.Controls.Add(comboTimeFormat, 1, 0); + tableLayoutPanel4.Controls.Add(comboIme, 1, 1); + tableLayoutPanel4.Controls.Add(comboRegion, 1, 2); + tableLayoutPanel4.Dock = DockStyle.Fill; + tableLayoutPanel4.Location = new Point(3, 42); + tableLayoutPanel4.Name = "tableLayoutPanel4"; + tableLayoutPanel4.RowCount = 4; + tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 25F)); + tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 25F)); + tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 25F)); + tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 25F)); + tableLayoutPanel4.Size = new Size(732, 113); + tableLayoutPanel4.TabIndex = 1; + // + // comboOffset + // + comboOffset.Dock = DockStyle.Fill; + comboOffset.FormattingEnabled = true; + comboOffset.Location = new Point(173, 87); + comboOffset.Name = "comboOffset"; + comboOffset.Size = new Size(556, 23); + comboOffset.TabIndex = 6; + comboOffset.SelectedIndexChanged += comboOffset_SelectedIndexChanged; + // + // label24 + // + label24.AutoSize = true; + label24.Dock = DockStyle.Fill; + label24.Location = new Point(3, 84); + label24.Name = "label24"; + label24.Size = new Size(164, 29); + label24.TabIndex = 5; + label24.Text = "Time zone:"; + label24.TextAlign = ContentAlignment.MiddleLeft; + // + // label23 + // + label23.AutoSize = true; + label23.Dock = DockStyle.Fill; + label23.Location = new Point(3, 56); + label23.Name = "label23"; + label23.Size = new Size(164, 28); + label23.TabIndex = 3; + label23.Text = "Region:"; + label23.TextAlign = ContentAlignment.MiddleLeft; + // + // label22 + // + label22.AutoSize = true; + label22.Dock = DockStyle.Fill; + label22.Location = new Point(3, 28); + label22.Name = "label22"; + label22.Size = new Size(164, 28); + label22.TabIndex = 2; + label22.Text = "Keyboard or input method:"; + label22.TextAlign = ContentAlignment.MiddleLeft; + // + // label21 + // + label21.AutoSize = true; + label21.Dock = DockStyle.Fill; + label21.Location = new Point(3, 0); + label21.Name = "label21"; + label21.Size = new Size(164, 28); + label21.TabIndex = 1; + label21.Text = "Time and currency format:"; + label21.TextAlign = ContentAlignment.MiddleLeft; + // + // comboTimeFormat + // + comboTimeFormat.Dock = DockStyle.Fill; + comboTimeFormat.FormattingEnabled = true; + comboTimeFormat.Location = new Point(173, 3); + comboTimeFormat.Name = "comboTimeFormat"; + comboTimeFormat.Size = new Size(556, 23); + comboTimeFormat.TabIndex = 4; + comboTimeFormat.SelectedIndexChanged += comboTimeFormat_SelectedIndexChanged; + // + // comboIme + // + comboIme.Dock = DockStyle.Fill; + comboIme.FormattingEnabled = true; + comboIme.Location = new Point(173, 31); + comboIme.Name = "comboIme"; + comboIme.Size = new Size(556, 23); + comboIme.TabIndex = 4; + comboIme.SelectedIndexChanged += comboIme_SelectedIndexChanged; + // + // comboRegion + // + comboRegion.Dock = DockStyle.Fill; + comboRegion.FormattingEnabled = true; + comboRegion.Location = new Point(173, 59); + comboRegion.Name = "comboRegion"; + comboRegion.Size = new Size(556, 23); + comboRegion.TabIndex = 4; + comboRegion.SelectedIndexChanged += comboRegion_SelectedIndexChanged; + // + // label20 + // + label20.AutoSize = true; + label20.Dock = DockStyle.Top; + label20.Location = new Point(3, 19); + label20.Name = "label20"; + label20.Padding = new Padding(4); + label20.Size = new Size(648, 23); + label20.TabIndex = 0; + label20.Text = "Configure the regional options for the target system. You can change these after the operating system finishes installing."; + // // FinishPage // FinishPage.Controls.Add(lnkViewCreationLogs); @@ -434,153 +725,6 @@ private void InitializeComponent() label15.TabIndex = 7; label15.Text = "Customizations in progress"; // - // IsoSettingsPage - // - IsoSettingsPage.Controls.Add(label19); - IsoSettingsPage.Controls.Add(UEFICA23CB); - IsoSettingsPage.Controls.Add(DriverExportCombo); - IsoSettingsPage.Controls.Add(label13); - IsoSettingsPage.Controls.Add(UnattendCopyCB); - IsoSettingsPage.Controls.Add(ReportToolCB); - IsoSettingsPage.Controls.Add(label11); - IsoSettingsPage.Controls.Add(label12); - IsoSettingsPage.Controls.Add(winutilConfigLabel); - IsoSettingsPage.Controls.Add(winutilConfigTextBox); - IsoSettingsPage.Controls.Add(winutilConfigBrowseBtn); - IsoSettingsPage.Controls.Add(CopyVirtIODrivers); - IsoSettingsPage.Dock = DockStyle.Fill; - IsoSettingsPage.Location = new Point(0, 0); - IsoSettingsPage.Name = "IsoSettingsPage"; - IsoSettingsPage.Size = new Size(1264, 641); - IsoSettingsPage.TabIndex = 6; - // - // label19 - // - label19.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; - label19.AutoEllipsis = true; - label19.Location = new Point(101, 340); - label19.Name = "label19"; - label19.Size = new Size(1062, 243); - label19.TabIndex = 14; - label19.Text = resources.GetString("label19.Text"); - label19.Visible = false; - // - // UEFICA23CB - // - UEFICA23CB.AutoSize = true; - UEFICA23CB.Checked = true; - UEFICA23CB.CheckState = CheckState.Checked; - UEFICA23CB.Location = new Point(83, 235); - UEFICA23CB.Name = "UEFICA23CB"; - UEFICA23CB.Size = new Size(380, 19); - UEFICA23CB.TabIndex = 10; - UEFICA23CB.Text = "Use Windows UEFI CA 2023 boot binaries, if available on the ISO file"; - UEFICA23CB.UseVisualStyleBackColor = true; - UEFICA23CB.CheckedChanged += UEFICA23CB_CheckedChanged; - // - // DriverExportCombo - // - DriverExportCombo.FormattingEnabled = true; - DriverExportCombo.Items.AddRange(new object[] { "Don't export drivers", "Export essential drivers (Storage Controllers and Network Adapters)", "Export all drivers" }); - DriverExportCombo.Location = new Point(83, 206); - DriverExportCombo.Name = "DriverExportCombo"; - DriverExportCombo.Size = new Size(412, 23); - DriverExportCombo.TabIndex = 9; - DriverExportCombo.SelectedIndexChanged += DriverExportCombo_SelectedIndexChanged; - // - // label13 - // - label13.AutoSize = true; - label13.Location = new Point(80, 185); - label13.Name = "label13"; - label13.Size = new Size(111, 15); - label13.TabIndex = 8; - label13.Text = "Driver export mode:"; - // - // UnattendCopyCB - // - UnattendCopyCB.AutoSize = true; - UnattendCopyCB.Location = new Point(83, 158); - UnattendCopyCB.Name = "UnattendCopyCB"; - UnattendCopyCB.Size = new Size(412, 19); - UnattendCopyCB.TabIndex = 7; - UnattendCopyCB.Text = "Make a copy of the unattended answer file that I can use on other images"; - UnattendCopyCB.UseVisualStyleBackColor = true; - UnattendCopyCB.CheckedChanged += UnattendCopyCB_CheckedChanged; - // - // ReportToolCB - // - ReportToolCB.AutoSize = true; - ReportToolCB.Checked = true; - ReportToolCB.CheckState = CheckState.Checked; - ReportToolCB.Location = new Point(83, 133); - ReportToolCB.Name = "ReportToolCB"; - ReportToolCB.Size = new Size(218, 19); - ReportToolCB.TabIndex = 7; - ReportToolCB.Text = "Add a shortcut for the reporting tool"; - ReportToolCB.UseVisualStyleBackColor = true; - ReportToolCB.CheckedChanged += ReportToolCB_CheckedChanged; - // - // label11 - // - label11.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; - label11.AutoEllipsis = true; - label11.Location = new Point(17, 64); - label11.Name = "label11"; - label11.Size = new Size(1233, 52); - label11.TabIndex = 6; - label11.Text = "Configure additional settings for your customized image."; - // - // label12 - // - label12.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; - label12.AutoEllipsis = true; - label12.Font = new Font("Segoe UI", 18F, FontStyle.Regular, GraphicsUnit.Point, 0); - label12.Location = new Point(14, 12); - label12.Name = "label12"; - label12.Size = new Size(1236, 45); - label12.TabIndex = 5; - label12.Text = "Specify additional settings for the image"; - // - // winutilConfigLabel - // - winutilConfigLabel.AutoSize = true; - winutilConfigLabel.Location = new Point(80, 265); - winutilConfigLabel.Name = "winutilConfigLabel"; - winutilConfigLabel.Size = new Size(127, 15); - winutilConfigLabel.TabIndex = 11; - winutilConfigLabel.Text = "WinUtil Config (JSON):"; - // - // winutilConfigTextBox - // - winutilConfigTextBox.Location = new Point(83, 286); - winutilConfigTextBox.Name = "winutilConfigTextBox"; - winutilConfigTextBox.Size = new Size(293, 23); - winutilConfigTextBox.TabIndex = 12; - winutilConfigTextBox.TextChanged += winutilConfigTextBox_TextChanged; - // - // winutilConfigBrowseBtn - // - winutilConfigBrowseBtn.FlatStyle = FlatStyle.System; - winutilConfigBrowseBtn.Location = new Point(382, 285); - winutilConfigBrowseBtn.Name = "winutilConfigBrowseBtn"; - winutilConfigBrowseBtn.Size = new Size(80, 23); - winutilConfigBrowseBtn.TabIndex = 13; - winutilConfigBrowseBtn.Text = "Browse..."; - winutilConfigBrowseBtn.UseVisualStyleBackColor = true; - winutilConfigBrowseBtn.Click += winutilConfigBrowseBtn_Click; - // - // CopyVirtIODrivers - // - CopyVirtIODrivers.AutoSize = true; - CopyVirtIODrivers.Location = new Point(83, 318); - CopyVirtIODrivers.Name = "CopyVirtIODrivers"; - CopyVirtIODrivers.Size = new Size(125, 19); - CopyVirtIODrivers.TabIndex = 7; - CopyVirtIODrivers.Text = "Copy VirtIO drivers"; - CopyVirtIODrivers.UseVisualStyleBackColor = true; - CopyVirtIODrivers.CheckedChanged += CopyVirtIODrivers_CheckedChanged; - // // UserAccountsPage // UserAccountsPage.Controls.Add(panel1); @@ -1101,6 +1245,12 @@ private void InitializeComponent() ButtonPanel.ResumeLayout(false); TableLayoutPanel1.ResumeLayout(false); PageContainerPanel.ResumeLayout(false); + IsoSettingsPage.ResumeLayout(false); + IsoSettingsPage.PerformLayout(); + gbRegionalOptions.ResumeLayout(false); + gbRegionalOptions.PerformLayout(); + tableLayoutPanel4.ResumeLayout(false); + tableLayoutPanel4.PerformLayout(); FinishPage.ResumeLayout(false); FinishPage.PerformLayout(); panel4.ResumeLayout(false); @@ -1109,8 +1259,6 @@ private void InitializeComponent() IsoCreationPage.PerformLayout(); pnlProgress.ResumeLayout(false); pnlProgress.PerformLayout(); - IsoSettingsPage.ResumeLayout(false); - IsoSettingsPage.PerformLayout(); UserAccountsPage.ResumeLayout(false); UserAccountsPage.PerformLayout(); panel1.ResumeLayout(false); @@ -1220,5 +1368,16 @@ private void InitializeComponent() private CheckBox UEFICA23CB; internal Label label19; private ColumnHeader columnHeader4; + private GroupBox gbRegionalOptions; + private TableLayoutPanel tableLayoutPanel4; + private Label label20; + private ComboBox comboOffset; + private Label label24; + private Label label23; + private Label label22; + private Label label21; + private ComboBox comboTimeFormat; + private ComboBox comboIme; + private ComboBox comboRegion; } } diff --git a/MicroWin/MainForm.cs b/MicroWin/MainForm.cs index cecce31..b6cd3d9 100755 --- a/MicroWin/MainForm.cs +++ b/MicroWin/MainForm.cs @@ -1,12 +1,14 @@ using Microsoft.Dism; using Microsoft.Win32; using MicroWin.Classes; +using MicroWin.Classes.Regional; using MicroWin.functions.dism; using MicroWin.functions.Helpers.DeleteFile; using MicroWin.functions.Helpers.DesktopWindowManager; using MicroWin.functions.Helpers.DriverHelpers; using MicroWin.functions.Helpers.Loggers; using MicroWin.functions.Helpers.PowerManagement; +using MicroWin.functions.Helpers.ProgramResources; using MicroWin.functions.Helpers.PropertyCheckers; using MicroWin.functions.Helpers.RegistryHelpers; using MicroWin.functions.Helpers.WMI; @@ -50,6 +52,19 @@ public partial class MainForm : Form private bool isEsdFile = false; + // REGIONAL SETTINGS + private List geoIds = []; + private List imageLanguages = []; + private List keyboardIdentifiers = []; + private List timeOffsets = []; + private List userLocales = []; + + private static readonly UserLocale defaultLocale = new() { Id = "en-US", DisplayName = "English (United States)", LCID = "0409", KeyboardLayout = "00000409", GeoLocation = "244" }; + private static UserLocale finalLocale = defaultLocale.Clone(); + private static TimeOffset defaultOffset = new() { Id = "UTC", DisplayName = "(UTC) Coordinated Universal Time" }; + private static TimeOffset finalOffset = defaultOffset.Clone(); + + public MainForm() { InitializeComponent(); @@ -87,6 +102,15 @@ private void SetColorMode() logTB.ForeColor = ForeColor; winutilConfigTextBox.BackColor = BackColor; winutilConfigTextBox.ForeColor = ForeColor; + gbRegionalOptions.ForeColor = ForeColor; + comboOffset.BackColor = BackColor; + comboOffset.ForeColor = ForeColor; + comboIme.BackColor = BackColor; + comboIme.ForeColor = ForeColor; + comboTimeFormat.BackColor = BackColor; + comboTimeFormat.ForeColor = ForeColor; + comboRegion.BackColor = BackColor; + comboRegion.ForeColor = ForeColor; WindowHelper.ToggleDarkTitleBar(Handle, colorVal == 0); } @@ -163,27 +187,33 @@ private bool VerifyOptionsInPage(WizardPage.Page wizardPage) } #pragma warning disable CS8602 - if (VersionComparer.IsOlderThanVersion(imageInfo.ElementAtOrDefault(AppState.SelectedImageIndex - 1 ?? 0).ProductVersion, VersionComparer.VERCONST_WIN10)) { + if (VersionComparer.IsOlderThanVersion(imageInfo.ElementAtOrDefault(AppState.SelectedImageIndex - 1 ?? 0).ProductVersion, VersionComparer.VERCONST_WIN10)) + { MessageBox.Show("Windows images containing Windows 10 1809 or earlier are not supported."); return false; } #pragma warning restore CS8602 // If we are in ESD mode, we'll begin the export procedure - if (isEsdFile) { + if (isEsdFile) + { string sourceEsd = Path.Combine(AppState.MountPath, "sources", "install.esd"), destinationWim = Path.Combine(AppState.MountPath, "sources", "install.wim"); MessageBox.Show("Your Windows image will be converted to an editable format.", Text, MessageBoxButtons.OK, MessageBoxIcon.Information); - if (!DismManager.ExportImage(sourceEsd, AppState.SelectedImageIndex, destinationWim, "max")) { + if (!DismManager.ExportImage(sourceEsd, AppState.SelectedImageIndex, destinationWim, "max")) + { MessageBox.Show("Your Windows image could not be converted to an editable format.", Text, MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } - try { + try + { File.Delete(sourceEsd); - } catch { + } + catch + { string cmdProcPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "system32", "cmd.exe"), takeownPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "system32", "takeown.exe"), icaclsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "system32", "icacls.exe"); @@ -292,6 +322,33 @@ private void MainForm_Load(object sender, EventArgs e) columnHeader4.Width = WindowHelper.ScaleLogical(128); columnHeader5.Width = WindowHelper.ScaleLogical(84); columnHeader6.Width = WindowHelper.ScaleLogical(160); + + // Load regional settings + geoIds = GeoId.LoadItems().OrderBy(entry => entry.DisplayName).ToList(); + imageLanguages = ImageLanguage.LoadItems().OrderBy(entry => entry.DisplayName).ToList(); + keyboardIdentifiers = KeyboardIdentifier.LoadItems().OrderBy(entry => entry.DisplayName).ToList(); + timeOffsets = TimeOffset.LoadItems().OrderBy(entry => entry.DisplayName).ToList(); + userLocales = UserLocale.LoadItems().OrderBy(entry => entry.DisplayName).ToList(); + + comboTimeFormat.Items.AddRange(userLocales.Select(locale => locale.DisplayName).ToArray()); + comboIme.Items.AddRange(keyboardIdentifiers.Select(keyboard => $"{keyboard.DisplayName}{(keyboard.GetKeyboardType() == KeyboardType.IME ? " (IME)" : "")}").ToArray()); + comboRegion.Items.AddRange(geoIds.Select(geoId => geoId.DisplayName).ToArray()); + comboOffset.Items.AddRange(timeOffsets.Select(offset => offset.DisplayName).ToArray()); + + try + { + comboTimeFormat.SelectedItem = defaultLocale.DisplayName; + comboIme.SelectedItem = keyboardIdentifiers.FirstOrDefault(kbd => kbd.Id == defaultLocale.KeyboardLayout)?.DisplayName; + comboRegion.SelectedItem = geoIds.FirstOrDefault(geoId => geoId.Id == defaultLocale.GeoLocation)?.DisplayName; + comboOffset.SelectedItem = "(UTC) Coordinated Universal Time"; + } + catch + { + + } + + AppState.userLocale = finalLocale.Clone(); + AppState.timeOffset = finalOffset.Clone(); } @@ -370,7 +427,8 @@ private void LoadWimData() if (File.Exists(wimPath)) { - if (Path.GetExtension(wimPath).EndsWith("esd", StringComparison.OrdinalIgnoreCase)) { + if (Path.GetExtension(wimPath).EndsWith("esd", StringComparison.OrdinalIgnoreCase)) + { // ESD files require that we export them first to WIM. This will be done later, // because we'll be able to know the index. isEsdFile = true; @@ -777,7 +835,9 @@ await Task.Run(() => } }); } - } catch { + } + catch + { WriteLogMessage("Could not download VirtIO drivers..."); } } @@ -851,16 +911,18 @@ await Task.Run(() => { // Check if we can do it using the embedded resource; otherwise grab it from the internet. string firstStartupPath = Path.Combine(AppState.ScratchPath, "Windows", "FirstStartup.ps1"); - try { - Assembly currentAssembly = Assembly.GetExecutingAssembly(); - using Stream resourceStream = currentAssembly.GetManifestResourceStream("MicroWin.tools.FirstStartup.ps1"); + try + { + using Stream resourceStream = ResourceHelper.GetProgramResourceStream("MicroWin.tools.FirstStartup.ps1"); if (resourceStream is null) throw new Exception(); using StreamReader sr = new(resourceStream); string firstRunScriptContents = sr.ReadToEnd(); File.WriteAllText(firstStartupPath, firstRunScriptContents, new UTF8Encoding(false)); - } catch { + } + catch + { DynaLog.logMessage("Could not get embedded res. Downloading from internet."); using HttpClient client = new(); byte[] data = client.GetByteArrayAsync("https://github.com/CodingWonders/MicroWin/raw/main/MicroWin/tools/FirstStartup.ps1").GetAwaiter().GetResult(); @@ -978,7 +1040,8 @@ await Task.Run(() => RegistryHelper.UnloadRegistryHive("zDEFAULT"); RegistryHelper.UnloadRegistryHive("zNTUSER"); - if (Directory.Exists(bootDriverPath)) { + if (Directory.Exists(bootDriverPath)) + { UpdateCurrentStatus("Installing system drivers..."); DriverInstallHelper.InstallDrivers(AppState.ScratchPath, bootDriverPath, (message) => WriteLogMessage(message)); } @@ -1167,5 +1230,46 @@ private void Cancel_Button_Click(object sender, EventArgs e) { Close(); } + + private void comboTimeFormat_SelectedIndexChanged(object sender, EventArgs e) + { + // Reselect the locale + UserLocale selectedLocale = userLocales[comboTimeFormat.SelectedIndex]; + int keyboardLayoutIndex = keyboardIdentifiers.FindIndex(keybId => keybId.Id == selectedLocale.KeyboardLayout); + int geoIdIndex = geoIds.FindIndex(geoId => geoId.Id == selectedLocale.GeoLocation); + finalLocale = selectedLocale.Clone(); + +#nullable disable + comboIme.SelectedIndexChanged -= comboIme_SelectedIndexChanged; + comboRegion.SelectedIndexChanged -= comboRegion_SelectedIndexChanged; + if (keyboardLayoutIndex > -1) comboIme.SelectedIndex = keyboardLayoutIndex; + if (geoIdIndex > -1) comboRegion.SelectedIndex = geoIdIndex; + comboIme.SelectedIndexChanged += comboIme_SelectedIndexChanged; + comboRegion.SelectedIndexChanged += comboRegion_SelectedIndexChanged; + + // set user preferences + finalLocale.GeoLocation = geoIds[comboRegion.SelectedIndex].Id; + finalLocale.KeyboardLayout = keyboardIdentifiers[comboIme.SelectedIndex].Id; +#nullable restore + AppState.userLocale = finalLocale.Clone(); + } + + private void comboIme_SelectedIndexChanged(object sender, EventArgs e) + { + finalLocale.KeyboardLayout = keyboardIdentifiers[comboIme.SelectedIndex].Id; + AppState.userLocale = finalLocale.Clone(); + } + + private void comboRegion_SelectedIndexChanged(object sender, EventArgs e) + { + finalLocale.GeoLocation = geoIds[comboRegion.SelectedIndex].Id; + AppState.userLocale = finalLocale.Clone(); + } + + private void comboOffset_SelectedIndexChanged(object sender, EventArgs e) + { + finalOffset = timeOffsets[comboOffset.SelectedIndex].Clone(); + AppState.timeOffset = finalOffset.Clone(); + } } } diff --git a/MicroWin/MainForm.resx b/MicroWin/MainForm.resx index b0a6ead..f6568f5 100644 --- a/MicroWin/MainForm.resx +++ b/MicroWin/MainForm.resx @@ -117,17 +117,17 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - To continue with OS installation, use a tool to create bootable USB drives, such as Rufus or Ventoy, and install the system. - -If you want to continue customizing this system, use either of the following: - To proceed with installation of the MicroWin image in QEMU/Proxmox VE: 1. Proceed with Setup until you reach the disk selection screen, in which you won't see any drives 2. Click "Load Driver" and click Browse 3. In the folder selection dialog, point to this path: "D:\VirtIO\vioscsi\w11\amd64" (replace amd64 with ARM64 if you are using Windows on ARM, and "D:" with the drive letter of the ISO) 4. Select all drivers that will appear in the list box and click OK" + + + To continue with OS installation, use a tool to create bootable USB drives, such as Rufus or Ventoy, and install the system. + +If you want to continue customizing this system, use either of the following: Enter the information that will be used to create the first user account on the target system. Additional users can be created later. You can skip entering this information. In that case, default values will be used. diff --git a/MicroWin/MicroWin.csproj b/MicroWin/MicroWin.csproj index 9612a4e..0f51dbd 100755 --- a/MicroWin/MicroWin.csproj +++ b/MicroWin/MicroWin.csproj @@ -18,6 +18,14 @@ 2.1.0.0 + + + + + + + + @@ -30,6 +38,11 @@ + + + + + diff --git a/MicroWin/Resources/Regional/GeoId.xml b/MicroWin/Resources/Regional/GeoId.xml new file mode 100644 index 0000000..a978a5d --- /dev/null +++ b/MicroWin/Resources/Regional/GeoId.xml @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MicroWin/Resources/Regional/ImageLanguage.xml b/MicroWin/Resources/Regional/ImageLanguage.xml new file mode 100644 index 0000000..68ff579 --- /dev/null +++ b/MicroWin/Resources/Regional/ImageLanguage.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MicroWin/Resources/Regional/KeyboardIdentifier.xml b/MicroWin/Resources/Regional/KeyboardIdentifier.xml new file mode 100644 index 0000000..c1b9daf --- /dev/null +++ b/MicroWin/Resources/Regional/KeyboardIdentifier.xml @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MicroWin/Resources/Regional/TimeOffset.xml b/MicroWin/Resources/Regional/TimeOffset.xml new file mode 100644 index 0000000..3b958d5 --- /dev/null +++ b/MicroWin/Resources/Regional/TimeOffset.xml @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MicroWin/Resources/Regional/UserLocale.xml b/MicroWin/Resources/Regional/UserLocale.xml new file mode 100644 index 0000000..6961cd4 --- /dev/null +++ b/MicroWin/Resources/Regional/UserLocale.xml @@ -0,0 +1,689 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MicroWin/functions/Helpers/ProgramResources/ResourceHelper.cs b/MicroWin/functions/Helpers/ProgramResources/ResourceHelper.cs new file mode 100644 index 0000000..c12e191 --- /dev/null +++ b/MicroWin/functions/Helpers/ProgramResources/ResourceHelper.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace MicroWin.functions.Helpers.ProgramResources +{ + public class ResourceHelper + { + + public static Stream? GetProgramResourceStream(string resourceName) { + Assembly currentAssembly = Assembly.GetExecutingAssembly(); + try { + return currentAssembly.GetManifestResourceStream(resourceName); + } catch { + return null; + } + } + + } +} diff --git a/MicroWin/functions/OSCDIMG/OscdimgUtilities.cs b/MicroWin/functions/OSCDIMG/OscdimgUtilities.cs index 9166ea7..96c5875 100644 --- a/MicroWin/functions/OSCDIMG/OscdimgUtilities.cs +++ b/MicroWin/functions/OSCDIMG/OscdimgUtilities.cs @@ -1,4 +1,5 @@ using MicroWin.functions.Helpers.Loggers; +using MicroWin.functions.Helpers.ProgramResources; using MicroWin.functions.Helpers.RegistryHelpers; using System; using System.Diagnostics; @@ -46,8 +47,7 @@ public static void CheckAndInvokeOscdimgBinaries(Action? outputReporter #pragma warning disable CS8600 if (outputReporter is not null) outputReporter.Invoke("Extracting OSCDIMG binaries..."); - Assembly currentAssembly = Assembly.GetExecutingAssembly(); - using Stream resourceStream = currentAssembly.GetManifestResourceStream("MicroWin.tools.oscdimg.exe"); + using Stream resourceStream = ResourceHelper.GetProgramResourceStream("MicroWin.tools.oscdimg.exe"); if (resourceStream is not null) { byte[] oscdimgBytes = new byte[resourceStream.Length]; diff --git a/MicroWin/functions/dism/UnattendGenerator.cs b/MicroWin/functions/dism/UnattendGenerator.cs index 7e81d19..c22fb00 100755 --- a/MicroWin/functions/dism/UnattendGenerator.cs +++ b/MicroWin/functions/dism/UnattendGenerator.cs @@ -1,8 +1,11 @@ using MicroWin.Classes; +using MicroWin.Classes.Regional; using MicroWin.functions.Helpers.Loggers; using MicroWin.functions.Helpers.PropertyCheckers; using System; +using System.Globalization; using System.IO; +using System.Security; using System.Text; namespace MicroWin.functions.dism @@ -90,7 +93,21 @@ public static void CreateUnattend(string destinationPath, Version? sourceVersion xml.AppendLine(" "); xml.AppendLine(" "); xml.AppendLine(" "); + xml.AppendLine(" "); + xml.AppendLine(" "); + string? inputLocale = GetInputLocale(AppState.userLocale); + if (!string.IsNullOrEmpty(inputLocale)) + xml.AppendLine($"{EscapeXml(inputLocale)}"); + xml.AppendLine(" "); + if (!string.IsNullOrWhiteSpace(AppState.userLocale?.Id)) + { + xml.AppendLine($" {EscapeXml(AppState.userLocale.Id)}"); + xml.AppendLine($" {EscapeXml(AppState.userLocale.Id)}"); + } + xml.AppendLine(" "); xml.AppendLine(" "); + if (!string.IsNullOrWhiteSpace(AppState.timeOffset?.Id)) + xml.AppendLine($" {EscapeXml(AppState.timeOffset.Id)}"); xml.AppendLine(" "); xml.AppendLine(" "); foreach (UserAccount user in AppState.UserAccounts) @@ -149,6 +166,13 @@ public static void CreateUnattend(string destinationPath, Version? sourceVersion xml.AppendLine(" 4"); xml.AppendLine(" powershell -ExecutionPolicy Bypass -File c:\\windows\\FirstStartup.ps1"); xml.AppendLine(" "); + if (int.TryParse(AppState.userLocale?.GeoLocation, NumberStyles.None, CultureInfo.InvariantCulture, out int geoId)) + { + xml.AppendLine(" "); + xml.AppendLine(" 5"); + xml.AppendLine($" powershell.exe -NoProfile -Command \"Set-WinHomeLocation -GeoId {geoId}\""); + xml.AppendLine(" "); + } xml.AppendLine(" "); xml.AppendLine(" "); xml.AppendLine(" "); @@ -179,5 +203,37 @@ public static void CreateUnattend(string destinationPath, Version? sourceVersion DynaLog.logMessage($"Unattended file could not be made: {ex.Message}"); } } + + private static string? GetInputLocale(UserLocale? locale) + { + if (locale is null || string.IsNullOrWhiteSpace(locale.KeyboardLayout)) + return null; + + string keyboardLayout = locale.KeyboardLayout; + KeyboardIdentifier? keyboard = KeyboardIdentifier.LoadItems().Find(item => + string.Equals(item.Id, keyboardLayout, StringComparison.OrdinalIgnoreCase)); + + if (keyboard?.GetKeyboardType() == KeyboardType.IME) + return EscapeXml(keyboardLayout); + + string lcid = locale.LCID; + if (string.Equals(lcid, "1000", StringComparison.OrdinalIgnoreCase)) + { + try + { + lcid = CultureInfo.GetCultureInfo(locale.Id).LCID.ToString("x4", CultureInfo.InvariantCulture); + } + catch (CultureNotFoundException) + { + } + } + + return EscapeXml($"{lcid}:{keyboardLayout}"); + } + + private static string EscapeXml(string value) + { + return SecurityElement.Escape(value) ?? string.Empty; + } } } \ No newline at end of file From 1d837dbdfc81f6079c635f9d2d6afafbbf2e0fb2 Mon Sep 17 00:00:00 2001 From: CodingWonders <101426328+CodingWonders@users.noreply.github.com> Date: Tue, 20 Oct 2026 07:41:14 +0200 Subject: [PATCH 2/3] Add version identifier --- VERSION | 1 + 1 file changed, 1 insertion(+) create mode 100644 VERSION diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..5fcca2a --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +2.0.1.0 From 874181cc9cd8ea7047baf900d092190b39ab80b7 Mon Sep 17 00:00:00 2001 From: CodingWonders <101426328+CodingWonders@users.noreply.github.com> Date: Tue, 20 Oct 2026 07:49:29 +0200 Subject: [PATCH 3/3] Add some logging --- MicroWin/functions/dism/UnattendGenerator.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MicroWin/functions/dism/UnattendGenerator.cs b/MicroWin/functions/dism/UnattendGenerator.cs index c22fb00..064b11b 100755 --- a/MicroWin/functions/dism/UnattendGenerator.cs +++ b/MicroWin/functions/dism/UnattendGenerator.cs @@ -96,6 +96,7 @@ public static void CreateUnattend(string destinationPath, Version? sourceVersion xml.AppendLine(" "); xml.AppendLine(" "); string? inputLocale = GetInputLocale(AppState.userLocale); + DynaLog.logMessage($"Regional locale settings: locale={AppState.userLocale?.Id ?? "(not set)"}, inputLocale={inputLocale ?? "(not set)"}, GeoID={AppState.userLocale?.GeoLocation ?? "(not set)"}."); if (!string.IsNullOrEmpty(inputLocale)) xml.AppendLine($"{EscapeXml(inputLocale)}"); xml.AppendLine(" "); @@ -106,6 +107,7 @@ public static void CreateUnattend(string destinationPath, Version? sourceVersion } xml.AppendLine(" "); xml.AppendLine(" "); + DynaLog.logMessage($"Regional time zone setting: {AppState.timeOffset?.Id ?? "(not set)"}."); if (!string.IsNullOrWhiteSpace(AppState.timeOffset?.Id)) xml.AppendLine($" {EscapeXml(AppState.timeOffset.Id)}"); xml.AppendLine(" "); @@ -168,11 +170,16 @@ public static void CreateUnattend(string destinationPath, Version? sourceVersion xml.AppendLine(" "); if (int.TryParse(AppState.userLocale?.GeoLocation, NumberStyles.None, CultureInfo.InvariantCulture, out int geoId)) { + DynaLog.logMessage($"GeoID {geoId} will be applied during first logon."); xml.AppendLine(" "); xml.AppendLine(" 5"); xml.AppendLine($" powershell.exe -NoProfile -Command \"Set-WinHomeLocation -GeoId {geoId}\""); xml.AppendLine(" "); } + else if (!string.IsNullOrWhiteSpace(AppState.userLocale?.GeoLocation)) + { + DynaLog.logMessage($"GeoID value '{AppState.userLocale.GeoLocation}' is invalid and will not be applied."); + } xml.AppendLine(" "); xml.AppendLine(" "); xml.AppendLine(" ");