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.

619 lines
21 KiB

  1. using Apewer.Internals.Interop;
  2. using Microsoft.Win32;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Runtime.InteropServices;
  8. using System.Text;
  9. #if NETFX
  10. using System.Management;
  11. #endif
  12. #if NETFX || NETCORE
  13. using System.Windows.Forms;
  14. #endif
  15. namespace Apewer
  16. {
  17. /// <summary>Windows 实用工具。</summary>
  18. public class WindowsUtility
  19. {
  20. #region 进程。
  21. #if NETFX
  22. /// <summary>操作系统是否基于 64 位架构。</summary>
  23. public static bool WindowsIsX64
  24. {
  25. get
  26. {
  27. try
  28. {
  29. string vbit = String.Empty;
  30. var options = new ConnectionOptions();
  31. var scope = new ManagementScope("\\\\localhost", options);
  32. var query = new ObjectQuery("select addresswidth from win32_processor");
  33. var searcher = new ManagementObjectSearcher(scope, query);
  34. var collection = searcher.Get();
  35. foreach (var i in collection)
  36. {
  37. if (i["addresswidth"].ToString() == "64") return true;
  38. }
  39. }
  40. catch (Exception ex)
  41. {
  42. Console.WriteLine(ex.ToString());
  43. }
  44. return false;
  45. }
  46. }
  47. #endif
  48. /// <summary>当前进程是否基于 64 位架构。</summary>
  49. /// <remarks>此属性读取 System.Environment.Is64BitProcess,由 mscorlib.dll 定义。</remarks>
  50. public static bool ProcessIsX64
  51. {
  52. #if NET20
  53. get { return IntPtr.Size == 8; }
  54. #else
  55. get { return Environment.Is64BitProcess && IntPtr.Size == 8; }
  56. #endif
  57. }
  58. /// <summary>调用 System.Diagnostics.Process.Start 启动进程。</summary>
  59. /// <param name="path">程序路径。</param>
  60. /// <param name="args">参数。</param>
  61. /// <param name="uac">以管理员身份启动。</param>
  62. public static Process StartProcess(string path, string[] args, bool uac = false)
  63. {
  64. var merged = (args == null || args.Length < 1) ? "" : TextUtility.MergeProcessArgument(args);
  65. return StartProcess(path, merged, uac);
  66. }
  67. /// <summary>调用 System.Diagnostics.Process.Start 启动进程。</summary>
  68. /// <param name="path">程序路径。</param>
  69. /// <param name="args">参数。</param>
  70. /// <param name="uac">以管理员身份启动。</param>
  71. public static Process StartProcess(string path, string args = null, bool uac = false)
  72. {
  73. var psi = new ProcessStartInfo();
  74. psi.FileName = path ?? "";
  75. psi.Arguments = args ?? "";
  76. if (uac) psi.Verb = "runas";
  77. try
  78. {
  79. var process = Process.Start(psi);
  80. return process;
  81. }
  82. catch
  83. {
  84. return null;
  85. }
  86. }
  87. /// <summary>从 Win32 程序启动进程。</summary>
  88. /// <param name="path">程序路径。</param>
  89. /// <param name="args">参数。</param>
  90. public static bool StartNativeProcess(string path, string args = null)
  91. {
  92. if (string.IsNullOrEmpty(path)) return false;
  93. if (!File.Exists(path)) return false;
  94. try
  95. {
  96. var si = new StartupInfo();
  97. var pi = new ProcessInformation();
  98. var created = Kernel32.CreateProcess(path, args ?? "", IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, null, ref si, ref pi);
  99. return created;
  100. }
  101. catch
  102. {
  103. return false;
  104. }
  105. }
  106. /// <summary>结束当前进程。</summary>
  107. public static bool KillCurrentProcess()
  108. {
  109. #if NETFX || NETCORE
  110. Application.Exit();
  111. #endif
  112. return KillProcess(Process.GetCurrentProcess());
  113. }
  114. /// <summary>结束所有具有指定名称的进程。</summary>
  115. public static void KillProcesses(string name)
  116. {
  117. try
  118. {
  119. var processes = Process.GetProcessesByName(name);
  120. foreach (var process in processes) KillProcess(process);
  121. }
  122. catch { }
  123. }
  124. /// <summary>结束具有指定 PID 的进程。</summary>
  125. /// <param name="pid">PID。</param>
  126. public static bool KillProcess(int pid)
  127. {
  128. try { return KillProcess(Process.GetProcessById(pid)); }
  129. catch { return false; }
  130. }
  131. /// <summary>结束进程。</summary>
  132. public static bool KillProcess(Process process)
  133. {
  134. try { process.Kill(); return true; }
  135. catch { return false; }
  136. }
  137. /// <summary>查询指定的进程 ID 是否存在。</summary>
  138. /// <param name="pid">进程 ID。</param>
  139. public static bool ProcessIsAlive(int pid)
  140. {
  141. if (pid > 0)
  142. {
  143. int vhp = 0, vec = 0;
  144. vhp = Kernel32.OpenProcess(Constant.PROCESS_QUERY_INFORMATION, 0, pid);
  145. Kernel32.GetExitCodeProcess(vhp, out vec);
  146. Kernel32.CloseHandle(vhp);
  147. if (vec == Constant.STILL_ALIVE) return true;
  148. else return false;
  149. }
  150. return false;
  151. }
  152. #if NETFX || NETCORE
  153. /// <summary>当前程序名是否已经运行。</summary>
  154. public static bool ProcessPreviousis
  155. {
  156. get
  157. {
  158. var path = Application.ExecutablePath;
  159. var filename = Path.GetFileName(path);
  160. return !FirstProcess(filename);
  161. }
  162. }
  163. /// <summary>指定的进程名称是否为首次运行。</summary>
  164. /// <param name="name">进程名。</param>
  165. public static bool FirstProcess(string name)
  166. {
  167. bool ret = false;
  168. if (Kernel32.OpenMutex(0x1F0001, 0, name) == IntPtr.Zero)
  169. {
  170. Kernel32.CreateMutex(IntPtr.Zero, 0, name);
  171. ret = true;
  172. }
  173. return ret;
  174. }
  175. /// <summary>获取启动了应用程序的可执行文件的路径,不包括可执行文件的名称。</summary>
  176. public static string StartupPath
  177. {
  178. get { return Application.StartupPath; }
  179. }
  180. /// <summary>获取启动了应用程序的可执行文件的路径,包括可执行文件的名称。</summary>
  181. public static string ExecutablePath
  182. {
  183. get { return Application.ExecutablePath; }
  184. }
  185. #endif
  186. #endregion
  187. #region 控制台。
  188. /// <summary>启动控制台进程,获取输出。</summary>
  189. public static string RunConsole(string cmd, string arg = null)
  190. {
  191. // var list = new List<string>();
  192. var output = null as string;
  193. try
  194. {
  195. var startInfo = new ProcessStartInfo();
  196. startInfo.FileName = cmd ?? "";
  197. startInfo.Arguments = arg ?? "";
  198. startInfo.UseShellExecute = false; // 必须禁用操作系统外壳程序。
  199. startInfo.CreateNoWindow = true;
  200. startInfo.RedirectStandardOutput = true;
  201. // startInfo.RedirectStandardInput = true;
  202. // startInfo.RedirectStandardError = true;
  203. using (var process = Process.Start(startInfo))
  204. {
  205. output = process.StandardOutput.ReadToEnd();
  206. process.WaitForExit();
  207. process.Close();
  208. }
  209. }
  210. catch { }
  211. return output;
  212. }
  213. #endregion
  214. #region 硬件。
  215. private static void ExitWindows(int flag)
  216. {
  217. bool ok;
  218. TokenPrivilege tp;
  219. IntPtr hproc = Kernel32.GetCurrentProcess();
  220. IntPtr htok = IntPtr.Zero;
  221. ok = AdvApi32.OpenProcessToken(hproc, Constant.TOKEN_ADJUST_PRIVILEGES | Constant.TOKEN_QUERY, ref htok);
  222. tp.Count = 1;
  223. tp.Luid = 0;
  224. tp.Attr = Constant.SE_PRIVILEGE_ENABLED;
  225. ok = AdvApi32.LookupPrivilegeValueA(null, Constant.SE_SHUTDOWN_NAME, ref tp.Luid);
  226. ok = AdvApi32.AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
  227. ok = User32.ExitWindowsEx(flag, 0);
  228. }
  229. /// <summary>强制关机。</summary>
  230. public static void Shutdown()
  231. {
  232. ExitWindows(Constant.EWX_FORCE | Constant.EWX_POWEROFF);
  233. }
  234. /// <summary>强制重启。</summary>
  235. public static void Reboot()
  236. {
  237. ExitWindows(Constant.EWX_FORCE | Constant.EWX_REBOOT);
  238. }
  239. /// <summary>强制注销。</summary>
  240. public static void LogOff()
  241. {
  242. ExitWindows(Constant.EWX_FORCE | Constant.EWX_LOGOFF);
  243. }
  244. #if NETFX
  245. private static string GetHardwareInfomation(string device, string property)
  246. {
  247. var vmc = new ManagementClass();
  248. var vmoc = vmc.GetInstances();
  249. var vinfo = "";
  250. foreach (var vmbo in vmoc)
  251. {
  252. if (!string.IsNullOrEmpty(property))
  253. {
  254. var vvalue = "";
  255. try { vvalue = vmbo.Properties[property].Value.ToString(); } catch { }
  256. vinfo += vvalue + ";";
  257. }
  258. else
  259. {
  260. foreach (var vpd in vmbo.Properties)
  261. {
  262. var vvalue = "";
  263. try { return vpd.Value.ToString(); } catch { }
  264. vinfo += vpd.Name + "=" + vvalue + ";";
  265. }
  266. }
  267. }
  268. return vinfo;
  269. }
  270. /// <summary>获取处理器的信息。</summary>
  271. public static string GetProcessorInfomation()
  272. {
  273. return GetHardwareInfomation("win32_processor", "processorid");
  274. }
  275. /// <summary>获取媒体介质的信息。</summary>
  276. public static string GetMediaDiskInfomation()
  277. {
  278. var vpm = GetHardwareInfomation("win32_physicalmedia", "serialnumber");
  279. var vdd = GetHardwareInfomation("win32_diskdrive", "serialnumber");
  280. return vpm + vdd;
  281. }
  282. /// <summary>获取主板的信息。</summary>
  283. public static string GetBaseBoardInfomation()
  284. {
  285. var vbb = GetHardwareInfomation("win32_baseboard", "serialnumber");
  286. var vb = GetHardwareInfomation("win32_bios", "serialnumber");
  287. return vbb + vb;
  288. }
  289. #endif
  290. #endregion
  291. #region 屏幕/桌面。
  292. /// <summary>关闭屏幕。</summary>
  293. public static void CloseScreen()
  294. {
  295. User32.SendMessage(IntPtr.Zero, 274, 61808, 2);
  296. }
  297. /// <summary>获取系统支持的屏幕分辨率。</summary>
  298. public static List<System.Drawing.Size> GetAvailableScreenResolution()
  299. {
  300. var list = new List<System.Drawing.Size>();
  301. int rc = -1;
  302. int mn = 0;
  303. while (rc != 0)
  304. {
  305. var dm = new DevMode();
  306. rc = User32.EnumDisplaySettings(null, mn, ref dm);
  307. if (rc != 0)
  308. {
  309. var size = new System.Drawing.Size(dm.dmPelsHeight, dm.dmPelsWidth);
  310. var exist = false;
  311. foreach (var cell in list)
  312. {
  313. if ((size.Width == cell.Width) && (size.Height == cell.Height))
  314. {
  315. exist = true;
  316. break;
  317. }
  318. }
  319. if (!exist) list.Add(size);
  320. mn += 1;
  321. }
  322. }
  323. return list;
  324. }
  325. /// <summary>设置屏幕分辨率。</summary>
  326. public static bool SetScreenResolution(System.Drawing.Size resolution)
  327. {
  328. if (resolution == null) return false;
  329. return SetScreenResolution(resolution.Width, resolution.Height, 0);
  330. }
  331. /// <summary>设置屏幕分辨率。</summary>
  332. public static bool SetScreenResolution(System.Drawing.Size resolution, short depth)
  333. {
  334. if (resolution == null) return false;
  335. return SetScreenResolution(resolution.Width, resolution.Height, depth);
  336. }
  337. /// <summary>设置屏幕分辨率。</summary>
  338. public static bool SetScreenResolution(int width, int height)
  339. {
  340. return SetScreenResolution(width, height, 0);
  341. }
  342. /// <summary>设置屏幕分辨率。</summary>
  343. public static bool SetScreenResolution(int width, int height, short depth)
  344. {
  345. if (width < 0) return false;
  346. if (height < 0) return false;
  347. if (depth < 0) return false;
  348. // 初始化 DEVMODE 结构。
  349. var dm = new DevMode();
  350. dm.dmDeviceName = new String(new char[32]);
  351. dm.dmFormName = new String(new char[32]);
  352. dm.dmSize = (short)Marshal.SizeOf(dm);
  353. var verify = User32.EnumDisplaySettings(null, Constant.ENUM_CURRENT_SETTINGS, ref dm);
  354. if (verify != 0)
  355. {
  356. dm.dmPelsWidth = width;
  357. dm.dmPelsHeight = height;
  358. //if (argDepth > 0) vdm.dmBitsPerPel = argDepth;
  359. // 改变分辨率。
  360. int cds = User32.ChangeDisplaySettings(ref dm, Constant.CDS_TEST);
  361. if (cds == Constant.DISP_CHANGE_FAILED) return false;
  362. cds = User32.ChangeDisplaySettings(ref dm, Constant.CDS_UPDATEREGISTRY);
  363. switch (cds)
  364. {
  365. case Constant.DISP_CHANGE_SUCCESSFUL: return true;
  366. case Constant.DISP_CHANGE_RESTART: return true;
  367. default: return false;
  368. }
  369. }
  370. // 指定的分辨率不受支持。
  371. return false;
  372. }
  373. private static void UnitiGoFullScreen()
  374. {
  375. const int GWL_STYLE = -16;
  376. const int WS_BORDER = 1;
  377. IntPtr i = User32.FindWindow("UnityWndClass", null);
  378. User32.SetWindowLong(i, GWL_STYLE, WS_BORDER);
  379. User32.ShowWindow(i, 1);
  380. }
  381. #endregion
  382. #region 鼠标指针。
  383. /// <summary>移动鼠标指针。</summary>
  384. public static void MousePointerMove(int x, int y)
  385. {
  386. User32.mouse_Callback(MouseCallbackFlag.LeftDown, x, y, 0, UIntPtr.Zero);
  387. }
  388. /// <summary>按下鼠标左键。</summary>
  389. public static void MouseLeftDown(int x, int y)
  390. {
  391. User32.mouse_Callback(MouseCallbackFlag.LeftDown, x, y, 0, UIntPtr.Zero);
  392. }
  393. /// <summary>释放鼠标左键。</summary>
  394. public static void MouseLeftUp(int x, int y)
  395. {
  396. User32.mouse_Callback(MouseCallbackFlag.LeftUp, x, y, 0, UIntPtr.Zero);
  397. }
  398. /// <summary>按下鼠标中键。</summary>
  399. public static void MouseMiddleDown(int x, int y)
  400. {
  401. User32.mouse_Callback(MouseCallbackFlag.MiddleDown, x, y, 0, UIntPtr.Zero);
  402. }
  403. /// <summary>释放鼠标中键。</summary>
  404. public static void MouseMiddleUp(int x, int y)
  405. {
  406. User32.mouse_Callback(MouseCallbackFlag.MiddleUp, x, y, 0, UIntPtr.Zero);
  407. }
  408. /// <summary>按下鼠标右键。</summary>
  409. public static void MouseRightDown(int x, int y)
  410. {
  411. User32.mouse_Callback(MouseCallbackFlag.RightDown, x, y, 0, UIntPtr.Zero);
  412. }
  413. /// <summary>释放鼠标右键。</summary>
  414. public static void MouseRightUp(int x, int y)
  415. {
  416. User32.mouse_Callback(MouseCallbackFlag.RightUp, x, y, 0, UIntPtr.Zero);
  417. }
  418. #endregion
  419. #region 窗体控制。
  420. /// <summary>获取指定窗体的句柄。</summary>
  421. /// <param name="title">窗体标题。</param>
  422. public static IntPtr GetWindowHandle(string title)
  423. {
  424. var handle = User32.FindWindow(null, title ?? "");
  425. return handle;
  426. }
  427. private static List<IntPtr> WindowHandleList = null;
  428. private static bool EnumWindowsCallBack(int hwnd, int lparam)
  429. {
  430. WindowHandleList.Add(new IntPtr(hwnd));
  431. return true;
  432. }
  433. /// <summary>获取所有窗体的句柄。</summary>
  434. /// <returns></returns>
  435. public static List<IntPtr> GetWindowHandle()
  436. {
  437. if (WindowHandleList != null)
  438. {
  439. WindowHandleList.Clear();
  440. WindowHandleList = null;
  441. }
  442. WindowHandleList = new List<IntPtr>();
  443. var callback = new EnumWindowsCallBack(EnumWindowsCallBack);
  444. var enumResult = User32.EnumWindows(callback, 0);
  445. return WindowHandleList;
  446. }
  447. /// <summary>获取指定窗体的标题。</summary>
  448. /// <param name="handle">窗体句柄。</param>
  449. public static string GetWindowTitle(IntPtr handle)
  450. {
  451. var sb = new StringBuilder(1024);
  452. var rc = User32.GetWindowTextW(handle, sb, sb.Capacity);
  453. var title = sb.ToString();
  454. return title;
  455. }
  456. /// <summary>向指定窗体发送消息。</summary>
  457. public static void PostMessage(IntPtr argHandle, int argMessage)
  458. {
  459. if (argHandle != IntPtr.Zero)
  460. {
  461. User32.PostMessage(argHandle, argMessage, IntPtr.Zero, IntPtr.Zero);
  462. }
  463. }
  464. /// <summary>还原显示指定窗体,并设置焦点至该窗体。</summary>
  465. /// <param name="argHandle"></param>
  466. public static void RestoreWindow(IntPtr argHandle)
  467. {
  468. if (argHandle != IntPtr.Zero)
  469. {
  470. User32.ShowWindow(argHandle, Constant.SW_RESTORE);
  471. User32.SetForegroundWindow(argHandle);
  472. }
  473. }
  474. #endregion
  475. #region 注册表。
  476. #if NETFX
  477. /// <summary>获取用于记录卸载信息的注册表路径。</summary>
  478. public static string[] GetUnInstallPath()
  479. {
  480. const string win32uninstall = "software\\microsoft\\windows\\currentversion\\uninstall";
  481. const string wow64uninstall = "software\\wow6432node\\microsoft\\windows\\currentversion\\uninstall";
  482. var vuninstallpath = new List<string>();
  483. var vwin32rk = Registry.LocalMachine.OpenSubKey(win32uninstall);
  484. var vwin32skns = vwin32rk.GetSubKeyNames();
  485. foreach (var i in vwin32skns) vuninstallpath.Add(win32uninstall + "\\" + i);
  486. vwin32rk.Close();
  487. if (WindowsIsX64)
  488. {
  489. var vwow64rk = Registry.LocalMachine.OpenSubKey(wow64uninstall);
  490. var vwow64skns = vwow64rk.GetSubKeyNames();
  491. foreach (var i in vwow64skns) vuninstallpath.Add(wow64uninstall + "\\" + i);
  492. vwow64rk.Close();
  493. }
  494. return vuninstallpath.ToArray();
  495. }
  496. #endif
  497. #endregion
  498. #region COM
  499. #if NETFX
  500. /// <summary>创建快捷方式。</summary>
  501. /// <param name="linkPath">快捷方式路径。</param>
  502. /// <param name="linkIcon">快捷方式图标。可使用 c:\source.exe,0 格式。</param>
  503. /// <param name="linkDescription">快捷方式说明。</param>
  504. /// <param name="sourcePath">源路径。</param>
  505. /// <param name="sourceArgs">源参数。</param>
  506. /// <param name="directory">工作目录。</param>
  507. public static void CreateShortcut(string linkPath, string sourcePath, string sourceArgs = null, string linkIcon = null, string linkDescription = null, string directory = null)
  508. {
  509. // var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
  510. // var shortcut = (IWshShortcut)new WshShellClass().CreateShortcut(linkPath);
  511. var wshShellClass = new IWshRuntimeLibrary.WshShellClass();
  512. var wshObject = wshShellClass.CreateShortcut(linkPath);
  513. var wshShortcut = (IWshRuntimeLibrary.IWshShortcut)wshObject;
  514. var shortcut = wshShortcut;
  515. shortcut.TargetPath = sourcePath ?? "";
  516. shortcut.Arguments = sourceArgs ?? "arg1";
  517. shortcut.Description = linkDescription ?? "Invalid Description";
  518. shortcut.WorkingDirectory = directory ?? "";
  519. shortcut.IconLocation = linkIcon;
  520. shortcut.WindowStyle = 1;
  521. // shortcut.WorkingDirectory = "";
  522. // shortcut.RelativePath = "";
  523. shortcut.Save();
  524. }
  525. #endif
  526. #endregion
  527. }
  528. }