You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

778 lines
27 KiB

#if NETFX
using System.Management;
#endif
#if NETFX || NETCORE
using System.Windows.Forms;
#endif
using Apewer.Internals.Interop;
using Apewer.Models;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using static Apewer.Internals.Interop.Constant;
using static Apewer.Internals.Interop.AdvApi32;
using static Apewer.Internals.Interop.Kernel32;
using static Apewer.Internals.Interop.User32;
namespace Apewer
{
/// <summary>Windows 实用工具。</summary>
public class SystemUtility
{
#region 系统信息。
private static int CheckOsType()
{
#if NETFX
return 1;
#else
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return 1;
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return 2;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return 3;
return 0;
#endif
}
/// <summary>当前操作系统是 Windows。</summary>
public static bool IsWindows { get => CheckOsType() == 1; }
/// <summary>当前操作系统是 OS X 或 macOS。</summary>
public static bool IsOSX { get => CheckOsType() == 2; }
/// <summary>当前操作系统是 Linux。</summary>
public static bool IsLinux { get => CheckOsType() == 3; }
#if NETFX
/// <summary>获取内存容量。</summary>
public static long RamTotal
{
get
{
try
{
var mos = new ManagementObjectSearcher();
mos.Query = new SelectQuery("win32_physicalmemory", "", new string[] { "capacity" });
var moc = mos.Get();
var total = 0L;
foreach (var mbo in moc)
{
var value = mbo.Properties["capacity"].Value;
if (value != null)
{
total += long.Parse(value.ToString());
}
}
return total;
}
catch { }
return 0;
}
}
#endif
#endregion
#region 进程。
#if NETFX
/// <summary>操作系统是否基于 64 位架构。</summary>
public static bool WindowsIsX64
{
get
{
try
{
string vbit = String.Empty;
var options = new ConnectionOptions();
var scope = new ManagementScope("\\\\localhost", options);
var query = new ObjectQuery("select addresswidth from win32_processor");
var searcher = new ManagementObjectSearcher(scope, query);
var collection = searcher.Get();
foreach (var i in collection)
{
if (i["addresswidth"].ToString() == "64") return true;
}
}
catch { }
return false;
}
}
#endif
/// <summary>当前进程是否基于 64 位架构。</summary>
/// <remarks>此属性读取 System.Environment.Is64BitProcess,由 mscorlib.dll 定义。</remarks>
public static bool ProcessIsX64
{
#if NET20
get { return IntPtr.Size == 8; }
#else
get { return Environment.Is64BitProcess && IntPtr.Size == 8; }
#endif
}
/// <summary>调用 System.Diagnostics.Process.Start 启动进程。</summary>
/// <param name="path">程序路径。</param>
/// <param name="args">参数。</param>
/// <param name="uac">以管理员身份启动。</param>
public static Process StartProcess(string path, string[] args, bool uac = false)
{
var merged = (args == null || args.Length < 1) ? "" : TextUtility.MergeProcessArgument(args);
return StartProcess(path, merged, uac);
}
/// <summary>调用 System.Diagnostics.Process.Start 启动进程。</summary>
/// <param name="path">程序路径。</param>
/// <param name="args">参数。</param>
/// <param name="uac">以管理员身份启动。</param>
public static Process StartProcess(string path, string args = null, bool uac = false)
{
var psi = new ProcessStartInfo();
psi.FileName = path ?? "";
psi.Arguments = args ?? "";
if (uac) psi.Verb = "runas";
try
{
var process = Process.Start(psi);
return process;
}
catch
{
return null;
}
}
/// <summary>从 Win32 程序启动进程。</summary>
/// <param name="path">程序路径。</param>
/// <param name="args">参数。</param>
public static bool StartNativeProcess(string path, string args = null)
{
if (string.IsNullOrEmpty(path)) return false;
if (!File.Exists(path)) return false;
try
{
var si = new StartupInfo();
var pi = new ProcessInformation();
var created = Kernel32.CreateProcess(path, args ?? "", IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, null, ref si, ref pi);
return created;
}
catch
{
return false;
}
}
/// <summary>结束当前进程。</summary>
public static bool KillCurrentProcess()
{
#if NETFX || NETCORE
Application.Exit();
#endif
return KillProcess(Process.GetCurrentProcess());
}
/// <summary>结束所有具有指定名称的进程。</summary>
public static void KillProcesses(string name)
{
try
{
var processes = Process.GetProcessesByName(name);
foreach (var process in processes) KillProcess(process);
}
catch { }
}
/// <summary>结束具有指定 PID 的进程。</summary>
/// <param name="pid">PID。</param>
public static bool KillProcess(int pid)
{
try { return KillProcess(Process.GetProcessById(pid)); }
catch { return false; }
}
/// <summary>结束进程。</summary>
public static bool KillProcess(Process process)
{
try { process.Kill(); return true; }
catch { return false; }
}
/// <summary>查询指定的进程 ID 是否存在。</summary>
/// <param name="pid">进程 ID。</param>
public static bool ProcessIsAlive(int pid)
{
if (pid > 0)
{
int vhp = 0, vec = 0;
vhp = Kernel32.OpenProcess(Constant.PROCESS_QUERY_INFORMATION, 0, pid);
Kernel32.GetExitCodeProcess(vhp, out vec);
Kernel32.CloseHandle(vhp);
if (vec == Constant.STILL_ALIVE) return true;
else return false;
}
return false;
}
#if NETFX || NETCORE
/// <summary>当前程序名是否已经运行。</summary>
public static bool ProcessPreviousis
{
get
{
var path = Application.ExecutablePath;
var filename = Path.GetFileName(path);
return !FirstProcess(filename);
}
}
/// <summary>指定的进程名称是否为首次运行。</summary>
/// <param name="name">进程名。</param>
public static bool FirstProcess(string name)
{
bool ret = false;
if (Kernel32.OpenMutex(0x1F0001, 0, name) == IntPtr.Zero)
{
Kernel32.CreateMutex(IntPtr.Zero, 0, name);
ret = true;
}
return ret;
}
/// <summary>获取启动了应用程序的可执行文件的路径,不包括可执行文件的名称。</summary>
public static string StartupPath
{
get { return Application.StartupPath; }
}
/// <summary>获取启动了应用程序的可执行文件的路径,包括可执行文件的名称。</summary>
public static string ExecutablePath
{
get { return Application.ExecutablePath; }
}
#endif
#endregion
#region 控制台。
/// <summary>启动控制台进程,获取输出。</summary>
public static string RunConsole(string cmd, string arg = null)
{
// var list = new List<string>();
var output = null as string;
try
{
var startInfo = new ProcessStartInfo();
startInfo.FileName = cmd ?? "";
startInfo.Arguments = arg ?? "";
startInfo.UseShellExecute = false; // 必须禁用操作系统外壳程序。
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
// startInfo.RedirectStandardInput = true;
// startInfo.RedirectStandardError = true;
using (var process = Process.Start(startInfo))
{
output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
process.Close();
}
}
catch { }
return output;
}
/// <summary>启动控制台进程,获取输出。</summary>
public static Exception RunConsole(string cmd, string arg, Func<string, string> output, Func<string, string> error, Action exited = null)
{
var exception = null as Exception;
// var list = new List<string>();
var process = new Process();
try
{
process.EnableRaisingEvents = true;
process.StartInfo = new ProcessStartInfo()
{
FileName = cmd ?? "",
Arguments = arg ?? "",
CreateNoWindow = true,
UseShellExecute = false, // 必须禁用操作系统外壳程序。
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardOutput = true,
RedirectStandardInput = true,
RedirectStandardError = true,
};
process.OutputDataReceived += (s, e) =>
{
var input = output?.Invoke(e.Data);
if (input != null) process.StandardInput.Write(input);
};
process.ErrorDataReceived += (s, e) =>
{
var input = error?.Invoke(e.Data);
if (input != null) process.StandardInput.Write(input);
};
process.Exited += (s, e) =>
{
exited?.Invoke();
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
process.Close();
}
catch (Exception ex)
{
exception = ex;
}
RuntimeUtility.Dispose(process);
return exception;
}
/// <summary>启动控制台进程,获取输出。</summary>
public static Exception RunConsole(string cmd, string arg, Action<string> received, Action exited = null)
{
return RunConsole(cmd, arg, (s) => { received?.Invoke(s); return null; }, (s) => { received?.Invoke(s); return null; }, exited);
}
#endregion
#region 硬件 & 电源。
private static void ExitWindows(int flag)
{
TokenPrivilege tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);
AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
ExitWindowsEx(flag, 0);
}
/// <summary>关机。</summary>
public static void Shutdown() => ExitWindows(EWX_FORCE | EWX_POWEROFF);
/// <summary>重启。</summary>
public static void Reboot() => ExitWindows(EWX_FORCE | EWX_REBOOT);
/// <summary>注销。</summary>
public static void LogOff() => ExitWindows(EWX_FORCE | EWX_LOGOFF);
#if NETFX
private static string GetHardwareInfomation(string device, string property)
{
var vmc = new ManagementClass();
var vmoc = vmc.GetInstances();
var vinfo = "";
foreach (var vmbo in vmoc)
{
if (!string.IsNullOrEmpty(property))
{
var vvalue = "";
try { vvalue = vmbo.Properties[property].Value.ToString(); } catch { }
vinfo += vvalue + ";";
}
else
{
foreach (var vpd in vmbo.Properties)
{
var vvalue = "";
try { return vpd.Value.ToString(); } catch { }
vinfo += vpd.Name + "=" + vvalue + ";";
}
}
}
return vinfo;
}
/// <summary>获取处理器的信息。</summary>
public static string GetProcessorInfomation()
{
return GetHardwareInfomation("win32_processor", "processorid");
}
/// <summary>获取媒体介质的信息。</summary>
public static string GetMediaDiskInfomation()
{
var vpm = GetHardwareInfomation("win32_physicalmedia", "serialnumber");
var vdd = GetHardwareInfomation("win32_diskdrive", "serialnumber");
return vpm + vdd;
}
/// <summary>获取主板的信息。</summary>
public static string GetBaseBoardInfomation()
{
var vbb = GetHardwareInfomation("win32_baseboard", "serialnumber");
var vb = GetHardwareInfomation("win32_bios", "serialnumber");
return vbb + vb;
}
#endif
#endregion
#region 屏幕/桌面。
/// <summary>关闭屏幕。</summary>
public static void CloseScreen()
{
User32.SendMessage(IntPtr.Zero, 274, 61808, 2);
}
/// <summary>获取系统支持的屏幕分辨率。</summary>
public static List<System.Drawing.Size> GetAvailableScreenResolution()
{
var list = new List<System.Drawing.Size>();
int rc = -1;
int mn = 0;
while (rc != 0)
{
var dm = new DevMode();
rc = User32.EnumDisplaySettings(null, mn, ref dm);
if (rc != 0)
{
var size = new System.Drawing.Size(dm.dmPelsHeight, dm.dmPelsWidth);
var exist = false;
foreach (var cell in list)
{
if ((size.Width == cell.Width) && (size.Height == cell.Height))
{
exist = true;
break;
}
}
if (!exist) list.Add(size);
mn += 1;
}
}
return list;
}
/// <summary>设置屏幕分辨率。</summary>
public static bool SetScreenResolution(System.Drawing.Size resolution)
{
if (resolution == null) return false;
return SetScreenResolution(resolution.Width, resolution.Height, 0);
}
/// <summary>设置屏幕分辨率。</summary>
public static bool SetScreenResolution(System.Drawing.Size resolution, short depth)
{
if (resolution == null) return false;
return SetScreenResolution(resolution.Width, resolution.Height, depth);
}
/// <summary>设置屏幕分辨率。</summary>
public static bool SetScreenResolution(int width, int height)
{
return SetScreenResolution(width, height, 0);
}
/// <summary>设置屏幕分辨率。</summary>
public static bool SetScreenResolution(int width, int height, short depth)
{
if (width < 0) return false;
if (height < 0) return false;
if (depth < 0) return false;
// 初始化 DEVMODE 结构。
var dm = new DevMode();
dm.dmDeviceName = new String(new char[32]);
dm.dmFormName = new String(new char[32]);
dm.dmSize = (short)Marshal.SizeOf(dm);
var verify = User32.EnumDisplaySettings(null, Constant.ENUM_CURRENT_SETTINGS, ref dm);
if (verify != 0)
{
dm.dmPelsWidth = width;
dm.dmPelsHeight = height;
//if (argDepth > 0) dm.dmBitsPerPel = depth;
// 改变分辨率。
int cds = User32.ChangeDisplaySettings(ref dm, Constant.CDS_TEST);
if (cds == Constant.DISP_CHANGE_FAILED) return false;
cds = User32.ChangeDisplaySettings(ref dm, Constant.CDS_UPDATEREGISTRY);
switch (cds)
{
case Constant.DISP_CHANGE_SUCCESSFUL: return true;
case Constant.DISP_CHANGE_RESTART: return true;
default: return false;
}
}
// 指定的分辨率不受支持。
return false;
}
private static void UnitiGoFullScreen()
{
const int GWL_STYLE = -16;
const int WS_BORDER = 1;
IntPtr i = User32.FindWindow("UnityWndClass", null);
User32.SetWindowLong(i, GWL_STYLE, WS_BORDER);
User32.ShowWindow(i, 1);
}
#endregion
#region 鼠标。
/// <summary>移动鼠标指针。</summary>
public static void MousePointerMove(int x, int y)
{
User32.mouse_Callback(MouseCallbackFlag.LeftDown, x, y, 0, UIntPtr.Zero);
}
/// <summary>按下鼠标左键。</summary>
public static void MouseLeftDown(int x, int y)
{
User32.mouse_Callback(MouseCallbackFlag.LeftDown, x, y, 0, UIntPtr.Zero);
}
/// <summary>释放鼠标左键。</summary>
public static void MouseLeftUp(int x, int y)
{
User32.mouse_Callback(MouseCallbackFlag.LeftUp, x, y, 0, UIntPtr.Zero);
}
/// <summary>按下鼠标中键。</summary>
public static void MouseMiddleDown(int x, int y)
{
User32.mouse_Callback(MouseCallbackFlag.MiddleDown, x, y, 0, UIntPtr.Zero);
}
/// <summary>释放鼠标中键。</summary>
public static void MouseMiddleUp(int x, int y)
{
User32.mouse_Callback(MouseCallbackFlag.MiddleUp, x, y, 0, UIntPtr.Zero);
}
/// <summary>按下鼠标右键。</summary>
public static void MouseRightDown(int x, int y)
{
User32.mouse_Callback(MouseCallbackFlag.RightDown, x, y, 0, UIntPtr.Zero);
}
/// <summary>释放鼠标右键。</summary>
public static void MouseRightUp(int x, int y)
{
User32.mouse_Callback(MouseCallbackFlag.RightUp, x, y, 0, UIntPtr.Zero);
}
private static IntPtr GetHINSTANCE(Module m)
{
if ((object)m == null)
{
throw new ArgumentNullException("m");
}
return (IntPtr)(-1);
}
/// <summary>钩住鼠标。当前线程必须具有消息循环。</summary>
private static int HookMouse(Func<MouseEvent, bool> func)
{
if (func == null) return 0;
var proc = new HookProc(LowLevelMouseProc);
// var hInstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);
var hInstance = GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);
var hook = 0;
hook = User32.SetWindowsHookEx(Constant.WH_MOUSE_LL, (int nCode, IntPtr wParam, IntPtr lParam) =>
{
if (func == null || nCode < 0)
{
return User32.CallNextHookEx(hook, nCode, wParam, lParam);
}
else
{
var info = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
var data = new MouseEvent()
{
Hook = hook,
X = info.pt.x,
Y = info.pt.y,
Button = wParam.ToInt64()
};
var @continue = func.Invoke(data);
return @continue ? User32.CallNextHookEx(hook, nCode, wParam, lParam) : 0;
}
}, hInstance, 0);
return hook;
}
/// <summary>An application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function every time a new mouse input event is about to be posted into a thread input queue.</summary>
/// <param name="nCode">A code the hook procedure uses to determine how to process the message. If nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx. This parameter can be one of the following values.</param>
/// <param name="wParam">The identifier of the mouse message. This parameter can be one of the following messages: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_RBUTTONDOWN, or WM_RBUTTONUP.</param>
/// <param name="lParam">A pointer to an MSLLHOOKSTRUCT structure.</param>
/// <returns></returns>
private static int LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
{
return 0;
}
/// <summary>释放钩子。</summary>
private static bool Unhook(int hook) => User32.UnhookWindowsHookEx(hook);
#endregion
#region 窗体控制。
/// <summary>获取指定窗体的句柄。</summary>
/// <param name="title">窗体标题。</param>
public static IntPtr GetWindowHandle(string title)
{
var handle = User32.FindWindow(null, title ?? "");
return handle;
}
private static List<IntPtr> WindowHandleList = null;
private static bool EnumWindowsCallBack(int hwnd, int lparam)
{
WindowHandleList.Add(new IntPtr(hwnd));
return true;
}
/// <summary>获取所有窗体的句柄。</summary>
/// <returns></returns>
public static List<IntPtr> GetWindowHandle()
{
if (WindowHandleList != null)
{
WindowHandleList.Clear();
WindowHandleList = null;
}
WindowHandleList = new List<IntPtr>();
var callback = new EnumWindowsCallBack(EnumWindowsCallBack);
var enumResult = User32.EnumWindows(callback, 0);
return WindowHandleList;
}
/// <summary>获取指定窗体的标题。</summary>
/// <param name="handle">窗体句柄。</param>
public static string GetWindowTitle(IntPtr handle)
{
var sb = new StringBuilder(1024);
var rc = User32.GetWindowTextW(handle, sb, sb.Capacity);
var title = sb.ToString();
return title;
}
/// <summary>向指定窗体发送消息。</summary>
public static void PostMessage(IntPtr handle, int message)
{
if (handle != IntPtr.Zero)
{
User32.PostMessage(handle, message, IntPtr.Zero, IntPtr.Zero);
}
}
/// <summary>还原显示指定窗体,并设置焦点至该窗体。</summary>
/// <param name="handle"></param>
public static void RestoreWindow(IntPtr handle)
{
if (handle != IntPtr.Zero)
{
User32.ShowWindow(handle, Constant.SW_RESTORE);
User32.SetForegroundWindow(handle);
}
}
#endregion
#region 注册表。
#if NETFX
/// <summary>获取用于记录卸载信息的注册表路径。</summary>
public static string[] GetUnInstallPath()
{
const string win32uninstall = "software\\microsoft\\windows\\currentversion\\uninstall";
const string wow64uninstall = "software\\wow6432node\\microsoft\\windows\\currentversion\\uninstall";
var vuninstallpath = new List<string>();
var vwin32rk = Registry.LocalMachine.OpenSubKey(win32uninstall);
var vwin32skns = vwin32rk.GetSubKeyNames();
foreach (var i in vwin32skns) vuninstallpath.Add(win32uninstall + "\\" + i);
vwin32rk.Close();
if (WindowsIsX64)
{
var vwow64rk = Registry.LocalMachine.OpenSubKey(wow64uninstall);
var vwow64skns = vwow64rk.GetSubKeyNames();
foreach (var i in vwow64skns) vuninstallpath.Add(wow64uninstall + "\\" + i);
vwow64rk.Close();
}
return vuninstallpath.ToArray();
}
#endif
#endregion
#region Windows COM
#if NETFX
/// <summary>创建快捷方式。</summary>
/// <param name="linkPath">快捷方式路径。</param>
/// <param name="linkIcon">快捷方式图标。可使用 c:\source.exe,0 格式。</param>
/// <param name="linkDescription">快捷方式说明。</param>
/// <param name="sourcePath">源路径。</param>
/// <param name="sourceArgs">源参数。</param>
/// <param name="directory">工作目录。</param>
public static void CreateShortcut(string linkPath, string sourcePath, string sourceArgs = null, string linkIcon = null, string linkDescription = null, string directory = null)
{
// var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
// var shortcut = (IWshShortcut)new WshShellClass().CreateShortcut(linkPath);
var wshShellClass = new IWshRuntimeLibrary.WshShellClass();
var wshObject = wshShellClass.CreateShortcut(linkPath);
var wshShortcut = (IWshRuntimeLibrary.IWshShortcut)wshObject;
var shortcut = wshShortcut;
shortcut.TargetPath = sourcePath ?? "";
shortcut.Arguments = sourceArgs ?? "arg1";
shortcut.Description = linkDescription ?? "Invalid Description";
shortcut.WorkingDirectory = directory ?? "";
shortcut.IconLocation = linkIcon;
shortcut.WindowStyle = 1;
// shortcut.WorkingDirectory = "";
// shortcut.RelativePath = "";
shortcut.Save();
}
#endif
#endregion
}
}