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.
1002 lines
38 KiB
1002 lines
38 KiB
#if NETFX
|
|
using System.Management;
|
|
#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 System.Windows.Forms;
|
|
|
|
using static Apewer.Internals.Interop.Constant;
|
|
using static Apewer.Internals.Interop.AdvApi32;
|
|
using static Apewer.Internals.Interop.Kernel32;
|
|
using static Apewer.Internals.Interop.User32;
|
|
using System.Net;
|
|
|
|
namespace Apewer
|
|
{
|
|
|
|
/// <summary>Windows 实用工具。</summary>
|
|
public static class WindowsUtility
|
|
{
|
|
|
|
#region 句柄
|
|
|
|
/// <summary>关闭句柄。</summary>
|
|
public static bool CloseHandle(IntPtr handle) => Kernel32.CloseHandle(handle);
|
|
|
|
#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
|
|
|
|
/// <summary>根据窗口标题获取进程 ID。</summary>
|
|
public static int GetPidByWindowTitle(string windowTitle, bool partial = false)
|
|
{
|
|
if (windowTitle == null) windowTitle = "";
|
|
var processes = Process.GetProcesses();
|
|
if (partial)
|
|
{
|
|
foreach (var p in processes)
|
|
{
|
|
try
|
|
{
|
|
var title = p.MainWindowTitle ?? "";
|
|
if (title == windowTitle) return p.Id;
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (var p in processes)
|
|
{
|
|
try
|
|
{
|
|
var title = p.MainWindowTitle ?? "";
|
|
if (title.Contains(windowTitle)) return p.Id;
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>打开现有的本地进程对象。</summary>
|
|
/// <param name="processId">要打开的本地进程的标识符。</param>
|
|
/// <returns>指定进程的打开句柄。</returns>
|
|
/// <exception cref="ArgumentNullException" />
|
|
/// <exception cref="SystemException" />
|
|
public static IntPtr OpenProcess(int processId)
|
|
{
|
|
if (processId == 0) throw new ArgumentNullException(nameof(processId));
|
|
var handle = Kernel32.OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE, false, processId);
|
|
if (handle == IntPtr.Zero) throw new SystemException($"打开进程 {processId} 失败。");
|
|
return handle;
|
|
}
|
|
|
|
/// <summary>打开现有的本地进程对象。</summary>
|
|
/// <param name="processId">要打开的本地进程的标识符。</param>
|
|
/// <param name="callback">使用句柄。</param>
|
|
/// <returns>指定进程的打开句柄。</returns>
|
|
/// <exception cref="ArgumentNullException" />
|
|
/// <exception cref="SystemException" />
|
|
public static void OpenProcess(int processId, Action<IntPtr> callback)
|
|
{
|
|
if (processId == 0) throw new ArgumentNullException(nameof(processId));
|
|
if (callback == null) throw new ArgumentNullException(nameof(callback));
|
|
|
|
var handle = IntPtr.Zero;
|
|
try
|
|
{
|
|
handle = OpenProcess(processId);
|
|
callback.Invoke(handle);
|
|
}
|
|
finally
|
|
{
|
|
if (handle != IntPtr.Zero) CloseHandle(handle);
|
|
}
|
|
}
|
|
|
|
/// <summary>打开现有的本地进程对象。</summary>
|
|
/// <param name="processId">要打开的本地进程的标识符。</param>
|
|
/// <param name="callback">使用句柄。</param>
|
|
/// <returns>指定进程的打开句柄。</returns>
|
|
/// <exception cref="ArgumentNullException" />
|
|
/// <exception cref="SystemException" />
|
|
public static T OpenProcess<T>(int processId, Func<IntPtr, T> callback)
|
|
{
|
|
if (processId == 0) throw new ArgumentNullException(nameof(processId));
|
|
if (callback == null) throw new ArgumentNullException(nameof(callback));
|
|
|
|
var handle = IntPtr.Zero;
|
|
try
|
|
{
|
|
handle = OpenProcess(processId);
|
|
return callback.Invoke(handle);
|
|
}
|
|
finally
|
|
{
|
|
if (handle != IntPtr.Zero) CloseHandle(handle);
|
|
}
|
|
}
|
|
|
|
/// <summary>读取指定进程的内存。</summary>
|
|
/// <param name="process">进程。</param>
|
|
/// <param name="address">要读取的内存地址。</param>
|
|
/// <param name="length">要读取的字节数。</param>
|
|
/// <returns>读取到的数据。</returns>
|
|
/// <exception cref="ArgumentNullException" />
|
|
/// <exception cref="ArgumentOutOfRangeException" />
|
|
/// <exception cref="SystemException" />
|
|
public static byte[] ReadMemory(this Process process, IntPtr address, int length)
|
|
{
|
|
if (process == null) throw new ArgumentNullException(nameof(process));
|
|
if (address == IntPtr.Zero) throw new ArgumentNullException(nameof(address));
|
|
if (length < 1) throw new ArgumentNullException(nameof(length));
|
|
|
|
return OpenProcess(process.Id, (processHandle) => ReadMemory(processHandle, address, length));
|
|
}
|
|
|
|
/// <summary>读取指定进程的内存。</summary>
|
|
/// <param name="processHandle">进程句柄。</param>
|
|
/// <param name="address">要读取的内存地址。</param>
|
|
/// <param name="length">要读取的字节数。</param>
|
|
/// <returns>读取到的数据。</returns>
|
|
/// <exception cref="ArgumentNullException" />
|
|
/// <exception cref="ArgumentOutOfRangeException" />
|
|
/// <exception cref="SystemException" />
|
|
public static byte[] ReadMemory(IntPtr processHandle, IntPtr address, int length)
|
|
{
|
|
if (processHandle == IntPtr.Zero) throw new ArgumentNullException(nameof(processHandle));
|
|
if (address == IntPtr.Zero) throw new ArgumentNullException(nameof(address));
|
|
if (length < 1) throw new ArgumentOutOfRangeException(nameof(length)); ;
|
|
|
|
var buffer = new byte[length];
|
|
if (ReadProcessMemory(processHandle, address.ToInt32(), buffer, length, out var read))
|
|
{
|
|
if (read == length) return buffer;
|
|
|
|
// 收缩数组
|
|
var array = new byte[read];
|
|
if (read > 0) Buffer.BlockCopy(buffer, 0, array, 0, read);
|
|
return array;
|
|
}
|
|
|
|
throw new SystemException($"从内存地址读取数据失败。");
|
|
}
|
|
|
|
/// <summary>在进程的指定地址写入数据。</summary>
|
|
/// <param name="process">进程。</param>
|
|
/// <param name="address">要读取的内存地址。</param>
|
|
/// <param name="data">要写入的数据。</param>
|
|
/// <returns>写入的字节数。</returns>
|
|
/// <exception cref="ArgumentNullException" />
|
|
/// <exception cref="SystemException" />
|
|
public static int WriteMemory(this Process process, IntPtr address, byte[] data)
|
|
{
|
|
if (process == null) throw new ArgumentNullException(nameof(process));
|
|
if (address == IntPtr.Zero) throw new ArgumentNullException(nameof(address));
|
|
if (data == null) throw new ArgumentNullException(nameof(data));
|
|
if (data.Length < 1) return 0;
|
|
|
|
return OpenProcess(process.Id, processHandle => WriteMemory(processHandle, address, data));
|
|
}
|
|
|
|
/// <summary>在进程的指定地址写入数据。</summary>
|
|
/// <param name="processHandle">进程句柄。</param>
|
|
/// <param name="address">要读取的内存地址。</param>
|
|
/// <param name="data">要写入的数据。</param>
|
|
/// <returns>写入的字节数。</returns>
|
|
/// <exception cref="ArgumentNullException" />
|
|
/// <exception cref="SystemException" />
|
|
public static int WriteMemory(IntPtr processHandle, IntPtr address, byte[] data)
|
|
{
|
|
if (processHandle == IntPtr.Zero) throw new ArgumentNullException(nameof(processHandle));
|
|
if (address == IntPtr.Zero) throw new ArgumentNullException(nameof(address));
|
|
if (data == null) throw new ArgumentNullException(nameof(data));
|
|
if (data.Length < 1) return 0;
|
|
|
|
if (WriteProcessMemory(processHandle, address, data, data.Length, out var written)) return written;
|
|
throw new SystemException($"向内存地址写入数据失败。");
|
|
}
|
|
|
|
#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);
|
|
}
|
|
|
|
/// <summary>获取系统空闲的毫秒数。</summary>
|
|
public static uint GetIdleTime()
|
|
{
|
|
LASTINPUTINFO LastUserAction = new LASTINPUTINFO();
|
|
LastUserAction.cbSize = (uint)Marshal.SizeOf(LastUserAction);
|
|
User32.GetLastInputInfo(ref LastUserAction);
|
|
return ((uint)Environment.TickCount - LastUserAction.dwTime);
|
|
}
|
|
|
|
#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);
|
|
}
|
|
}
|
|
|
|
/// <summary>在所有进程中根据主窗口标题查找窗口句柄。</summary>
|
|
public static IntPtr FindWindow(string title, bool partial = false)
|
|
{
|
|
var ps = Process.GetProcesses();
|
|
try
|
|
{
|
|
foreach (Process p in ps)
|
|
{
|
|
if (p.MainWindowTitle == title) return p.MainWindowHandle;
|
|
}
|
|
}
|
|
catch { }
|
|
|
|
if (partial)
|
|
{
|
|
try
|
|
{
|
|
foreach (Process p in ps)
|
|
{
|
|
if (p.MainWindowTitle.Contains(title)) return p.MainWindowHandle;
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
/// <summary>运行指定窗体,启动消息循环。</summary>
|
|
[STAThread]
|
|
public static void Run<T>(bool dpiAware = true) where T : Form, new()
|
|
{
|
|
if (dpiAware)
|
|
{
|
|
var ntver = Environment.OSVersion.Version;
|
|
if (ntver.Major == 6)
|
|
{
|
|
switch (ntver.Minor)
|
|
{
|
|
case 1: // Win 7
|
|
case 2: // Win 8
|
|
SetProcessDPIAware();
|
|
break;
|
|
case 3: // Win 8.1
|
|
// SHCore.SetProcessDpiAwareness(SHCore.PROCESS_DPI_AWARENESS.Process_System_DPI_Aware);
|
|
SHCore.SetProcessDpiAwareness(SHCore.PROCESS_DPI_AWARENESS.Process_Per_Monitor_DPI_Aware);
|
|
break;
|
|
}
|
|
}
|
|
else if (ntver.Major >= 10)
|
|
{
|
|
// SHCore.SetProcessDpiAwareness(SHCore.PROCESS_DPI_AWARENESS.Process_System_DPI_Aware);
|
|
SHCore.SetProcessDpiAwareness(SHCore.PROCESS_DPI_AWARENESS.Process_Per_Monitor_DPI_Aware);
|
|
}
|
|
}
|
|
|
|
Control.CheckForIllegalCrossThreadCalls = false;
|
|
Application.EnableVisualStyles();
|
|
Application.SetCompatibleTextRenderingDefault(false);
|
|
#if NETCORE
|
|
if (dpiAware) Application.SetHighDpiMode(HighDpiMode.PerMonitor);
|
|
#endif
|
|
// Application.SetCompatibleTextRenderingDefault(true);
|
|
|
|
var form = new T();
|
|
// if (dpiAware) form.AutoScaleMode = AutoScaleMode.Dpi;
|
|
Application.Run(form);
|
|
}
|
|
|
|
/// <summary>移除窗体的关闭按钮。</summary>
|
|
public static void RemoveCloseMenu(IntPtr handle)
|
|
{
|
|
var menu = GetSystemMenu(handle, IntPtr.Zero);
|
|
RemoveMenu(menu, SC_CLOSE, 0x0);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 注册表。
|
|
|
|
/// <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();
|
|
|
|
try
|
|
{
|
|
var vwow64rk = Registry.LocalMachine.OpenSubKey(wow64uninstall);
|
|
var vwow64skns = vwow64rk.GetSubKeyNames();
|
|
foreach (var i in vwow64skns) vuninstallpath.Add(wow64uninstall + "\\" + i);
|
|
vwow64rk.Close();
|
|
}
|
|
catch { }
|
|
|
|
return vuninstallpath.ToArray();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ARP
|
|
|
|
/// <summary>发送 ARP 请求,获取目标 IP 地址对应设备的 MAC 地址,MAC 格式为 01-23-45-67-89-AB。</summary>
|
|
/// <param name="ip">目标 IP 地址。</param>
|
|
/// <remarks>注:<br />仅 Windows 可用。</remarks>
|
|
/// <returns>MAC 地址。</returns>
|
|
public static string SendARP(string ip)
|
|
{
|
|
if (!string.IsNullOrEmpty(ip))
|
|
{
|
|
try
|
|
{
|
|
var ipa = IPAddress.Parse(ip);
|
|
uint dip = BitConverter.ToUInt32(ipa.GetAddressBytes(), 0);
|
|
ulong mac = 0;
|
|
uint len = 6;
|
|
uint err = IpHlpApi.SendARP(dip, 0, ref mac, ref len);
|
|
byte[] bytes = BitConverter.GetBytes(mac);
|
|
return BitConverter.ToString(bytes, 0, 6);
|
|
}
|
|
catch { }
|
|
}
|
|
return "";
|
|
}
|
|
|
|
#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
|
|
|
|
}
|
|
|
|
}
|