Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PT Run] System plugin: Add IP and MAC #17023

Merged
merged 19 commits into from
Mar 21, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using System.Globalization;
using System.Net.NetworkInformation;
using System.Windows;
using System.Windows.Interop;
using Microsoft.PowerToys.Run.Plugin.System.Properties;
using Wox.Infrastructure;
using Wox.Plugin;
using Wox.Plugin.Common.Win32;
using Wox.Plugin.Logger;

namespace Microsoft.PowerToys.Run.Plugin.System.Components
{
internal static class Commands
{
internal const int EWXLOGOFF = 0x00000000;
internal const int EWXSHUTDOWN = 0x00000001;
internal const int EWXREBOOT = 0x00000002;
internal const int EWXFORCE = 0x00000004;
internal const int EWXPOWEROFF = 0x00000008;
internal const int EWXFORCEIFHUNG = 0x00000010;

internal static List<Result> GetSystemCommands(bool isUefi, string iconTheme, CultureInfo culture, bool confirmCommands)
{
var results = new List<Result>();
results.AddRange(new[]
{
new Result
{
Title = Resources.ResourceManager.GetString("Microsoft_plugin_sys_shutdown_computer", culture),
SubTitle = Resources.ResourceManager.GetString("Microsoft_plugin_sys_shutdown_computer_description", culture),
IcoPath = $"Images\\shutdown.{iconTheme}.png",
Action = c =>
{
return ResultHelper.ExecuteCommand(confirmCommands, Resources.Microsoft_plugin_sys_shutdown_computer_confirmation, () => Helper.OpenInShell("shutdown", "/s /hybrid /t 0"));
},
},
new Result
{
Title = Resources.ResourceManager.GetString("Microsoft_plugin_sys_restart_computer", culture),
SubTitle = Resources.ResourceManager.GetString("Microsoft_plugin_sys_restart_computer_description", culture),
IcoPath = $"Images\\restart.{iconTheme}.png",
Action = c =>
{
return ResultHelper.ExecuteCommand(confirmCommands, Resources.Microsoft_plugin_sys_restart_computer_confirmation, () => Helper.OpenInShell("shutdown", "/r /t 0"));
},
},
new Result
{
Title = Resources.ResourceManager.GetString("Microsoft_plugin_sys_sign_out", culture),
SubTitle = Resources.ResourceManager.GetString("Microsoft_plugin_sys_sign_out_description", culture),
IcoPath = $"Images\\logoff.{iconTheme}.png",
Action = c =>
{
return ResultHelper.ExecuteCommand(confirmCommands, Resources.Microsoft_plugin_sys_sign_out_confirmation, () => NativeMethods.ExitWindowsEx(EWXLOGOFF, 0));
},
},
new Result
{
Title = Resources.ResourceManager.GetString("Microsoft_plugin_sys_lock", culture),
SubTitle = Resources.ResourceManager.GetString("Microsoft_plugin_sys_lock_description", culture),
IcoPath = $"Images\\lock.{iconTheme}.png",
Action = c =>
{
return ResultHelper.ExecuteCommand(confirmCommands, Resources.Microsoft_plugin_sys_lock_confirmation, () => NativeMethods.LockWorkStation());
},
},
new Result
{
Title = Resources.ResourceManager.GetString("Microsoft_plugin_sys_sleep", culture),
SubTitle = Resources.ResourceManager.GetString("Microsoft_plugin_sys_sleep_description", culture),
IcoPath = $"Images\\sleep.{iconTheme}.png",
Action = c =>
{
return ResultHelper.ExecuteCommand(confirmCommands, Resources.Microsoft_plugin_sys_sleep_confirmation, () => NativeMethods.SetSuspendState(false, true, true));
},
},
new Result
{
Title = Resources.ResourceManager.GetString("Microsoft_plugin_sys_hibernate", culture),
SubTitle = Resources.ResourceManager.GetString("Microsoft_plugin_sys_hibernate_description", culture),
IcoPath = $"Images\\sleep.{iconTheme}.png", // Icon change needed
Action = c =>
{
return ResultHelper.ExecuteCommand(confirmCommands, Resources.Microsoft_plugin_sys_hibernate_confirmation, () => NativeMethods.SetSuspendState(true, true, true));
},
},
new Result
{
Title = Resources.ResourceManager.GetString("Microsoft_plugin_sys_emptyrecyclebin", culture),
SubTitle = Resources.ResourceManager.GetString("Microsoft_plugin_sys_emptyrecyclebin_description", culture),
IcoPath = $"Images\\recyclebin.{iconTheme}.png",
Action = c =>
{
// http://www.pinvoke.net/default.aspx/shell32/SHEmptyRecycleBin.html
// FYI, couldn't find documentation for this but if the recycle bin is already empty, it will return -2147418113 (0x8000FFFF (E_UNEXPECTED))
// 0 for nothing
var result = NativeMethods.SHEmptyRecycleBin(new WindowInteropHelper(Application.Current.MainWindow).Handle, 0);
if (result != (uint)HRESULT.S_OK && result != 0x8000FFFF)
{
var name = "Plugin: " + Resources.Microsoft_plugin_sys_plugin_name;
var message = $"Error emptying recycle bin, error code: {result}\n" +
"please refer to https://msdn.microsoft.com/en-us/library/windows/desktop/aa378137";
Log.Error(message, typeof(Commands));
_ = MessageBox.Show(message, name);
}

return true;
},
},
});

// UEFI command/result. It is only available on systems booted in UEFI mode.
if (isUefi)
{
results.Add(new Result
{
Title = Resources.ResourceManager.GetString("Microsoft_plugin_sys_uefi", culture),
SubTitle = Resources.ResourceManager.GetString("Microsoft_plugin_sys_uefi_description", culture),
IcoPath = $"Images\\firmwareSettings.{iconTheme}.png",
Action = c =>
{
return ResultHelper.ExecuteCommand(confirmCommands, Resources.Microsoft_plugin_sys_uefi_confirmation, () => Helper.OpenInShell("shutdown", "/r /fw /t 0", null, true));
},
});
}

return results;
}

internal static List<Result> GetNetworkConnectionResults(string iconTheme, CultureInfo culture)
{
var adapters = NetworkInterface.GetAllNetworkInterfaces();
var results = new List<Result>();

foreach (NetworkInterface a in adapters)
{
string mac = a.GetPhysicalAddress().ToString();
var ips = NetworkInfoHelper.GetMainIpsForConnection(a);
string connectionDetails = NetworkInfoHelper.GetConnectionDetails(a);
string adapterDetails = NetworkInfoHelper.GetAdapterDetails(a);

if (!string.IsNullOrEmpty(ips["IpV4"]))
{
results.Add(new Result()
{
Title = ips["IpV4"],
SubTitle = "IPv4 address of " + a.Name + " - Press enter to copy",
IcoPath = $"Images\\network.{iconTheme}.png",
ToolTipData = new ToolTipData("Connection details", string.Format(CultureInfo.InvariantCulture, connectionDetails, ips["IpV4"], ips["IpV6"]) + "\n\nFor detailed IP information please use the ipconfig command!"),
ContextData = new SystemCommandResultContext { Type = SystemCommandResultType.IpResult, Data = connectionDetails },
Action = _ => ResultHelper.CopyToClipBoard(ips["IpV4"]),
});
}

if (!string.IsNullOrEmpty(ips["IpV6"]))
{
results.Add(new Result()
{
Title = ips["IpV6"],
SubTitle = "IPv6 address of " + a.Name + " - Press enter to copy",
IcoPath = $"Images\\network.{iconTheme}.png",
ToolTipData = new ToolTipData("Connection details", string.Format(CultureInfo.InvariantCulture, connectionDetails, ips["IpV4"], ips["IpV6"]) + "\n\nFor detailed IP information please use the ipconfig command!"),
ContextData = new SystemCommandResultContext { Type = SystemCommandResultType.IpResult, Data = connectionDetails },
Action = _ => ResultHelper.CopyToClipBoard(ips["IpV6"]),
});
}

if (!string.IsNullOrEmpty(mac))
{
results.Add(new Result()
{
Title = mac,
SubTitle = "MAC address of " + a.Name + " - Press enter to copy",
IcoPath = $"Images\\networkCard.{iconTheme}.png",
ToolTipData = new ToolTipData("Adapter details", adapterDetails),
ContextData = new SystemCommandResultContext { Type = SystemCommandResultType.MacResult, Data = adapterDetails },
Action = _ => ResultHelper.CopyToClipBoard(mac),
});
}
}

return results;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;

namespace Microsoft.PowerToys.Run.Plugin.System.Components
{
internal static class NetworkInfoHelper
{
internal static Dictionary<string, string> GetMainIpsForConnection(NetworkInterface adapter)
{
UnicastIPAddressInformationCollection adresses = adapter.GetIPProperties().UnicastAddresses;
string ip4 = adresses.Where(addr => addr.Address.AddressFamily == AddressFamily.InterNetwork).FirstOrDefault().Address.ToString();
string ip6 = adresses.Where(addr => addr.Address.AddressFamily == AddressFamily.InterNetworkV6).FirstOrDefault().Address.ToString();

return new Dictionary<string, string>()
{
{ "IpV4", ip4 },
{ "IpV6", ip6 },
};
}

internal static string GetConnectionDetails(NetworkInterface adapter)
{
return $"Name: {adapter.Name}" +
$"\nState: " + (adapter.OperationalStatus == OperationalStatus.Up ? "Connected" : "Disconnected") +
$"\nType: {GetAdapterType(adapter.NetworkInterfaceType)}" +
$"\nSuffix: {adapter.GetIPProperties().DnsSuffix}" +
"\nIP v4: {0}" +
"\nIP v6: {1}" +
$"\nAdapter: {adapter.Description}" +
$"\nMAC: {adapter.GetPhysicalAddress()}" +
$"\nSpeed: {FormatSpeedValue(adapter.Speed)}";
}

internal static string GetAdapterDetails(NetworkInterface adapter)
{
return $"Name: {adapter.Description}" +
$"\nMAC: {adapter.GetPhysicalAddress()}" +
$"\nSpeed: {FormatSpeedValue(adapter.Speed)}" +
$"\nType: {GetAdapterType(adapter.NetworkInterfaceType)}" +
$"\nState: " + (adapter.OperationalStatus == OperationalStatus.Up ? "Connected" : "Disconnected") +
$"\nConnection: {adapter.Name}";
}

private static string GetAdapterType(NetworkInterfaceType type)
{
switch (type)
{
case NetworkInterfaceType.Wman:
case NetworkInterfaceType.Wwanpp:
case NetworkInterfaceType.Wwanpp2:
return "Mobile broadband";
case NetworkInterfaceType.Wireless80211:
return "Wireless";
case NetworkInterfaceType.Loopback:
return "Loopback";
case NetworkInterfaceType.Tunnel:
return "Tunnel connection";
case NetworkInterfaceType.Unknown:
return "Unknown";
default:
return "Cable";
}
}

private static string FormatSpeedValue(long speed)
{
return (speed >= 1000000000) ? (speed / 1000000000) + " Gb/s" : (speed / 1000000) + " Mb/s";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using Microsoft.PowerToys.Run.Plugin.System.Properties;
using Wox.Infrastructure;
using Wox.Plugin;
using Wox.Plugin.Logger;

namespace Microsoft.PowerToys.Run.Plugin.System.Components
{
internal static class ResultHelper
{
internal static bool ExecuteCommand(bool confirm, string confirmationMessage, Action command)
{
if (confirm)
{
MessageBoxResult messageBoxResult = MessageBox.Show(
confirmationMessage,
Resources.Microsoft_plugin_sys_confirmation,
MessageBoxButton.YesNo,
MessageBoxImage.Warning);

if (messageBoxResult == MessageBoxResult.No)
{
return false;
}
}

command();
return true;
}

internal static bool CopyToClipBoard(in string text)
{
try
{
Clipboard.Clear();
Clipboard.SetText(text);
return true;
}
catch (Exception exception)
{
Log.Exception("Can't copy to clipboard", exception, typeof(ResultHelper));
return false;
}
}

internal static List<ContextMenuResult> GetContextMenuForresult(Result result)
{
var contextMenu = new List<ContextMenuResult>();

if (!(result?.ContextData is SystemCommandResultContext contextData))
{
return contextMenu;
}

if (contextData.Type == SystemCommandResultType.IpResult || contextData.Type == SystemCommandResultType.MacResult)
{
contextMenu.Add(new ContextMenuResult()
{
AcceleratorKey = Key.C,
AcceleratorModifiers = ModifierKeys.Control,
FontFamily = "Segoe MDL2 Assets",
Glyph = "\xE8C8", // E8C8 => Symbol: Copy
Title = "Copy details",
Action = _ => ResultHelper.CopyToClipBoard(contextData.Data),
});
}

if (contextData.Type == SystemCommandResultType.IpResult)
{
contextMenu.Add(new ContextMenuResult()
htcfreek marked this conversation as resolved.
Show resolved Hide resolved
{
AcceleratorKey = Key.I,
AcceleratorModifiers = ModifierKeys.Control,
FontFamily = "Segoe MDL2 Assets",
Glyph = "\xE756", // E756 => Symbol: CommandPrompt
Title = "Execute 'ipconfig /all'",
Action = _ => Helper.OpenInShell("cmd.exe", "/k ipconfig /all"),
});
}

return contextMenu;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace Microsoft.PowerToys.Run.Plugin.System.Components
{
internal class SystemCommandResultContext
htcfreek marked this conversation as resolved.
Show resolved Hide resolved
{
/// <summary>
/// Gets or sets the type of the result
/// </summary>
public SystemCommandResultType Type { get; set; }

/// <summary>
/// Gets or sets the context data for the command/results
/// </summary>
public string Data { get; set; }
}

internal enum SystemCommandResultType
htcfreek marked this conversation as resolved.
Show resolved Hide resolved
{
Command,
IpResult,
MacResult,
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading