Skip to content

Commit

Permalink
Detect current Hyper-V state; async operations; F1 info message
Browse files Browse the repository at this point in the history
  • Loading branch information
ygoe committed Aug 12, 2016
1 parent cbe13a0 commit e294605
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 34 deletions.
29 changes: 29 additions & 0 deletions HyperVSwitch/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace HyperVSwitch
{
internal static class Extensions
{
/// <summary>
/// Waits asynchronously for the process to exit.
/// </summary>
/// <param name="process">The process to wait for cancellation.</param>
/// <param name="cancellationToken">A cancellation token. If invoked, the task will return
/// immediately as canceled.</param>
/// <returns>A Task representing waiting for the process to end.</returns>
public static Task WaitForExitAsync(this Process process, CancellationToken cancellationToken = default(CancellationToken))
{
var tcs = new TaskCompletionSource<object>();
process.EnableRaisingEvents = true;
process.Exited += (sender, args) => tcs.TrySetResult(null);
if (cancellationToken != default(CancellationToken))
{
cancellationToken.Register(tcs.SetCanceled);
}
return tcs.Task;
}
}
}
1 change: 1 addition & 0 deletions HyperVSwitch/HyperVSwitch.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Extensions.cs" />
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
</Compile>
Expand Down
35 changes: 31 additions & 4 deletions HyperVSwitch/MainForm.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

100 changes: 70 additions & 30 deletions HyperVSwitch/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace HyperVSwitch
Expand All @@ -23,9 +24,24 @@ public MainForm()
{
InitializeComponent();

isHyperVActive = GetHyperVStatus();
statusLabel.Text = "Detecting current state…\nThis may take a few seconds.";
statusLabel.ForeColor = Color.Gray;
actionButton.Visible = false;
infoLabel.Text = "© 2016 Yves Goergen, GNU GPL v3";
}

#endregion Constructors

#region Window event handlers

private async void MainForm_Load(object sender, EventArgs args)
{
isHyperVActive = await GetHyperVStatus();
isHyperVRunning = GetHyperVRunning();

actionButton.Visible = true;
actionButton.Focus();

if (isHyperVActive == true)
{
statusLabel.Text = "Hyper-V is ACTIVE.";
Expand Down Expand Up @@ -53,59 +69,83 @@ public MainForm()
else
{
statusLabel.Text = "The current state of Hyper-V is UNKNOWN. The Hyper-V role may not be installed on this computer.";
statusLabel.ForeColor = SystemColors.WindowText;
actionButton.Text = "No action available";
actionButton.Enabled = false;
}
infoLabel.Text = "© 2016 Yves Goergen, GNU GPL v3";
}

#endregion Constructors

#region Window event handlers

private void MainForm_KeyDown(object sender, KeyEventArgs args)
{
if (args.KeyCode == Keys.Escape && args.Modifiers == 0)
{
Application.Exit();
}
if (args.KeyCode == Keys.F1 && args.Modifiers == 0)
{
string message =
"Hyper-V Switch allows you to enable or disable permanent virtualisation with Hyper-V without uninstalling it so that you can use Hyper-V and other virtualisation solutions like VMware or VirtualBox easily. This setting is stored in the boot configuration so that the computer must be restarted to apply the new setting.\n\n" +
"For more information please click on the link to open the website.\n\n" +
"Available keyboard shortcuts:\n\n" +
"Escape: Close program\n" +
"Shift+Click: Change state but skip restart (you need to restart manually)";
MessageBox.Show(message, "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}

#endregion Window event handlers

#region Control event handlers

private void ActionButton_Click(object sender, EventArgs args)
private async void ActionButton_Click(object sender, EventArgs args)
{
if (!justRestart)
bool shiftKeyPressed = ModifierKeys == Keys.Shift;
actionButton.Enabled = false;
try
{
if (isHyperVActive == true)
if (!justRestart)
{
if (!SetHyperVStatus(false))
if (isHyperVActive == true)
{
MessageBox.Show("Deactivating Hyper-V failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
if (!await SetHyperVStatus(false))
{
MessageBox.Show("Deactivating Hyper-V failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
}
else if (isHyperVActive == false)
{
if (!SetHyperVStatus(true))
else if (isHyperVActive == false)
{
if (!await SetHyperVStatus(true))
{
MessageBox.Show("Activating Hyper-V failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
else
{
MessageBox.Show("Activating Hyper-V failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
return; // Should not happen
}
}
else

if (!shiftKeyPressed)
{
return; // Should not happen
if (!SafeNativeMethods.ExitWindowsEx(
ExitWindows.Reboot,
ShutdownReason.MajorOperatingSystem | ShutdownReason.MinorReconfig | ShutdownReason.FlagPlanned))
{
//int error = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
//string errorMessage = new System.ComponentModel.Win32Exception(error).Message;
//MessageBox.Show($"Restarting the computer failed. {errorMessage} (Error {error}) Trying another method…", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

// ExitWindowsEx fails on Windows 10.
// Use the system command, there's no feedback from it.
Process.Start("shutdown.exe", "-r -t 0");
}
}
}

if (!SafeNativeMethods.ExitWindowsEx(
ExitWindows.RestartApps,
ShutdownReason.MajorOperatingSystem | ShutdownReason.MinorReconfig | ShutdownReason.FlagPlanned))
finally
{
MessageBox.Show("Restarting the computer failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
actionButton.Enabled = true;
}

// System is restarted. Prevent further actions
Expand All @@ -121,7 +161,7 @@ private void InfoLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs

#region Hyper-V support methods

private bool? GetHyperVStatus()
private async Task<bool?> GetHyperVStatus()
{
var startInfo = new ProcessStartInfo
{
Expand All @@ -133,6 +173,7 @@ private void InfoLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs
};
using (var process = Process.Start(startInfo))
{
await process.WaitForExitAsync();
while (!process.StandardOutput.EndOfStream)
{
string line = process.StandardOutput.ReadLine();
Expand All @@ -145,7 +186,7 @@ private void InfoLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs
return null;
}

private bool SetHyperVStatus(bool active)
private async Task<bool> SetHyperVStatus(bool active)
{
var startInfo = new ProcessStartInfo
{
Expand All @@ -156,15 +197,14 @@ private bool SetHyperVStatus(bool active)
};
using (var process = Process.Start(startInfo))
{
process.WaitForExit();
await process.WaitForExitAsync();
return process.ExitCode == 0;
}
}

private bool? GetHyperVRunning()
{
// TODO
return null;
return !SafeNativeMethods.IsProcessorFeaturePresent(ProcessorFeature.PF_VIRT_FIRMWARE_ENABLED);
}

#endregion Hyper-V support methods
Expand Down
9 changes: 9 additions & 0 deletions HyperVSwitch/SafeNativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ public static class SafeNativeMethods
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason);

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsProcessorFeaturePresent(ProcessorFeature processorFeature);
}

[Flags]
Expand Down Expand Up @@ -67,4 +71,9 @@ public enum ShutdownReason : uint
FlagUserDefined = 0x40000000,
FlagPlanned = 0x80000000
}

public enum ProcessorFeature
{
PF_VIRT_FIRMWARE_ENABLED = 21
}
}

0 comments on commit e294605

Please sign in to comment.