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.

1046 lines
38 KiB

2 years ago
3 years ago
4 years ago
2 years ago
2 years ago
2 years ago
2 years ago
4 years ago
4 years ago
4 years ago
  1. using Apewer.Internals.Interop;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.IO;
  6. using System.Runtime.InteropServices;
  7. using System.Security;
  8. using System.Reflection;
  9. using System.Diagnostics;
  10. #if NETFX || NETCORE
  11. using Microsoft.Win32;
  12. using System.Drawing.Drawing2D;
  13. using System.Drawing.Imaging;
  14. using System.Drawing.Text;
  15. using System.Windows.Forms;
  16. #endif
  17. using static Apewer.Internals.Interop.SHCore;
  18. namespace Apewer.Surface
  19. {
  20. /// <summary>窗体实用工具。</summary>
  21. [SecuritySafeCritical]
  22. public class FormsUtility
  23. {
  24. /// <summary>线程锁。</summary>
  25. public static object ThreadLocker = new object();
  26. /// <summary>已使用系统 DPI 设置。</summary>
  27. public static bool UsedSystemDPI { get; private set; }
  28. internal static Nullable<float> DpiScale { get; set; }
  29. #if NETFX || NETCORE
  30. /// <summary>窗体启动初始化。</summary>
  31. [STAThread]
  32. public static void StartInitialization(bool useSystemDPI = false)
  33. {
  34. Control.CheckForIllegalCrossThreadCalls = false;
  35. Application.EnableVisualStyles();
  36. Application.SetCompatibleTextRenderingDefault(false);
  37. #if NETCORE
  38. Application.SetHighDpiMode(HighDpiMode.SystemAware);
  39. #endif
  40. // Application.SetCompatibleTextRenderingDefault(true);
  41. if (useSystemDPI) UseSystemDPI();
  42. }
  43. /// <summary>使用系统的 DPI 设置。</summary>
  44. public static void UseSystemDPI()
  45. {
  46. if (UsedSystemDPI) return;
  47. UsedSystemDPI = true;
  48. #if NETCORE
  49. Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
  50. #else
  51. SetProcessDpiAwareness(PROCESS_DPI_AWARENESS.Process_System_DPI_Aware);
  52. Marshal.GetLastWin32Error();
  53. PROCESS_DPI_AWARENESS awareness;
  54. GetProcessDpiAwareness(Process.GetCurrentProcess().Handle, out awareness);
  55. Marshal.GetLastWin32Error();
  56. #endif
  57. }
  58. /// <summary>禁用跨线程调用检查。</summary>
  59. public static void CrossThread()
  60. {
  61. Control.CheckForIllegalCrossThreadCalls = false;
  62. }
  63. #endif
  64. #region 颜色。
  65. /// <summary>获取所有可枚举的颜色。</summary>
  66. public static Color[] EnumerableColor
  67. {
  68. get
  69. {
  70. var list = new List<Color>();
  71. list.Add(Color.AliceBlue);
  72. list.Add(Color.AntiqueWhite);
  73. list.Add(Color.Aqua);
  74. list.Add(Color.Aquamarine);
  75. list.Add(Color.Azure);
  76. list.Add(Color.Beige);
  77. list.Add(Color.Bisque);
  78. list.Add(Color.Black);
  79. list.Add(Color.BlanchedAlmond);
  80. list.Add(Color.Blue);
  81. list.Add(Color.BlueViolet);
  82. list.Add(Color.Brown);
  83. list.Add(Color.BurlyWood);
  84. list.Add(Color.CadetBlue);
  85. list.Add(Color.Chartreuse);
  86. list.Add(Color.Chocolate);
  87. list.Add(Color.Coral);
  88. list.Add(Color.CornflowerBlue);
  89. list.Add(Color.Cornsilk);
  90. list.Add(Color.Crimson);
  91. list.Add(Color.Cyan);
  92. list.Add(Color.DarkBlue);
  93. list.Add(Color.DarkCyan);
  94. list.Add(Color.DarkGoldenrod);
  95. list.Add(Color.DarkGray);
  96. list.Add(Color.DarkGreen);
  97. list.Add(Color.DarkKhaki);
  98. list.Add(Color.DarkMagenta);
  99. list.Add(Color.DarkOliveGreen);
  100. list.Add(Color.DarkOrange);
  101. list.Add(Color.DarkOrchid);
  102. list.Add(Color.DarkRed);
  103. list.Add(Color.DarkSalmon);
  104. list.Add(Color.DarkSeaGreen);
  105. list.Add(Color.DarkSlateBlue);
  106. list.Add(Color.DarkSlateGray);
  107. list.Add(Color.DarkTurquoise);
  108. list.Add(Color.DarkViolet);
  109. list.Add(Color.DeepPink);
  110. list.Add(Color.DeepSkyBlue);
  111. list.Add(Color.DimGray);
  112. list.Add(Color.DodgerBlue);
  113. list.Add(Color.Firebrick);
  114. list.Add(Color.FloralWhite);
  115. list.Add(Color.ForestGreen);
  116. list.Add(Color.Fuchsia);
  117. list.Add(Color.Gainsboro);
  118. list.Add(Color.GhostWhite);
  119. list.Add(Color.Gold);
  120. list.Add(Color.Goldenrod);
  121. list.Add(Color.Gray);
  122. list.Add(Color.Green);
  123. list.Add(Color.GreenYellow);
  124. list.Add(Color.Honeydew);
  125. list.Add(Color.HotPink);
  126. list.Add(Color.IndianRed);
  127. list.Add(Color.Indigo);
  128. list.Add(Color.Ivory);
  129. list.Add(Color.Khaki);
  130. list.Add(Color.Lavender);
  131. list.Add(Color.LavenderBlush);
  132. list.Add(Color.LawnGreen);
  133. list.Add(Color.LemonChiffon);
  134. list.Add(Color.LightBlue);
  135. list.Add(Color.LightCoral);
  136. list.Add(Color.LightCyan);
  137. list.Add(Color.LightGoldenrodYellow);
  138. list.Add(Color.LightGray);
  139. list.Add(Color.LightGreen);
  140. list.Add(Color.LightPink);
  141. list.Add(Color.LightSalmon);
  142. list.Add(Color.LightSeaGreen);
  143. list.Add(Color.LightSkyBlue);
  144. list.Add(Color.LightSlateGray);
  145. list.Add(Color.LightSteelBlue);
  146. list.Add(Color.LightYellow);
  147. list.Add(Color.Lime);
  148. list.Add(Color.LimeGreen);
  149. list.Add(Color.Linen);
  150. list.Add(Color.Magenta);
  151. list.Add(Color.Maroon);
  152. list.Add(Color.MediumAquamarine);
  153. list.Add(Color.MediumBlue);
  154. list.Add(Color.MediumOrchid);
  155. list.Add(Color.MediumPurple);
  156. list.Add(Color.MediumSeaGreen);
  157. list.Add(Color.MediumSlateBlue);
  158. list.Add(Color.MediumSpringGreen);
  159. list.Add(Color.MediumTurquoise);
  160. list.Add(Color.MediumVioletRed);
  161. list.Add(Color.MidnightBlue);
  162. list.Add(Color.MintCream);
  163. list.Add(Color.MistyRose);
  164. list.Add(Color.Moccasin);
  165. list.Add(Color.NavajoWhite);
  166. list.Add(Color.Navy);
  167. list.Add(Color.OldLace);
  168. list.Add(Color.Olive);
  169. list.Add(Color.OliveDrab);
  170. list.Add(Color.Orange);
  171. list.Add(Color.OrangeRed);
  172. list.Add(Color.Orchid);
  173. list.Add(Color.PaleGoldenrod);
  174. list.Add(Color.PaleGreen);
  175. list.Add(Color.PaleTurquoise);
  176. list.Add(Color.PaleVioletRed);
  177. list.Add(Color.PapayaWhip);
  178. list.Add(Color.PeachPuff);
  179. list.Add(Color.Peru);
  180. list.Add(Color.Pink);
  181. list.Add(Color.Plum);
  182. list.Add(Color.PowderBlue);
  183. list.Add(Color.Purple);
  184. list.Add(Color.Red);
  185. list.Add(Color.RosyBrown);
  186. list.Add(Color.RoyalBlue);
  187. list.Add(Color.SaddleBrown);
  188. list.Add(Color.Salmon);
  189. list.Add(Color.SandyBrown);
  190. list.Add(Color.SeaGreen);
  191. list.Add(Color.SeaShell);
  192. list.Add(Color.Sienna);
  193. list.Add(Color.Silver);
  194. list.Add(Color.SkyBlue);
  195. list.Add(Color.SlateBlue);
  196. list.Add(Color.SlateGray);
  197. list.Add(Color.Snow);
  198. list.Add(Color.SpringGreen);
  199. list.Add(Color.SteelBlue);
  200. list.Add(Color.Tan);
  201. list.Add(Color.Teal);
  202. list.Add(Color.Thistle);
  203. list.Add(Color.Tomato);
  204. //list.Add(Color.Transparent);
  205. list.Add(Color.Turquoise);
  206. list.Add(Color.Violet);
  207. list.Add(Color.Wheat);
  208. list.Add(Color.White);
  209. list.Add(Color.WhiteSmoke);
  210. list.Add(Color.Yellow);
  211. list.Add(Color.YellowGreen);
  212. return list.ToArray();
  213. }
  214. }
  215. /// <summary>用于填充背景色。</summary>
  216. public static Color GraceWall { get { return Color.FromArgb(0xff, 0xf7, 0xf7, 0xf7); } }
  217. /// <summary>用于控件边框。</summary>
  218. public static Color GraceBorder { get { return Color.FromArgb(0xff, 0xdf, 0xdf, 0xdf); } }
  219. /// <summary>用于无效的文本、备注文本。</summary>
  220. public static Color GraceLocked { get { return Color.FromArgb(0xff, 0x7f, 0x7f, 0x7f); } }
  221. /// <summary>用于次级文本。</summary>
  222. public static Color GraceMinor { get { return Color.FromArgb(0xff, 0x3f, 0x3f, 0x3f); } }
  223. /// <summary>用于焦点状态的控件边框。</summary>
  224. public static Color GraceSilver { get { return Color.FromArgb(0xff, 0xbf, 0xbf, 0xbf); } }
  225. /// <summary>系统定义的颜色。</summary>
  226. public static Color Transparent { get { return Color.Transparent; } }
  227. /// <summary>系统定义的颜色。</summary>
  228. public static Color Black { get { return Color.Black; } }
  229. /// <summary>系统定义的颜色。</summary>
  230. public static Color White { get { return Color.White; } }
  231. /// <summary>系统定义的颜色。</summary>
  232. public static Color Gray { get { return Color.Gray; } }
  233. /// <summary>系统定义的颜色。</summary>
  234. public static Color DarkGray { get { return Color.DarkGray; } }
  235. /// <summary>系统定义的颜色。</summary>
  236. public static Color LightGray { get { return Color.LightGray; } }
  237. /// <summary>系统定义的颜色。</summary>
  238. public static Color Red { get { return Color.Red; } }
  239. /// <summary>系统定义的颜色。</summary>
  240. public static Color Green { get { return Color.Green; } }
  241. /// <summary>系统定义的颜色。</summary>
  242. public static Color Blue { get { return Color.Blue; } }
  243. /// <summary>系统定义的颜色。</summary>
  244. public static Color Orange { get { return Color.DarkOrange; } }
  245. /// <summary>系统定义的颜色。</summary>
  246. public static Color Purple { get { return Color.Purple; } }
  247. /// <summary>随机主题色。</summary>
  248. public static Color RandomColor
  249. {
  250. get { var colors = EnumerableColor; return colors[NumberUtility.Random(colors.Length - 1)]; }
  251. }
  252. /// <summary>计算 Alpha 合成颜色(基色),基色均需计算。</summary>
  253. /// <param name="alpha">前景色 Alpha 值。</param>
  254. /// <param name="back">背景色(基色)。</param>
  255. /// <param name="fore">前景色(基色)。</param>
  256. /// <param name="depth">颜色深度,最大值。</param>
  257. /// <returns>合成后的颜色(基色)。</returns>
  258. public static int MixAlpha(int alpha, int fore, int back, int depth = 255)
  259. {
  260. int b = back, f = fore;
  261. if (b > depth) b = depth; if (b < 0) b = 0;
  262. if (f > depth) f = depth; if (f < 0) f = 0;
  263. int v = fore * alpha / depth + back * (depth - alpha) / depth;
  264. if (v > depth) v = depth; if (v < 0) v = 0;
  265. return v;
  266. }
  267. /// <summary>按 Alpha 混合不透明的颜色。</summary>
  268. /// <param name="backColor">背景色。</param>
  269. /// <param name="foreColor">前景色。</param>
  270. /// <param name="foreAlpha">前景 Alpha 值。</param>
  271. /// <returns>混合后的颜色。</returns>
  272. public static Color MixAlpha(Color backColor, Color foreColor, int foreAlpha)
  273. {
  274. var r = MixAlpha(backColor.R, foreColor.R, foreAlpha);
  275. var g = MixAlpha(backColor.G, foreColor.G, foreAlpha);
  276. var b = MixAlpha(backColor.B, foreColor.B, foreAlpha);
  277. var a = MixAlpha(backColor.A, foreColor.A, foreAlpha);
  278. return Color.FromArgb(a, r, g, b);
  279. }
  280. #endregion
  281. #region 屏幕。
  282. #if NETFX || NETCORE
  283. /// <summary>获取屏幕的截图。</summary>
  284. public static Bitmap[] ScreenShot()
  285. {
  286. var list = new List<Bitmap>();
  287. var all = Screen.AllScreens;
  288. foreach (var screen in all)
  289. {
  290. int vw = screen.Bounds.Width;
  291. int vh = screen.Bounds.Height;
  292. int vd = screen.BitsPerPixel;
  293. Bitmap b = new Bitmap(vw, vh, PixelFormat.Format32bppArgb);
  294. Graphics g = Graphics.FromImage(b);
  295. g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(vw, vh));
  296. g.Dispose();
  297. list.Add(b);
  298. }
  299. return list.ToArray();
  300. }
  301. /// <summary>获取指定屏幕的截图。</summary>
  302. /// <param name="screen">屏幕号。</param>
  303. internal static Bitmap ScreenShot(int screen)
  304. {
  305. var a = Screen.AllScreens;
  306. if ((a.Length > 0) && (screen >= 0) && (screen < a.Length))
  307. {
  308. try
  309. {
  310. int w = a[screen].Bounds.Width;
  311. int h = a[screen].Bounds.Height;
  312. int d = a[screen].BitsPerPixel;
  313. Bitmap b = new Bitmap(w, h, PixelFormat.Format32bppArgb);
  314. Graphics g = Graphics.FromImage(b);
  315. g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(w, h));
  316. g.Dispose();
  317. return b;
  318. }
  319. catch { }
  320. }
  321. return new Bitmap(0, 0, PixelFormat.Format32bppArgb);
  322. }
  323. /// <summary>获取指定屏幕的截图。</summary>
  324. /// <param name="screen">屏幕,若为 Null 则选择主屏幕。</param>
  325. internal static Bitmap ScreenShot(Screen screen)
  326. {
  327. if (screen == null)
  328. {
  329. try
  330. {
  331. int w = Screen.PrimaryScreen.Bounds.Width;
  332. int h = Screen.PrimaryScreen.Bounds.Height;
  333. int d = Screen.PrimaryScreen.BitsPerPixel;
  334. Bitmap b = new Bitmap(w, h, PixelFormat.Format32bppArgb);
  335. Graphics g = Graphics.FromImage(b);
  336. g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(w, h));
  337. g.Dispose();
  338. return b;
  339. }
  340. catch { }
  341. }
  342. return new Bitmap(0, 0, PixelFormat.Format32bppArgb);
  343. }
  344. #endif
  345. #endregion
  346. #region Aero
  347. /// <summary>获取 DWM 的 Composition 启用状态。</summary>
  348. public static bool DwmIsCompositionEnabled
  349. {
  350. get => DwmApi.DwmIsCompositionEnabled();
  351. }
  352. #endregion
  353. #region 窗体。
  354. #if NETFX || NETCORE
  355. /// <summary>移动窗体。</summary>
  356. public static void MoveForm(Form form)
  357. {
  358. if (form != null) MoveForm(form.Handle);
  359. }
  360. /// <summary>移动窗体。</summary>
  361. public static void MoveForm(IntPtr form)
  362. {
  363. User32.ReleaseCapture();
  364. User32.SendMessage(form, 0x112, new IntPtr(Constant.SC_MOVE + 2), new IntPtr(0));
  365. }
  366. /// <summary>启用鼠标穿透。</summary>
  367. public static void MousePenetration(Form form)
  368. {
  369. if (form != null) MousePenetration(form.Handle);
  370. }
  371. /// <summary>启用鼠标穿透。</summary>
  372. public static void MousePenetration(IntPtr form)
  373. {
  374. int intExTemp = User32.GetWindowLong(form, Constant.GWL_EXSTYLE);
  375. int oldGWLEx = User32.SetWindowLong(form, Constant.GWL_EXSTYLE, Constant.WS_EX_TRANSPARENT | Constant.WS_EX_LAYERED);
  376. }
  377. /// <summary>将窗体最大化,不覆盖任务栏。</summary>
  378. /// <param name="form">窗体。</param>
  379. public static void ToMaximum(Form form)
  380. {
  381. if (form != null)
  382. {
  383. var s = Screen.FromControl(form);
  384. var r = s.WorkingArea;
  385. if ((form.MaximumSize.Width < r.Width) || (form.MaximumSize.Height < r.Height))
  386. {
  387. form.MaximumSize = r.Size;
  388. }
  389. form.Location = r.Location;
  390. form.Size = r.Size;
  391. }
  392. }
  393. /// <summary>用指定图像绘制窗体,窗体与图像的大小必须一致。</summary>
  394. /// <param name="form">要绘制的窗体。</param>
  395. /// <param name="image">要使用的图像。</param>
  396. public static void UpdateShadow(Form form, Image image)
  397. {
  398. if ((form != null) && (image != null))
  399. {
  400. Bitmap vbitmap;
  401. if ((form.Width != image.Width) || (form.Height != image.Height))
  402. {
  403. vbitmap = new Bitmap(image.GetThumbnailImage(form.Width, form.Height, null, IntPtr.Zero));
  404. }
  405. else
  406. {
  407. vbitmap = new Bitmap(image);
  408. }
  409. var screendc = User32.GetDC(IntPtr.Zero);
  410. var location = new Internals.Interop.Point(form.Left, form.Top);
  411. var size = new Internals.Interop.Size(form.Width, form.Height);
  412. var compatibledc = Gdi32.CreateCompatibleDC(screendc);
  413. var handle = vbitmap.GetHbitmap(Color.FromArgb(0));
  414. var oldbitmap = Gdi32.SelectObject(compatibledc, handle);
  415. var srcloc = new Internals.Interop.Point(0, 0);
  416. var blendfunction = new BlendFunction();
  417. blendfunction.blendop = Constant.AC_SRC_OVER;
  418. blendfunction.sourceconstantalpha = byte.Parse("255");
  419. blendfunction.alphaformat = Constant.AC_SRC_ALPHA;
  420. blendfunction.blendflags = 0;
  421. User32.UpdateLayeredWindow(form.Handle, screendc, ref location, ref size, compatibledc, ref srcloc, 0, ref blendfunction, Constant.ULW_ALPHA);
  422. if (handle != IntPtr.Zero)
  423. {
  424. Gdi32.SelectObject(compatibledc, oldbitmap);
  425. Gdi32.DeleteObject(handle);
  426. }
  427. User32.ReleaseDC(IntPtr.Zero, screendc);
  428. Gdi32.DeleteDC(compatibledc);
  429. }
  430. }
  431. /// <summary>为窗体启用阴影。</summary>
  432. /// <param name="form">要启用阴影的窗体。</param>
  433. public static void EnableShadow(Form form)
  434. {
  435. if (form == null) return;
  436. int vformclass = User32.GetClassLong(form.Handle, Constant.GCL_STYLE);
  437. User32.SetClassLong(form.Handle, Constant.GCL_STYLE, vformclass | Constant.CS_DROPSHADOW);
  438. }
  439. /// <summary>恢复任务栏中窗体标题的右键菜单。</summary>
  440. public static void SetTaskMenu(Form form)
  441. {
  442. if (form != null)
  443. {
  444. var hwnd = form.Handle;
  445. var href = new HandleRef(form, hwnd);
  446. int windowLong = (User32.GetWindowLong(hwnd, -16));
  447. User32.SetWindowLong(hwnd, -16, windowLong | Constant.WS_SYSMENU | Constant.WS_MINIMIZEBOX);
  448. }
  449. }
  450. #endif
  451. #endregion
  452. #region 控件。
  453. #if NETFX || NETCORE
  454. /// <summary>在主界面中移动控件,由目标控件取代当前控件,形成切换控件的动画。</summary>
  455. /// <param name="current">当前显示的控件。</param>
  456. /// <param name="target">将要显示的目标控件。</param>
  457. public static void AnimateGoPanel(Control current, Control target)
  458. {
  459. AnimateGoPanel(current.Location, current.Size, 0, 10, current, target, true);
  460. }
  461. /// <summary>在主界面中移动控件,由目标控件取代当前控件,形成切换控件的动画。</summary>
  462. /// <param name="current">当前显示的控件。</param>
  463. /// <param name="target">将要显示的目标控件。</param>
  464. /// <param name="next">向左移动。</param>
  465. public static void AnimateGoPanel(Control current, Control target, bool next)
  466. {
  467. AnimateGoPanel(current.Location, current.Size, 0, 10, current, target, next);
  468. }
  469. /// <summary>在主界面中移动控件,由目标控件取代当前控件,形成切换控件的动画。</summary>
  470. /// <param name="point">控件左上角坐标。</param>
  471. /// <param name="size">控件大小。</param>
  472. /// <param name="span">当前控件和目标控件的间距,若值小于 0 则更正为 0 。</param>
  473. /// <param name="frame">移动的次数,若值小于 0 则更正为 20。</param>
  474. /// <param name="current">当前显示的控件。</param>
  475. /// <param name="target">将要显示的目标控件。</param>
  476. /// <param name="next">向左移动。</param>
  477. public static void AnimateGoPanel(System.Drawing.Point point, System.Drawing.Size size, int span, int frame, Control current, Control target, bool next = true)
  478. {
  479. int s = (span < 0) ? span : 0;
  480. int step = (current.Width + s) / ((frame < 1) ? 20 : frame);
  481. int x = point.X;
  482. int y = point.Y;
  483. current.Size = size;
  484. target.Size = size;
  485. current.Location = point;
  486. if (next)
  487. {
  488. target.Location = new System.Drawing.Point(size.Width, point.Y);
  489. current.Visible = true;
  490. target.Visible = true;
  491. Application.DoEvents();
  492. while (target.Left > x)
  493. {
  494. s = ((target.Left - x) < step) ? (target.Left - x) : step;
  495. target.Left -= s;
  496. current.Left -= s;
  497. Application.DoEvents();
  498. System.Threading.Thread.Sleep(1);
  499. }
  500. }
  501. else
  502. {
  503. target.Location = new System.Drawing.Point(x - size.Width, x);
  504. current.Visible = true;
  505. target.Visible = true;
  506. Application.DoEvents();
  507. while (target.Left < x)
  508. {
  509. s = ((x - target.Left) < step) ? x - target.Left : step;
  510. target.Left += s;
  511. current.Left += s;
  512. Application.DoEvents();
  513. System.Threading.Thread.Sleep(1);
  514. }
  515. }
  516. current.Visible = false;
  517. }
  518. /// <summary></summary>
  519. public static void Invoke(Control control, Action action, bool async = false)
  520. {
  521. if (control == null || action == null) return;
  522. // control.Invoke(action);
  523. if (async)
  524. {
  525. control.BeginInvoke(new Action(delegate ()
  526. {
  527. action.Invoke();
  528. }));
  529. }
  530. else
  531. {
  532. control.Invoke(new Action(delegate ()
  533. {
  534. action.Invoke();
  535. }));
  536. }
  537. }
  538. /// <summary></summary>
  539. public static void BeginInvoke(Control control, Action action)
  540. {
  541. if (control == null || action == null) return;
  542. control.BeginInvoke(new Action(delegate ()
  543. {
  544. action.Invoke();
  545. }));
  546. }
  547. /// <summary>设置窗体置顶。</summary>
  548. public static void SetTopMost(IntPtr form, bool value = true)
  549. {
  550. if (form == null || form == IntPtr.Zero) return;
  551. User32.SetWindowPos(form, new IntPtr(value ? -1 : -2), 0, 0, 0, 0, 3);
  552. }
  553. /// <summary>设置窗体置顶。</summary>
  554. public static void SetTopMost(Form form, bool value = true)
  555. {
  556. if (form != null) SetTopMost(form.Handle, value);
  557. }
  558. #endif
  559. #endregion
  560. #region 绘图。
  561. #if NETFX || NETCORE
  562. /// <summary>绘制内边框。</summary>
  563. /// <param name="image">源图像。</param>
  564. /// <param name="border">边框颜色。</param>
  565. public static bool PaintBorder(ref Image image, Color border)
  566. {
  567. if (image != null)
  568. {
  569. var g = Graphics.FromImage(image);
  570. var p = new Pen(border);
  571. g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1);
  572. p.Dispose();
  573. g.Dispose();
  574. return true;
  575. }
  576. else return false;
  577. }
  578. /// <summary>绘制内边框。</summary>
  579. /// <param name="image">源图像。</param>
  580. /// <param name="border">边框颜色。</param>
  581. public static bool PaintBorder(ref Bitmap image, Color border)
  582. {
  583. if (image != null)
  584. {
  585. var g = Graphics.FromImage(image);
  586. var p = new Pen(border);
  587. g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1);
  588. p.Dispose();
  589. g.Dispose();
  590. return true;
  591. }
  592. else return false;
  593. }
  594. /// <summary>绘制内边框。</summary>
  595. /// <param name="image">源图像。</param>
  596. /// <param name="border">边框颜色。</param>
  597. /// <param name="wall">背景颜色。</param>
  598. public static bool PaintBorder(ref Image image, Color border, Color wall)
  599. {
  600. if (image != null)
  601. {
  602. var g = Graphics.FromImage(image);
  603. var p = new Pen(border);
  604. g.Clear(wall);
  605. g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1);
  606. p.Dispose();
  607. g.Dispose();
  608. return true;
  609. }
  610. else return false;
  611. }
  612. /// <summary>建立带有圆角样式的路径。</summary>
  613. /// <param name="rect">建立矩形路径的区域。</param>
  614. /// <param name="radius">圆角的大小。</param>
  615. /// <returns>建立的路径。</returns>
  616. public static GraphicsPath CreatePath(Rectangle rect, int radius = 0)
  617. {
  618. GraphicsPath path = new GraphicsPath();
  619. int r = (radius < 0) ? 0 : radius;
  620. switch (r)
  621. {
  622. case 0:
  623. path.AddRectangle(rect);
  624. break;
  625. default:
  626. path.AddArc(rect.X, rect.Y, r, r, 180, 90);
  627. path.AddArc(rect.Right - r - 1, rect.Y, r, r, 270, 90);
  628. path.AddArc(rect.Right - r - 1, rect.Bottom - r - 1, r, r, 0, 90);
  629. path.AddArc(rect.X, rect.Bottom - r - 1, r, r, 90, 90);
  630. break;
  631. }
  632. path.CloseFigure();
  633. return path;
  634. }
  635. /// <summary></summary>
  636. /// <param name="location"></param>
  637. /// <param name="size"></param>
  638. /// <param name="radius"></param>
  639. /// <returns></returns>
  640. public static GraphicsPath GetRadiusPath(PointF location, SizeF size, float radius)
  641. {
  642. var loc = location;
  643. var rds = Math.Abs(radius);
  644. var path = new GraphicsPath();
  645. float x, y, r;
  646. r = rds * 2;
  647. // 左上角。
  648. x = loc.X;
  649. y = loc.Y;
  650. path.AddArc(x, y, r, r, 180, 90);
  651. // 右上角。
  652. x = loc.X + size.Width - rds * 2;
  653. y = loc.Y;
  654. path.AddArc(x, y, r, r, 270, 90);
  655. // 左下角。
  656. x = loc.X;
  657. y = loc.Y + size.Height - rds * 2;
  658. path.AddArc(x, y, r, r, 0, 90);
  659. // 右下角。
  660. x = loc.X + size.Width - rds * 2;
  661. y = loc.Y + size.Height - rds * 2;
  662. path.AddArc(x, y, r, r, 90, 90);
  663. // 边框直线:上、下、左、右。
  664. path.AddLine((float)(loc.X + rds), (float)loc.Y, (float)(loc.X + size.Width - rds), (float)loc.Y);
  665. path.AddLine((float)(loc.X + rds), (float)(loc.Y + size.Height), (float)(loc.X + size.Width - rds), (float)(loc.Y + size.Height));
  666. path.AddLine((float)loc.X, (float)(loc.Y + rds), (float)loc.X, (float)(loc.Y + size.Height - rds));
  667. path.AddLine((float)(loc.X + size.Width), (float)(loc.Y + rds), (float)(loc.X + size.Width), (float)(loc.Y + size.Height - rds));
  668. return path;
  669. }
  670. /// <summary>获取指定文件中的图标总数。</summary>
  671. public static int GetIconsCount(string path)
  672. {
  673. if (!File.Exists(path)) return 0;
  674. var count = User32.PrivateExtractIcons(path, 0, 0, 0, null, null, 0, 0);
  675. return count;
  676. }
  677. /// <summary>获取指定文件中的图标。</summary>
  678. public static Bitmap[] GetIconsBitmap(string path = null, int size = 256)
  679. {
  680. if (string.IsNullOrEmpty(path)) path = Application.ExecutablePath;
  681. if (!File.Exists(path)) return null;
  682. var count = User32.PrivateExtractIcons(path, 0, 0, 0, null, null, 0, 0);
  683. var ptrs = new IntPtr[count];
  684. var ids = new int[count];
  685. var succeed = User32.PrivateExtractIcons(path, 0, size, size, ptrs, ids, count, 0);
  686. var images = new Bitmap[count];
  687. for (var i = 0; i < succeed; i++)
  688. {
  689. if (ptrs[i] == IntPtr.Zero) continue;
  690. using (var icon = Icon.FromHandle(ptrs[i]))
  691. {
  692. var bitmap = icon.ToBitmap();
  693. images[i] = bitmap;
  694. }
  695. User32.DestroyIcon(ptrs[i]);
  696. }
  697. return images;
  698. }
  699. /// <summary>从文件获取图标。</summary>
  700. public static Icon GetExecutableIcon(string path)
  701. {
  702. try { return Icon.ExtractAssociatedIcon(path); }
  703. catch { return null; }
  704. }
  705. #endif
  706. #endregion
  707. #region 字体。
  708. private const string FontYahei = "Microsoft Yahei";
  709. private const string FontSimsun = "Simsun";
  710. private const string GuiFontRegKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\GRE_Initialize";
  711. private static string _fontname = "";
  712. /// <summary>存在微软雅黑字体。</summary>
  713. public static bool MsyhExist { get => File.Exists("c:\\windows\\fonts\\msyh.ttc"); }
  714. /// <summary>获取默认字体名称。</summary>
  715. public static string DefaultFontName
  716. {
  717. get
  718. {
  719. if (!string.IsNullOrEmpty(_fontname)) return _fontname;
  720. try
  721. {
  722. if (File.Exists("c:\\windows\\fonts\\msyh.ttc")) return FontYahei;
  723. else return FontSimsun;
  724. }
  725. catch { return FontSimsun; }
  726. }
  727. }
  728. /// <summary>获取默认字体名称。</summary>
  729. public static string GuiFontName { get => Registry.GetValue(GuiFontRegKey, "GUIFont.Facename", "Arial") as string; }
  730. /// <summary>获取默认字体大小。</summary>
  731. public static float GuiFontSize { get => Convert.ToSingle(Registry.GetValue(GuiFontRegKey, "GUIFont.Height", 9F)); }
  732. #if NETFX || NETCORE
  733. /// <summary>获取默认字体。</summary>
  734. public static Font GuiFont { get => new Font(GuiFontName, GuiFontSize); }
  735. /// <summary>获取默认字体。</summary>
  736. public static Font DefaultFont
  737. {
  738. get { return new Font(DefaultFontName, 9); }
  739. }
  740. /// <summary>获取大小为 9 的默认字体。</summary>
  741. public static Font NewFont()
  742. {
  743. return new Font(DefaultFontName, 9);
  744. }
  745. /// <summary>获取指定大小的默认字体。</summary>
  746. public static Font NewFont(float size)
  747. {
  748. return new Font(DefaultFontName, size);
  749. }
  750. /// <summary>获取指定大小的默认字体。</summary>
  751. public static Font NewFont(float size, bool bold)
  752. {
  753. return new Font(DefaultFontName, size, bold ? FontStyle.Bold : FontStyle.Regular);
  754. }
  755. /// <summary>从文件加载字体,并获取指定字体。</summary>
  756. /// <param name="path">文件路径。</param>
  757. /// <param name="index">文件中的 Font Family 索引,默认取第一个(索引 0)。</param>
  758. /// <returns>已存在的 Font Family,如果指定的索引处不存在 Font Family,则返回 NULL 值。</returns>
  759. public static FontFamily LoadFont(string path, int index = 0)
  760. {
  761. if (index < 0) return null;
  762. if (string.IsNullOrEmpty(path)) return null;
  763. if (!File.Exists(path)) return null;
  764. try
  765. {
  766. var pfc = new PrivateFontCollection();
  767. pfc.AddFontFile(path);
  768. var fs = pfc.Families;
  769. if (fs.Length > 0 && index < fs.Length) return fs[index];
  770. }
  771. catch { }
  772. return null;
  773. }
  774. #if NET40 || NET461
  775. /// <summary></summary>
  776. public static List<System.Windows.Media.FontFamily> ListFileFont(string path)
  777. {
  778. try
  779. {
  780. var collection = System.Windows.Media.Fonts.GetFontFamilies(path);
  781. var list = new List<System.Windows.Media.FontFamily>(collection.Count);
  782. foreach (var item in collection) list.Add(item);
  783. return list;
  784. }
  785. catch { }
  786. return new List<System.Windows.Media.FontFamily>();
  787. }
  788. /// <summary></summary>
  789. public static List<System.Windows.Media.FontFamily> ListSystemFont()
  790. {
  791. var collection = System.Windows.Media.Fonts.SystemFontFamilies;
  792. var list = new List<System.Windows.Media.FontFamily>(collection.Count);
  793. foreach (var item in collection) list.Add(item);
  794. return list;
  795. }
  796. /// <summary>枚举指定字体中的所有字符。</summary>
  797. public static List<char> EnumerateFontChars(IEnumerable<System.Windows.Media.Typeface> typefaces)
  798. {
  799. var chars = new List<char>();
  800. if (typefaces != null)
  801. {
  802. foreach (var typeface in typefaces)
  803. {
  804. var subs = EnumerateFontChars(typeface);
  805. if (subs != null) chars.AddRange(subs);
  806. }
  807. }
  808. return chars;
  809. }
  810. /// <summary>枚举指定字体中的所有字符。</summary>
  811. public static char[] EnumerateFontChars(System.Windows.Media.Typeface typeface)
  812. {
  813. System.Windows.Media.GlyphTypeface glyph;
  814. var tried = typeface.TryGetGlyphTypeface(out glyph);
  815. if (glyph == null) return null;
  816. var map = glyph.CharacterToGlyphMap;
  817. var keys = map.Keys;
  818. var chars = new List<char>(keys.Count);
  819. for (int i = 0; i < keys.Count; i++)
  820. {
  821. var index = System.Linq.Enumerable.ElementAt(keys, i);
  822. try
  823. {
  824. var c = Convert.ToChar(index);
  825. chars.Add(c);
  826. }
  827. catch { }
  828. }
  829. return chars.ToArray();
  830. }
  831. #endif
  832. /// <summary>获取已安装的字体。</summary>
  833. public static List<FontFamily> ListInstalledFonts()
  834. {
  835. var list = new List<FontFamily>();
  836. int ret = 0; // Win32 API 返回值,非零值均为异常。
  837. // 初始化 FontCollection。
  838. var collection = new Internals.FontCollection();
  839. ret = GdiPlus.GdipNewInstalledFontCollection(out collection.NativePointer);
  840. if (ret != 0) return list;
  841. // 获取字体总数。
  842. int found1 = 0;
  843. ret = GdiPlus.GdipGetFontCollectionFamilyCount(new HandleRef(collection, collection.NativePointer), out found1);
  844. if (ret != 0) return list;
  845. // 获取字体指针。
  846. var ptrs = new IntPtr[found1];
  847. int found2 = 0;
  848. ret = GdiPlus.GdipGetFontCollectionFamilyList(new HandleRef(collection, collection.NativePointer), found1, ptrs, out found2);
  849. if (ret != 0) return list;
  850. // 获取字体列表。
  851. list.Capacity = found2;
  852. for (int i = 0; i < found2; i++)
  853. {
  854. IntPtr cloned;
  855. GdiPlus.GdipCloneFontFamily(new HandleRef(null, ptrs[i]), out cloned);
  856. try
  857. {
  858. var flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance;
  859. var args = new object[] { cloned };
  860. var instance = Activator.CreateInstance(typeof(FontFamily), flags, null, args, null, null);
  861. var item = instance as FontFamily;
  862. if (item != null) list.Add(item);
  863. }
  864. catch { }
  865. }
  866. list.Capacity = list.Count;
  867. return list;
  868. }
  869. private static bool GlyphExists(char c, Font font)
  870. {
  871. using (var dummy = Graphics.FromImage(new Bitmap(1, 1)))
  872. {
  873. IntPtr hdc = dummy.GetHdc();
  874. var pgi = new ushort[1];
  875. try
  876. {
  877. IntPtr hfont = font.ToHfont();
  878. Gdi32.SelectObject(hdc, hfont);
  879. string str = c.ToString();
  880. Gdi32.GetGlyphIndices(hdc, str, str.Length, pgi, Constant.GGI_MARK_NONEXISTING_GLYPHS);
  881. }
  882. catch { }
  883. dummy.ReleaseHdc(hdc);
  884. // 0xFFFF 表示字形不存在。
  885. return (pgi[0] != 0xffff);
  886. }
  887. }
  888. #endif
  889. #endregion
  890. }
  891. }