Browse Source

feat(SelectWindowsImage): return winver & check it

pull/13/head
he3als 2 months ago
parent
commit
544083e817
Signed by: he3als GPG Key ID: A0FC52EA5368ECF4
6 changed files with 230 additions and 69 deletions
  1. +14
    -15
      src/Actions/.NET.cs
  2. +1
    -0
      src/Ameliorated.ConsoleUtils/ConsoleTUI/FrameWriteMethods.cs
  3. +1
    -1
      src/Globals.cs
  4. +192
    -51
      src/Misc/SelectWindowsImage.cs
  5. +15
    -2
      src/NSudo.cs
  6. +7
    -0
      src/app.manifest

+ 14
- 15
src/Actions/.NET.cs View File

@ -15,23 +15,23 @@ namespace amecs.Actions
{
public class _NET
{
private static string isoPath;
private static string mountedPath;
private static string _mountedPath;
private static string _isoPath;
private static void Unmount()
{
if (isoPath == "none")
if (_isoPath == "none")
return;
SelectWindowsImage.DismountIso(isoPath);
SelectWindowsImage.DismountIso(_isoPath);
}
public static bool Install()
{
(mountedPath, isoPath) = SelectWindowsImage.GetMediaPath();
if (mountedPath == null) return false;
(_mountedPath, _isoPath, _, _, _) = SelectWindowsImage.GetMediaPath(true);
if (_mountedPath == null) return false;
if (!Directory.Exists(mountedPath + @"\sources\sxs") || !Directory.GetFiles(mountedPath + @"\sources\sxs", "*netfx3*").Any())
if (!Directory.Exists(_mountedPath + @"\sources\sxs") || !Directory.GetFiles(_mountedPath + @"\sources\sxs", "*netfx3*").Any())
{
Unmount();
Console.WriteLine();
@ -52,9 +52,9 @@ namespace amecs.Actions
using (var session = DismApi.OpenOnlineSession())
{
var stdout = GetStdHandle(-11);
bool indicatorStopped = false;
var indicatorStopped = false;
var maxHashTags = (ConsoleTUI.OpenFrame.DisplayWidth - 5);
DismApi.EnableFeatureByPackagePath(session, "NetFX3", null, true, true, new List<string>() { mountedPath + @"\sources\sxs" }, delegate(DismProgress progress)
DismApi.EnableFeatureByPackagePath(session, "NetFX3", null, true, true, new List<string>() { _mountedPath + @"\sources\sxs" }, delegate(DismProgress progress)
{
inProgress = true;
if (!indicatorStopped)
@ -65,12 +65,11 @@ namespace amecs.Actions
}
indicatorStopped = true;
var progressPerc = progress.Current / 10;
var currentHashTags = (int)Math.Ceiling(Math.Min(((double)progressPerc / 100) * maxHashTags, maxHashTags));
var spaces = maxHashTags - currentHashTags + (4 - progressPerc.ToString().Length);
var sb = new StringBuilder(new string('#', currentHashTags) + new string(' ', spaces) + progressPerc + "%");
uint throwaway;
WriteConsoleOutputCharacter(stdout, sb, (uint)sb.Length, new Languages.COORD((short)ConsoleTUI.OpenFrame.DisplayOffset, (short)Console.CursorTop), out throwaway);
var progressPercentage = progress.Current / 10;
var currentHashTags = (int)Math.Ceiling(Math.Min(((double)progressPercentage / 100) * maxHashTags, maxHashTags));
var spaces = maxHashTags - currentHashTags + (4 - progressPercentage.ToString().Length);
var sb = new StringBuilder(new string('#', currentHashTags) + new string(' ', spaces) + progressPercentage + "%");
WriteConsoleOutputCharacter(stdout, sb, (uint)sb.Length, new Languages.COORD((short)ConsoleTUI.OpenFrame.DisplayOffset, (short)Console.CursorTop), out _);
inProgress = false;
});
session.Close();


+ 1
- 0
src/Ameliorated.ConsoleUtils/ConsoleTUI/FrameWriteMethods.cs View File

@ -323,6 +323,7 @@ namespace Ameliorated.ConsoleUtils
ConsoleUtils.ResetColor();
}
// TODO: Fix this splitting lines when a piece of text can fit on one line
private List<CenteredString> CenterLines(string text, LineCenterOptions options, int maxWidth = 0)
{
var _maxWidth = DisplayWidth;


+ 1
- 1
src/Globals.cs View File

@ -36,6 +36,6 @@ namespace amecs
return true;
}
public static readonly int WinVer = Int32.Parse(Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValue("CurrentBuildNumber").ToString());
public static readonly int WinVer = int.Parse(Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValue("CurrentBuildNumber").ToString());
}
}

+ 192
- 51
src/Misc/SelectWindowsImage.cs View File

@ -1,26 +1,25 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security;
using System.Windows.Forms;
using Ameliorated.ConsoleUtils;
using Microsoft.Dism;
// Asks user to select Windows installation media, and mounts it if applicable
// Returns path to where it's mounted
namespace amecs.Misc
{
/// <summary>
/// Asks user to select Windows installation media, and mounts it if applicable
/// Returns path to where it's mounted
/// </summary>
public class SelectWindowsImage
public static class SelectWindowsImage
{
private static string file;
private static string _fileViolationTest;
private static bool CheckFileViolation(string inputFile)
{
try
{
file = inputFile;
_fileViolationTest = inputFile;
}
catch (SecurityException e)
{
@ -32,7 +31,22 @@ namespace amecs.Misc
return false;
}
public static bool DismountIso(string path)
public static string GetWindowsVersion(float majorMinor, int isoBuild)
{
return (majorMinor, isoBuild) switch
{
(6, _) => "Windows Vista",
(6.1f, _) => "Windows 7",
(6.2f, _) => "Windows 8",
(6.3f, _) => "Windows 8.1",
(10, var a) when a < 19041 => "Windows 10 (Old)",
(10, var a) when a >= 22000 => "Windows 11",
(10, _) => "Windows 10",
_ => "Unknown"
};
}
public static bool DismountIso(string imagePath)
{
var startInfo = new ProcessStartInfo
{
@ -40,7 +54,7 @@ namespace amecs.Misc
UseShellExecute = false,
FileName = "PowerShell.exe",
WindowStyle = ProcessWindowStyle.Hidden,
Arguments = $"-NoP -C \"Dismount-DiskImage '{path}'\"",
Arguments = $"-NoP -C \"Dismount-DiskImage '{imagePath}'\"",
RedirectStandardOutput = true
};
@ -50,11 +64,24 @@ namespace amecs.Misc
return true;
}
public static (string MountedPath, string IsoPath) GetMediaPath()
private static string _mountedPath;
private static string _isoPath;
private static string _isoWinVer;
private static int _isoBuild;
/// <summary>
/// Asks user to select Windows installation media, mounts it if applicable, and checks its version
/// </summary>
/// <param name="winVersionsMustMatch">If true when ISO and host versions mismatch, prompts user that things can break if they continue</param>
/// <param name="isoBuildMustBeReturned">If true and the ISO build can't be retrieved, prompts a user with an error</param>
public static (
string MountedPath, string IsoPath, string Winver, int? Build, bool? VersionsMatch
) GetMediaPath(bool winVersionsMustMatch = false, bool isoBuildMustBeReturned = false)
{
var error = ((string)null, "none", (string)null, (int?)null, (bool?)null);
var choice =
new ChoicePrompt() { Text = "To continue, Windows installation media is needed.\r\nDo you have a Windows USB instead of an ISO file? (Y/N): " }.Start();
if (choice == null) return (null, "none");
if (!choice.HasValue) return error;
// Folder/drive chosen
var usingFolder = choice == 0;
@ -64,56 +91,170 @@ namespace amecs.Misc
{
InputPath = Globals.UserFolder
};
if (dlg.ShowDialog(IntPtr.Zero, false).GetValueOrDefault())
return CheckFileViolation(dlg.ResultPath) ? (null, "none") : (dlg.ResultPath, "none");
Console.WriteLine();
ConsoleTUI.OpenFrame.Close("\r\nYou must select a folder or drive containing Windows installation media.",
new ChoicePrompt() { AnyKey = true, Text = "Press any key to return to the Menu: " });
return (null, "none");
}
// Mounting the ISO
var dialog = new OpenFileDialog();
dialog.Filter = "ISO Files (*.ISO)| *.ISO";
dialog.Multiselect = false;
dialog.InitialDirectory = Globals.UserFolder;
NativeWindow window = new NativeWindow();
window.AssignHandle(Process.GetCurrentProcess().MainWindowHandle);
if (dialog.ShowDialog(window) == DialogResult.OK)
{
if (CheckFileViolation(dialog.FileName)) return (null, "none");
Console.WriteLine();
ConsoleTUI.OpenFrame.WriteCentered("\r\nMounting ISO");
if (dlg.ShowDialog(IntPtr.Zero).GetValueOrDefault())
{
if (CheckFileViolation(dlg.ResultPath))
return error;
_mountedPath = dlg.ResultPath;
}
else
{
Console.WriteLine();
ConsoleTUI.OpenFrame.Close("\r\nYou must select a folder or drive containing Windows installation media.",
new ChoicePrompt() { AnyKey = true, Text = "Press any key to return to the Menu: " });
return error;
}
}
else
{
Console.WriteLine();
ConsoleTUI.OpenFrame.Close("\r\nYou must select an ISO.",
new ChoicePrompt() { AnyKey = true, Text = "Press any key to return to the Menu: " });
return (null, "none");
}
// Mounting the ISO
var dialog = new OpenFileDialog();
dialog.Filter = "ISO Files (*.ISO)| *.ISO";
dialog.Multiselect = false;
dialog.InitialDirectory = Globals.UserFolder;
using (new ConsoleUtils.LoadingIndicator(true))
var window = new NativeWindow();
window.AssignHandle(Process.GetCurrentProcess().MainWindowHandle);
if (dialog.ShowDialog(window) == DialogResult.OK)
{
_isoPath = dialog.FileName;
if (CheckFileViolation(_isoPath)) return error;
Console.WriteLine();
ConsoleTUI.OpenFrame.WriteCentered("\r\nMounting ISO");
}
else
{
Console.WriteLine();
ConsoleTUI.OpenFrame.Close("\r\nYou must select an ISO.",
new ChoicePrompt() { AnyKey = true, Text = "Press any key to return to the Menu: " });
return error;
}
using (new ConsoleUtils.LoadingIndicator(true))
{
var startInfo = new ProcessStartInfo
{
CreateNoWindow = false,
UseShellExecute = false,
FileName = "PowerShell.exe",
WindowStyle = ProcessWindowStyle.Hidden,
Arguments = $"-NoP -C \"(Mount-DiskImage '{_isoPath}' -PassThru | Get-Volume).DriveLetter + ':\'\"",
RedirectStandardOutput = true
};
var proc = Process.Start(startInfo);
if (proc == null) return error;
proc.WaitForExit();
_mountedPath = proc.StandardOutput.ReadLine();
}
}
// Check WIM version
var wimOrEsdPath = new[] { $@"{_mountedPath}\sources\install.esd", $@"{_mountedPath}\sources\install.wim" }.FirstOrDefault(File.Exists);
if (!string.IsNullOrEmpty(wimOrEsdPath))
{
var startInfo = new ProcessStartInfo
try
{
CreateNoWindow = false,
UseShellExecute = false,
FileName = "PowerShell.exe",
WindowStyle = ProcessWindowStyle.Hidden,
Arguments = $"-NoP -C \"(Mount-DiskImage '{file}' -PassThru | Get-Volume).DriveLetter + ':\'\"",
RedirectStandardOutput = true
};
DismApi.Initialize(DismLogLevel.LogErrors);
string previousIndexVersion = null;
string isoFullVersion = null;
var multiVersion = false;
var imageInfos = DismApi.GetImageInfo(wimOrEsdPath);
foreach (var imageInfo in imageInfos)
{
isoFullVersion = imageInfo.ProductVersion.ToString();
if (isoFullVersion != previousIndexVersion && previousIndexVersion != null)
{
// If it's multi-version, WinVer will be "Unknown" as well
multiVersion = true;
isoFullVersion = "0.0.0.0";
break;
}
previousIndexVersion = isoFullVersion;
}
switch (multiVersion)
{
case true when isoBuildMustBeReturned:
ConsoleTUI.OpenFrame.Close(
$"Multiple Windows versions were found in the Windows image, can't determine which Windows build it is. Please use an unmodified Windows ISO.",
ConsoleColor.Red, Console.BackgroundColor,
new ChoicePrompt() { AnyKey = true, Text = "Press any key to return to the Menu: " });
return error;
case true when winVersionsMustMatch:
ConsoleTUI.OpenFrame.Close(
$"Multiple Windows versions were found in the Windows image, can't determine which Windows build it is. If your Windows version doesn't match the ISO, there will be problems.",
ConsoleColor.Red, Console.BackgroundColor,
new ChoicePrompt() { AnyKey = true, Text = "Press any key to continue anyways: " });
Program.Frame.Clear();
ConsoleTUI.OpenFrame.WriteCentered("\r\nContinuing without version check\r\n");
break;
}
var proc = Process.Start(startInfo);
if (proc == null) return (null, "none");
proc.WaitForExit();
var buildSplit = isoFullVersion.Split('.');
_isoBuild = int.Parse(buildSplit[2]);
_isoWinVer = GetWindowsVersion(float.Parse($"{buildSplit[0]}.{buildSplit[1]}"), _isoBuild);
}
catch (Exception e)
{
Console.WriteLine();
ConsoleTUI.OpenFrame.Close(
"Error checking ISO version: " + e.Message.TrimEnd('\n').TrimEnd('\r'),
ConsoleColor.Red, Console.BackgroundColor,
new ChoicePrompt() { AnyKey = true, Text = "Press any key to return to the Menu: " });
return error;
}
finally
{
try
{
DismApi.Shutdown();
}
catch
{
// do nothing
}
}
return (proc.StandardOutput.ReadLine(), file);
// Check the current OS version
var hostVersion = Environment.OSVersion.Version;
var hostWinver = GetWindowsVersion(float.Parse($"{hostVersion.Major}.{hostVersion.Minor}"), hostVersion.Build);
// If it all matches
if (hostWinver == _isoWinVer && winVersionsMustMatch) return (_mountedPath, _isoPath, _isoWinVer, _isoBuild, true);
// If ISO version doesn't match host version, and winVersionsMustMatch is true
if (hostWinver != _isoWinVer && winVersionsMustMatch)
{
if (!string.IsNullOrEmpty(_isoPath)) DismountIso(_isoPath);
ConsoleTUI.OpenFrame.Close(
$"You're on {hostWinver}, but the selected image is {_isoWinVer}. You can only use an ISO that matches your Windows version.",
ConsoleColor.Red, Console.BackgroundColor,
new ChoicePrompt() { AnyKey = true, Text = "Press any key to return to the Menu: " });
return error;
}
// If ISO version doesn't match host version, and winVersionsMustMatch is true
if (hostWinver != _isoWinVer) return (_mountedPath, _isoPath, _isoWinVer, _isoBuild, false);
}
var noWimText = isoBuildMustBeReturned
? "Press any key to return to the Menu"
: "Press any key to continue anyways";
ConsoleTUI.OpenFrame.Close(
$"No Windows installation image was found inside the selected Windows media. No version check can be done, things might break.",
ConsoleColor.Red, Console.BackgroundColor,
new ChoicePrompt() { AnyKey = true, Text = $"{noWimText}: " });
Program.Frame.Clear();
ConsoleTUI.OpenFrame.WriteCentered("\r\nContinuing without version check\r\n");
return isoBuildMustBeReturned ? error : (_mountedPath, _isoPath, null, null, null);
}
}
}

+ 15
- 2
src/NSudo.cs View File

@ -6,6 +6,7 @@ using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;
namespace amecs
@ -505,8 +506,20 @@ namespace amecs
RtlAdjustPrivilege((int)luid, true, true, out throwaway);
}
public class Win32 {
public static void RunAsUser(Action action)
{
var token = NSudo.GetUserToken();
Task.Run((Action)Delegate.Combine((Action)(() => { NSudo.GetUserPrivilege(token); }),
action)).Wait();
Marshal.FreeHGlobal(token);
}
private static async Task RunAsUserAsync(Action action)
{
var token = NSudo.GetUserToken();
await Task.Run((Action)Delegate.Combine((Action)(() => { NSudo.GetUserPrivilege(token); }),
action));
Marshal.FreeHGlobal(token);
}
}
}

+ 7
- 0
src/app.manifest View File

@ -7,4 +7,11 @@
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Support Windows 10 and above - needed for certain functions to return
correct Windows version. https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests#supportedOS -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>

Loading…
Cancel
Save