diff --git a/TimedShutdown.sln b/TimedShutdown.sln index 0ae9497..00039df 100644 --- a/TimedShutdown.sln +++ b/TimedShutdown.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27130.2027 +VisualStudioVersion = 15.0.27004.2005 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TimedShutdown", "TimedShutdown\TimedShutdown.csproj", "{C1158C45-7666-4586-A6DA-CCC1EE95D457}" EndProject diff --git a/TimedShutdown/Messaging.cs b/TimedShutdown/Messaging.cs new file mode 100644 index 0000000..7382da6 --- /dev/null +++ b/TimedShutdown/Messaging.cs @@ -0,0 +1,26 @@ +using System.Windows; + +namespace TimedShutdown +{ + public class Messaging + { + public enum Message + { + RemoteShutdown + } + + public void Show(Message message, string info) + { + switch (message) + { + case Message.RemoteShutdown: + MessageBox.Show( + $"The following remote machine has been sent a shutdown/reboot signal:\n\n{info}", + "Timed Shutdown", + MessageBoxButton.OK, + MessageBoxImage.Information); + break; + } + } + } +} diff --git a/TimedShutdown/PingWidget.cs b/TimedShutdown/PingWidget.cs new file mode 100644 index 0000000..f03c876 --- /dev/null +++ b/TimedShutdown/PingWidget.cs @@ -0,0 +1,50 @@ +using System.ComponentModel; +using System.Diagnostics; +using System.Net; +using System.Net.NetworkInformation; +using System.Threading; + +namespace TimedShutdown +{ + public class PingWidget + { + IPAddress _ipAddress = IPAddress.None; + public bool IsCancellationRequested { get; set; } = false; + + BackgroundWorker contPingBackgroundWorker = new BackgroundWorker(); + + public void InitatePingRequest(IPAddress ipAddress) + { + _ipAddress = ipAddress; + + contPingBackgroundWorker.DoWork += ContPingBackgroundWorkerDoWork; + contPingBackgroundWorker.RunWorkerAsync(); + } + + /// + /// Will continuously ping the input IP address every 5 seconds, + /// will stop if a cancellation request is made. + /// + /// + /// + private void ContPingBackgroundWorkerDoWork(object sender, DoWorkEventArgs e) + { + + while (IsCancellationRequested == false) + { + Thread.Sleep(5000); + + Ping pingSender = new Ping(); + IPAddress address = _ipAddress; + PingReply reply = pingSender.Send(address); + + if (reply.Status == IPStatus.Success) + Debug.WriteLine("Ping Success!"); + else + { + Debug.WriteLine(reply.Status); + } + } + } + } +} diff --git a/TimedShutdown/Properties/AssemblyInfo.cs b/TimedShutdown/Properties/AssemblyInfo.cs index 737b87e..4eb03ae 100644 --- a/TimedShutdown/Properties/AssemblyInfo.cs +++ b/TimedShutdown/Properties/AssemblyInfo.cs @@ -51,5 +51,5 @@ using System.Windows; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.1.0.0")] +[assembly: AssemblyFileVersion("1.1.0.0")] diff --git a/TimedShutdown/ShutdownManager.cs b/TimedShutdown/ShutdownManager.cs index 6915e61..6479900 100644 --- a/TimedShutdown/ShutdownManager.cs +++ b/TimedShutdown/ShutdownManager.cs @@ -1,10 +1,15 @@ using System; using System.Diagnostics; +using System.Net.Sockets; namespace TimedShutdown { public class ShutdownManager { + private readonly Func _funcForceShutdown = ForceShutdown; + private readonly Func _funcShutdownOperation = ShutdownOperation; + private readonly Func _funcRemoteShutdown = RemoteShutdown; + public enum Operation { Shutdown, @@ -17,18 +22,16 @@ namespace TimedShutdown /// /// /// - public void ExecuteOperation(Operation shutdownoperation, int shutdownSeconds, bool forceShutdownState) + public void ExecuteOperation(Operation shutdownoperation, int shutdownSeconds, bool forceShutdownState, string remoteShutdown) { - Func forceShutdown = ForceShutdown; - Func shutdownOperation = ShutdownOperation; - ProcessStartInfo info = new ProcessStartInfo(); Process proc = new Process(); info.FileName = "cmd.exe"; - info.Arguments = $"/c shutdown {ShutdownOperation(shutdownoperation)} -t" + + info.Arguments = $"/c shutdown {_funcShutdownOperation(shutdownoperation)} -t" + $" {shutdownSeconds}" + - $" {ForceShutdown(forceShutdownState)}"; + $" {_funcForceShutdown(forceShutdownState)}" + + $" {_funcRemoteShutdown(remoteShutdown)}"; info.WindowStyle = ProcessWindowStyle.Hidden; info.CreateNoWindow = true; @@ -36,22 +39,23 @@ namespace TimedShutdown proc.Start(); } - public void AbortOperation() + public void AbortOperation(string remoteShutdown) { ProcessStartInfo info = new ProcessStartInfo(); Process proc = new Process(); info.FileName = "cmd.exe"; - info.Arguments = $"/c shutdown -a"; + info.Arguments = $"/c shutdown -a {_funcRemoteShutdown(remoteShutdown)}"; info.CreateNoWindow = true; info.WindowStyle = ProcessWindowStyle.Hidden; + proc.StartInfo = info; proc.Start(); } #region Functions - private string ShutdownOperation(Operation arg) + private static string ShutdownOperation(Operation arg) { switch (arg) { @@ -64,11 +68,21 @@ namespace TimedShutdown } } - private string ForceShutdown(bool arg) + private static string ForceShutdown(bool arg) { return "-f"; } + private static string RemoteShutdown(string arg) + { + if (string.IsNullOrEmpty(arg)) return string.Empty; + if (arg.StartsWith(@"\\")) + { + return $"-m {arg}"; + } + return $@"-m \\{arg}"; + } + #endregion } diff --git a/TimedShutdown/TimedShutdown.csproj b/TimedShutdown/TimedShutdown.csproj index cf4470d..51bf3d1 100644 --- a/TimedShutdown/TimedShutdown.csproj +++ b/TimedShutdown/TimedShutdown.csproj @@ -70,6 +70,8 @@ MSBuild:Compile Designer + + diff --git a/TimedShutdown/ViewModels/ShellRootViewModel.cs b/TimedShutdown/ViewModels/ShellRootViewModel.cs index 4f52710..1d5a775 100644 --- a/TimedShutdown/ViewModels/ShellRootViewModel.cs +++ b/TimedShutdown/ViewModels/ShellRootViewModel.cs @@ -1,4 +1,6 @@ using System; +using System.Diagnostics; +using System.Net; using System.Windows.Media.Imaging; using Caliburn.Micro; @@ -6,29 +8,8 @@ namespace TimedShutdown.ViewModels { public class ShellRootViewModel : Screen { - readonly ShutdownManager shutdownManager = new ShutdownManager(); - - #region Labels - - public string LabelWindowTitle { get; } = "Timed Shutdown"; - - public string LabelHoursLabel { get; } = "Hours:"; - - public string LabelMinutesLabel { get; } = "Minutes:"; - - public string LabelShutdownOptions { get; } = "Options:"; - - public string LabelShutdownOptionsForce { get; } = "Force Operation"; - - public string LabelShutdownTime { get; set; } = "Shutdown Time:"; - - public string LabelShutdown { get; } = "Shutdown"; - - public string LabelReboot { get; } = "Reboot"; - - public string LabelAbortShutdown { get; } = "Abort Shutdown"; - - #endregion + private readonly ShutdownManager _shutdownManager = new ShutdownManager(); + private readonly PingWidget pingWidget = new PingWidget(); #region Values @@ -82,6 +63,66 @@ namespace TimedShutdown.ViewModels public bool ShutdownOptionsForce { get; set; } + private string _remoteShutdown; + public string RemoteShutdown + { + get { return _remoteShutdown; } + set + { + // Show remote shutdown alert upon checking for a non-loopback + // address. + if (!string.IsNullOrEmpty(value) + && value != "localhost" + && value != "127.0.0.1") + { + Messaging alert = new Messaging(); + alert.Show(Messaging.Message.RemoteShutdown, value); + } + _remoteShutdown = value; + } + } + + private bool _pingRemoteHost; + public bool PingRemoteHost + { + get { return _pingRemoteHost; } + set + { + _pingRemoteHost = value; + + if (value == true) + { + pingWidget.IsCancellationRequested = false; + pingWidget.InitatePingRequest(IPAddress.Parse(RemoteShutdown)); + } + else + { + pingWidget.IsCancellationRequested = true; + } + } + } + + public string PingRemoteHostStatus { get; set; } + + #region Remote Expander + + public int WindowHeight { get; set; } = 335; // Default 335 + + private bool _remoteExpander; + public bool RemoteExpander + { + get { return _remoteExpander; } + set + { + WindowHeight = value ? 460 : 335; + NotifyOfPropertyChange(() => WindowHeight); + + _remoteExpander = value; + } + } + + #endregion + #endregion #region Buttons @@ -89,44 +130,48 @@ namespace TimedShutdown.ViewModels public bool CanShutdown { get; set; } = true; public void Shutdown() { - shutdownManager.ExecuteOperation(ShutdownManager.Operation.Shutdown, ShutdownTime, false); - CanAbortShutdown = true; - CanReboot = false; - CanShutdown = false; + _shutdownManager.ExecuteOperation( + ShutdownManager.Operation.Shutdown, + ShutdownTime, + ShutdownOptionsForce, + RemoteShutdown); - NotifyOfPropertyChange(() => CanAbortShutdown); - NotifyOfPropertyChange(() => CanReboot); - NotifyOfPropertyChange(() => CanShutdown); + CanReboot = false; + CanShutdown = false; + + NotifyOfPropertyChange(() => CanReboot); + NotifyOfPropertyChange(() => CanShutdown); } public bool CanReboot { get; set; } = true; public void Reboot() { - shutdownManager.ExecuteOperation(ShutdownManager.Operation.Reboot, ShutdownTime, false); - CanAbortShutdown = true; - CanReboot = false; - CanShutdown = false; + _shutdownManager.ExecuteOperation( + ShutdownManager.Operation.Reboot, + ShutdownTime, + ShutdownOptionsForce, + RemoteShutdown); - NotifyOfPropertyChange(() => CanAbortShutdown); - NotifyOfPropertyChange(() => CanReboot); - NotifyOfPropertyChange(() => CanShutdown); + CanReboot = false; + CanShutdown = false; + + NotifyOfPropertyChange(() => CanReboot); + NotifyOfPropertyChange(() => CanShutdown); } - public bool CanAbortShutdown { get; set; } = true; public void AbortShutdown() { // Reset values to defaults. Minutes = 0; Hours = 0; - shutdownManager.AbortOperation(); - CanAbortShutdown = false; + _shutdownManager.AbortOperation(RemoteShutdown); CanReboot = true; CanShutdown = true; - NotifyOfPropertyChange(() => CanAbortShutdown); NotifyOfPropertyChange(() => CanReboot); NotifyOfPropertyChange(() => CanShutdown); + NotifyOfPropertyChange(() => RemoteShutdown); } #endregion diff --git a/TimedShutdown/Views/ShellRootView.xaml b/TimedShutdown/Views/ShellRootView.xaml index 99a0d5c..8dad97e 100644 --- a/TimedShutdown/Views/ShellRootView.xaml +++ b/TimedShutdown/Views/ShellRootView.xaml @@ -4,7 +4,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" - Title="{Binding LabelWindowTitle}" Height="300" Width="400" WindowStartupLocation="CenterScreen" + Title="Timed Shutdown" Height="{Binding WindowHeight, Mode=TwoWay}" Width="400" WindowStartupLocation="CenterScreen" ResizeMode="NoResize"> @@ -21,36 +21,37 @@ + + Margin="0,0,5,0" Grid.RowSpan="5" RenderOptions.BitmapScalingMode="Fant"/> - @@ -64,15 +65,50 @@ + -