From ebbd35482161a53bf12eb0d0279d29c87e9e3e41 Mon Sep 17 00:00:00 2001 From: Elivo Date: Mon, 7 Jun 2021 21:21:42 +0800 Subject: [PATCH] =?UTF-8?q?Apewer-6.3.2=EF=BC=9A=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Apewer/Apewer.csproj | 2 +- Apewer/Internals/FontCollection.cs | 21 + Apewer/Internals/Interop/Constant.cs | 2 + Apewer/Internals/Interop/Gdi32.cs | 41 +- Apewer/Internals/Interop/GdiPlus.cs | 25 + Apewer/NetworkUtility.cs | 20 +- Apewer/RuntimeUtility.cs | 43 +- Apewer/Source/ColumnAttribute.cs | 7 +- Apewer/Source/Record.cs | 21 +- Apewer/Surface/FontInstance.cs | 2 +- Apewer/Surface/FormsUtility.cs | 764 ++++++++++++++++----------- Apewer/Web/ApiProcessor.cs | 8 +- Apewer/_ChangeLog.md | 6 + 13 files changed, 587 insertions(+), 375 deletions(-) create mode 100644 Apewer/Internals/FontCollection.cs create mode 100644 Apewer/Internals/Interop/GdiPlus.cs diff --git a/Apewer/Apewer.csproj b/Apewer/Apewer.csproj index f5d3a33..ed44a85 100644 --- a/Apewer/Apewer.csproj +++ b/Apewer/Apewer.csproj @@ -20,7 +20,7 @@ Apewer Apewer Libraries - 6.3.1 + 6.3.2 diff --git a/Apewer/Internals/FontCollection.cs b/Apewer/Internals/FontCollection.cs new file mode 100644 index 0000000..e296bfe --- /dev/null +++ b/Apewer/Internals/FontCollection.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Apewer.Internals +{ + + internal sealed class FontCollection : IDisposable + { + + public IntPtr NativePointer = IntPtr.Zero; + + ~FontCollection() { Dispose(false); } + + public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } + + private void Dispose(bool disposing) { } + + } + +} diff --git a/Apewer/Internals/Interop/Constant.cs b/Apewer/Internals/Interop/Constant.cs index 7032671..934a7c9 100644 --- a/Apewer/Internals/Interop/Constant.cs +++ b/Apewer/Internals/Interop/Constant.cs @@ -72,6 +72,8 @@ namespace Apewer.Internals.Interop /// public const int GWL_EXSTYLE = -20; + public const uint GGI_MARK_NONEXISTING_GLYPHS = 0x01; + /// public const int INVALID_HANDLE_VALUE = -1; diff --git a/Apewer/Internals/Interop/Gdi32.cs b/Apewer/Internals/Interop/Gdi32.cs index 8ce37d9..54b1203 100644 --- a/Apewer/Internals/Interop/Gdi32.cs +++ b/Apewer/Internals/Interop/Gdi32.cs @@ -8,62 +8,27 @@ namespace Apewer.Internals.Interop internal class Gdi32 { - /// - /// - /// - /// - /// [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] public static extern IntPtr CreateCompatibleDC(IntPtr hdc); - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// [DllImport("gdi32.dll")] public static extern int CreateRoundRectRgn(int x1, int y1, int x2, int y2, int x3, int y3); - /// - /// - /// - /// - /// [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] public static extern int DeleteDC(IntPtr hdc); - /// - /// - /// - /// - /// [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] public static extern int DeleteObject(IntPtr hobj); - /// - /// - /// - /// - /// - /// - /// [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] public static extern IntPtr ExtCreateRegion(IntPtr lpxform, uint ncount, IntPtr rgndata); - /// - /// - /// - /// - /// - /// [DllImport("gdi32.dll", ExactSpelling = true)] public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hobj); + [DllImport("gdi32.dll", EntryPoint = "GetGlyphIndicesW")] + public static extern uint GetGlyphIndices([In] IntPtr hdc, [In][MarshalAs(UnmanagedType.LPTStr)] string lpsz, int c, [Out] ushort[] pgi, uint fl); + } } diff --git a/Apewer/Internals/Interop/GdiPlus.cs b/Apewer/Internals/Interop/GdiPlus.cs new file mode 100644 index 0000000..75e7fb0 --- /dev/null +++ b/Apewer/Internals/Interop/GdiPlus.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace Apewer.Internals.Interop +{ + internal class GdiPlus + { + + [DllImport("gdiplus.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] + internal static extern int GdipCloneFontFamily(HandleRef fontfamily, out IntPtr clonefontfamily); + + [DllImport("gdiplus.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] + internal static extern int GdipGetFontCollectionFamilyCount(HandleRef fontCollection, out int numFound); + + [DllImport("gdiplus.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] + internal static extern int GdipGetFontCollectionFamilyList(HandleRef fontCollection, int numSought, IntPtr[] gpfamilies, out int numFound); + + [DllImport("gdiplus.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] + internal static extern int GdipNewInstalledFontCollection(out IntPtr fontCollection); + + } + +} diff --git a/Apewer/NetworkUtility.cs b/Apewer/NetworkUtility.cs index bf59c37..ac3caba 100644 --- a/Apewer/NetworkUtility.cs +++ b/Apewer/NetworkUtility.cs @@ -46,6 +46,18 @@ namespace Apewer } /// 从 NTP 服务器获取 UTC 时间。 + /// + /// Worldwide: pool.ntp.org
+ /// Asia: asia.pool.ntp.org
+ /// Europe: europe.pool.ntp.org
+ /// North: America north-america.pool.ntp.org
+ /// Oceania: oceania.pool.ntp.org
+ /// South America: south-america.pool.ntp.org
+ /// Windows: time.windows.com
+ /// Windows: time.nist.gov
+ /// China: us.ntp.org.cn
+ /// China: edu.ntp.org.cn
+ ///
public static DateTime GetUtcFromNtp(string server = "pool.ntp.org", int port = 123, int timeout = 1000) { try @@ -57,7 +69,9 @@ namespace Apewer return GetUtcFromNtp(endpoint, timeout); } } - catch { } + catch (Exception ex) + { + } return ClockUtility.Zero; } @@ -89,7 +103,9 @@ namespace Apewer var utc = (new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds(milliseconds); return utc; } - catch { } + catch (Exception ex) + { + } return ClockUtility.Zero; } diff --git a/Apewer/RuntimeUtility.cs b/Apewer/RuntimeUtility.cs index 2e40033..5116277 100644 --- a/Apewer/RuntimeUtility.cs +++ b/Apewer/RuntimeUtility.cs @@ -750,32 +750,43 @@ namespace Apewer #region Assembly - /// 获取当前进程程序集的资源。 - public static byte[] GetAssemblyResource(string name) + /// 列出当前域中的程序集。 + public static Assembly[] ListLoadedAssemblies() { - var assembly = Assembly.GetExecutingAssembly(); - return GetAssemblyResource(assembly, name); + return AppDomain.CurrentDomain.GetAssemblies(); } - /// 获取指定程序集的资源。 - public static byte[] GetAssemblyResource(Assembly assembly, string name) + /// 从指定的程序集加载资源。 + /// 资源的名称。 + /// 程序集,为 NULL 值时指向 CallingAssembly。 + /// 该资源的流,发生错误时返回 NULL 值。 + /// 此方法不引发异常。 + public static Stream OpenResource(string name, Assembly assembly = null) { - var result = Constant.EmptyBytes; - if (assembly == null) return null; + var stream = null as Stream; try { - var source = assembly.GetManifestResourceStream(name); - result = StreamHelper.Read(source); - Dispose(source); + var asm = assembly ?? Assembly.GetCallingAssembly(); + stream = asm.GetManifestResourceStream(name); } - finally { } - return result; + catch { } + return null; } - /// 获取已加载的程序集。 - public static Assembly[] GetLoadedAssemblies() + /// 从程序集获取资源,读取到内存流。发生错误时返回 NULL 值,不引发异常。 + /// 资源的名称。 + /// 程序集,为 NULL 值时指向 CallingAssembly。 + /// 该资源的流,发生错误时返回 NULL 值。 + /// 此方法不引发异常。 + public static MemoryStream GetResource(string name, Assembly assembly = null) { - return AppDomain.CurrentDomain.GetAssemblies(); + var res = OpenResource(name, assembly); + if (res == null) return null; + + var memory = new MemoryStream(); + BinaryUtility.Read(res, memory); + res.Dispose(); + return memory; } #endregion diff --git a/Apewer/Source/ColumnAttribute.cs b/Apewer/Source/ColumnAttribute.cs index 6c9e04d..da82bf6 100644 --- a/Apewer/Source/ColumnAttribute.cs +++ b/Apewer/Source/ColumnAttribute.cs @@ -7,7 +7,7 @@ using System.Text; namespace Apewer.Source { - /// 数据库中的列,类型默认为 NVarChar(255),错误类型将修正为 NText。 + /// 数据库中的列,类型默认为 NVarChar(191),错误类型将修正为 NText。 [Serializable] [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public sealed class ColumnAttribute : Attribute @@ -25,14 +25,14 @@ namespace Apewer.Source /// 使用自动的列名称。当类型为 VarChar 或 NVarChar 时必须指定长度。 /// - public ColumnAttribute(ColumnType type = ColumnType.NVarChar255, int length = 0) + public ColumnAttribute(ColumnType type = ColumnType.NVarChar, int length = 191) { New(null, type, length, true); } /// 使用指定的列名称。当类型为 VarChar 或 NVarChar 时必须指定长度。 /// - public ColumnAttribute(string field, ColumnType type = ColumnType.NVarChar255, int length = 0) + public ColumnAttribute(string field, ColumnType type = ColumnType.NVarChar, int length = 191) { New(field, type, length, false); } @@ -113,6 +113,7 @@ namespace Apewer.Source _length = length; break; } + Lock(); } /// 锁定属性,阻止修改。 diff --git a/Apewer/Source/Record.cs b/Apewer/Source/Record.cs index e754bfa..dfbb189 100644 --- a/Apewer/Source/Record.cs +++ b/Apewer/Source/Record.cs @@ -11,6 +11,9 @@ namespace Apewer.Source public class Record : IRecord { + private const int DefaultLength = 191; + private const int KeyLength = 128; + [NonSerialized] private string _created = ""; @@ -26,13 +29,13 @@ namespace Apewer.Source [NonSerialized] private string _key = GenerateKey(); - /// 记录的创建时间,NVarChar 255 类型,值为执行 INSERT INTO 语句时的时间。 - [Column("_created", ColumnType.NVarChar255)] - public virtual string Created { get { return _created; } set { _created = TextModifier.Compact(value, 255); } } + /// 记录的创建时间,值为执行 INSERT INTO 语句时的时间。 + [Column("_created", ColumnType.NVarChar, DefaultLength)] + public virtual string Created { get { return _created; } set { _created = TextModifier.Compact(value, DefaultLength); } } - /// 记录的更新时间,NVarChar 255 类型,每次对此记录执行 UPDATE 时应更新此值为当前系统时间。 - [Column("_updated", ColumnType.NVarChar255)] - public virtual string Updated { get { return _updated; } set { _updated = TextModifier.Compact(value, 255); } } + /// 记录的更新时间,类型,每次对此记录执行 UPDATE 时应更新此值为当前系统时间。 + [Column("_updated", ColumnType.NVarChar, DefaultLength)] + public virtual string Updated { get { return _updated; } set { _updated = TextModifier.Compact(value, DefaultLength); } } /// 记录的标记,Int64 类型,区分记录的状态。 [Column("_flag", ColumnType.Integer)] @@ -42,9 +45,9 @@ namespace Apewer.Source [Column("_remark", ColumnType.NText)] public virtual string Remark { get { return _remark; } set { _remark = TextModifier.Compact(value); } } - /// 记录唯一键,NVarChar 128 类型,一般使用 GUID 的字符串形式。 - [Column("_key", ColumnType.NVarChar, 128)] - public virtual string Key { get { return _key; } set { _key = TextModifier.Compact(value, 128); } } + /// 记录唯一键,一般使用 GUID 的字符串形式。 + [Column("_key", ColumnType.NVarChar, KeyLength)] + public virtual string Key { get { return _key; } set { _key = TextModifier.Compact(value, KeyLength); } } /// 重置主键。 internal static void ResetKey(Record record) diff --git a/Apewer/Surface/FontInstance.cs b/Apewer/Surface/FontInstance.cs index 4ea4675..eafec2a 100644 --- a/Apewer/Surface/FontInstance.cs +++ b/Apewer/Surface/FontInstance.cs @@ -10,7 +10,7 @@ namespace Apewer.Surface { /// - public class FontInstance + internal class FontInstance { private FontFamily _fontfamily = null; diff --git a/Apewer/Surface/FormsUtility.cs b/Apewer/Surface/FormsUtility.cs index fa708bb..a701b47 100644 --- a/Apewer/Surface/FormsUtility.cs +++ b/Apewer/Surface/FormsUtility.cs @@ -1,5 +1,4 @@ -using Apewer; -using Apewer.Internals.Interop; +using Apewer.Internals.Interop; using System; using System.Collections.Generic; using System.Drawing; @@ -23,35 +22,30 @@ namespace Apewer.Surface public class FormsUtility { - private const string FontYahei = "Microsoft Yahei"; - private const string FontSimsun = "Simsun"; - - private static string _fontname = ""; - /// 线程锁。 public static object ThreadLocker = new object(); - /// 存在微软雅黑字体。 - public static bool MsyhExist +#if NETFX || NETCORE + + /// 窗体启动初始化。 + [STAThread] + public static void StartInitialization() { - get { return File.Exists("c:\\windows\\fonts\\msyh.ttc"); } + Control.CheckForIllegalCrossThreadCalls = false; + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); } - /// 获取默认字体名称。 - public static string DefaultFontName + /// 禁用跨线程调用检查。 + public static void CrossThread() { - get - { - if (!string.IsNullOrEmpty(_fontname)) return _fontname; - try - { - if (File.Exists("c:\\windows\\fonts\\msyh.ttc")) return FontYahei; - else return FontSimsun; - } - catch { return FontSimsun; } - } + Control.CheckForIllegalCrossThreadCalls = false; } +#endif + + #region 颜色。 + /// 获取所有可枚举的颜色。 public static Color[] EnumerableColor { @@ -284,7 +278,7 @@ namespace Apewer.Surface /// 前景色(基色)。 /// 颜色深度,最大值。 /// 合成后的颜色(基色)。 - public static int AlphaColor(int alpha, int fore, int back, int depth = 255) + public static int MixAlpha(int alpha, int fore, int back, int depth = 255) { int b = back, f = fore; if (b > depth) b = depth; if (b < 0) b = 0; @@ -294,81 +288,97 @@ namespace Apewer.Surface return v; } - /// 从程序集获取资源。发生错误时返回 NULL 值,不引发异常。 - public static Stream OpenResourceStream(string name, Assembly assembly = null) + /// 按 Alpha 混合不透明的颜色。 + /// 背景色。 + /// 前景色。 + /// 前景 Alpha 值。 + /// 混合后的颜色。 + public static Color MixAlpha(Color backColor, Color foreColor, int foreAlpha) { - var stream = null as Stream; - try - { - if (assembly == null) assembly = Assembly.GetCallingAssembly(); - stream = assembly.GetManifestResourceStream(name); - } - catch { } - return null; + var r = MixAlpha(backColor.R, foreColor.R, foreAlpha); + var g = MixAlpha(backColor.G, foreColor.G, foreAlpha); + var b = MixAlpha(backColor.B, foreColor.B, foreAlpha); + var a = MixAlpha(backColor.A, foreColor.A, foreAlpha); + return Color.FromArgb(a, r, g, b); } - /// 从程序集获取资源,读取到内存流。发生错误时返回 NULL 值,不引发异常。 - public static MemoryStream GetResourceStream(string name, Assembly assembly = null) - { - var stream = OpenResourceStream(name, assembly); - if (stream == null) return null; - var memory = new MemoryStream(); - BinaryUtility.Read(stream, memory); - stream.Dispose(); - memory.ResetPosition(); - return memory; - } + #endregion - /// 从程序集获取资源,读取到内存流。发生错误时返回 NULL 值,不引发异常。 - public static byte[] GetResource(string name, Assembly assembly = null) - { - var stream = OpenResourceStream(name, assembly); - if (stream == null) return null; - var bytes = BinaryUtility.Read(stream); - stream.Dispose(); - return bytes; - } + #region 屏幕。 #if NETFX || NETCORE - /// 获取默认字体。 - public static Font DefaultFont + /// 获取屏幕的截图。 + public static Bitmap[] ScreenShot() { - get { return new Font(DefaultFontName, 9); } + var list = new List(); + var all = Screen.AllScreens; + foreach (var screen in all) + { + int vw = screen.Bounds.Width; + int vh = screen.Bounds.Height; + int vd = screen.BitsPerPixel; + Bitmap b = new Bitmap(vw, vh, PixelFormat.Format32bppArgb); + Graphics g = Graphics.FromImage(b); + g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(vw, vh)); + g.Dispose(); + list.Add(b); + } + return list.ToArray(); } - /// 获取大小为 9 的默认字体。 - public static Font NewFont() + /// 获取指定屏幕的截图。 + /// 屏幕号。 + internal static Bitmap ScreenShot(int screen) { - return new Font(DefaultFontName, 9); + var a = Screen.AllScreens; + if ((a.Length > 0) && (screen >= 0) && (screen < a.Length)) + { + try + { + int w = a[screen].Bounds.Width; + int h = a[screen].Bounds.Height; + int d = a[screen].BitsPerPixel; + Bitmap b = new Bitmap(w, h, PixelFormat.Format32bppArgb); + Graphics g = Graphics.FromImage(b); + g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(w, h)); + g.Dispose(); + return b; + } + catch { } + } + return new Bitmap(0, 0, PixelFormat.Format32bppArgb); } - /// 获取指定大小的默认字体。 - public static Font NewFont(float size) + /// 获取指定屏幕的截图。 + /// 屏幕,若为 Null 则选择主屏幕。 + internal static Bitmap ScreenShot(Screen screen) { - return new Font(DefaultFontName, size); + if (screen == null) + { + try + { + int w = Screen.PrimaryScreen.Bounds.Width; + int h = Screen.PrimaryScreen.Bounds.Height; + int d = Screen.PrimaryScreen.BitsPerPixel; + Bitmap b = new Bitmap(w, h, PixelFormat.Format32bppArgb); + Graphics g = Graphics.FromImage(b); + g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(w, h)); + g.Dispose(); + return b; + } + catch { } + } + return new Bitmap(0, 0, PixelFormat.Format32bppArgb); } - /// 获取指定大小的默认字体。 - public static Font NewFont(float size, bool bold) - { - return new Font(DefaultFontName, size, bold ? FontStyle.Bold : FontStyle.Regular); - } +#endif - /// 窗体启动初始化。 - [STAThread] - public static void StartInitialization() - { - Control.CheckForIllegalCrossThreadCalls = false; - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - } + #endregion - /// 禁用跨线程调用检查。 - public static void CrossThread() - { - Control.CheckForIllegalCrossThreadCalls = false; - } + #region 窗体。 + +#if NETFX || NETCORE /// 移动窗体。 public static void MoveForm(Form form) @@ -396,85 +406,72 @@ namespace Apewer.Surface int oldGWLEx = User32.SetWindowLong(form, Constant.GWL_EXSTYLE, Constant.WS_EX_TRANSPARENT | Constant.WS_EX_LAYERED); } - /// 绘制内边框。 - /// 源图像。 - /// 边框颜色。 - public static bool PaintBorder(ref Image image, Color border) + /// 将窗体最大化,不覆盖任务栏。 + /// 窗体。 + public static void ToMaximum(Form form) { - if (image != null) + if (form != null) { - var g = Graphics.FromImage(image); - var p = new Pen(border); - - g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1); - p.Dispose(); - g.Dispose(); - return true; + var s = Screen.FromControl(form); + var r = s.WorkingArea; + if ((form.MaximumSize.Width < r.Width) || (form.MaximumSize.Height < r.Height)) + { + form.MaximumSize = r.Size; + } + form.Location = r.Location; + form.Size = r.Size; } - else return false; } - /// 绘制内边框。 - /// 源图像。 - /// 边框颜色。 - public static bool PaintBorder(ref Bitmap image, Color border) + /// 用指定图像绘制窗体,窗体与图像的大小必须一致。 + /// 要绘制的窗体。 + /// 要使用的图像。 + public static void UpdateShadow(Form form, Image image) { - if (image != null) + if ((form != null) && (image != null)) { - var g = Graphics.FromImage(image); - var p = new Pen(border); - - g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1); - p.Dispose(); - g.Dispose(); - return true; - } - else return false; - } + Bitmap vbitmap; + if ((form.Width != image.Width) || (form.Height != image.Height)) + { + vbitmap = new Bitmap(image.GetThumbnailImage(form.Width, form.Height, null, IntPtr.Zero)); + } + else + { + vbitmap = new Bitmap(image); + } - /// 绘制内边框。 - /// 源图像。 - /// 边框颜色。 - /// 背景颜色。 - public static bool PaintBorder(ref Image image, Color border, Color wall) - { - if (image != null) - { - var g = Graphics.FromImage(image); - var p = new Pen(border); + var screendc = User32.GetDC(IntPtr.Zero); + var location = new Internals.Interop.Point(form.Left, form.Top); + var size = new Internals.Interop.Size(form.Width, form.Height); + var compatibledc = Gdi32.CreateCompatibleDC(screendc); + var handle = vbitmap.GetHbitmap(Color.FromArgb(0)); + var oldbitmap = Gdi32.SelectObject(compatibledc, handle); + var srcloc = new Internals.Interop.Point(0, 0); + var blendfunction = new BlendFunction(); - g.Clear(wall); + blendfunction.blendop = Constant.AC_SRC_OVER; + blendfunction.sourceconstantalpha = byte.Parse("255"); + blendfunction.alphaformat = Constant.AC_SRC_ALPHA; + blendfunction.blendflags = 0; + User32.UpdateLayeredWindow(form.Handle, screendc, ref location, ref size, compatibledc, ref srcloc, 0, ref blendfunction, Constant.ULW_ALPHA); - g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1); - p.Dispose(); - g.Dispose(); - return true; + if (handle != IntPtr.Zero) + { + Gdi32.SelectObject(compatibledc, oldbitmap); + Gdi32.DeleteObject(handle); + } + User32.ReleaseDC(IntPtr.Zero, screendc); + Gdi32.DeleteDC(compatibledc); } - else return false; } - /// 建立带有圆角样式的路径。 - /// 建立矩形路径的区域。 - /// 圆角的大小。 - /// 建立的路径。 - public static GraphicsPath CreatePath(Rectangle rect, int radius = 0) + /// 为窗体启用阴影。 + /// 要启用阴影的窗体。 + public static void EnableShadow(Form form) { - GraphicsPath path = new GraphicsPath(); - int r = (radius < 0) ? 0 : radius; - switch (r) - { - case 0: - path.AddRectangle(rect); - break; - default: - path.AddArc(rect.X, rect.Y, r, r, 180, 90); - path.AddArc(rect.Right - r - 1, rect.Y, r, r, 270, 90); - path.AddArc(rect.Right - r - 1, rect.Bottom - r - 1, r, r, 0, 90); - path.AddArc(rect.X, rect.Bottom - r - 1, r, r, 90, 90); - break; - } - path.CloseFigure(); - return path; + if (form == null) return; + int vformclass = User32.GetClassLong(form.Handle, Constant.GCL_STYLE); + User32.SetClassLong(form.Handle, Constant.GCL_STYLE, vformclass | Constant.CS_DROPSHADOW); } /// 恢复任务栏中窗体标题的右键菜单。 @@ -489,6 +486,14 @@ namespace Apewer.Surface } } +#endif + + #endregion + + #region 控件。 + +#if NETFX || NETCORE + /// 在主界面中移动控件,由目标控件取代当前控件,形成切换控件的动画。 /// 当前显示的控件。 /// 将要显示的目标控件。 @@ -556,136 +561,138 @@ namespace Apewer.Surface current.Visible = false; } - /// 将窗体最大化,不覆盖任务栏。 - /// 窗体。 - public static void ToMaximum(Form form) + /// + public static void Invoke(Control control, Action action, bool async = false) { - if (form != null) + if (control == null || action == null) return; + // control.Invoke(action); + if (async) { - var s = Screen.FromControl(form); - var r = s.WorkingArea; - if ((form.MaximumSize.Width < r.Width) || (form.MaximumSize.Height < r.Height)) + control.BeginInvoke(new Action(delegate () { - form.MaximumSize = r.Size; - } - form.Location = r.Location; - form.Size = r.Size; + action.Invoke(); + })); + } + else + { + control.Invoke(new Action(delegate () + { + action.Invoke(); + })); } } - /// 用指定图像绘制窗体,窗体与图像的大小必须一致。 - /// 要绘制的窗体。 - /// 要使用的图像。 - public static void UpdateShadow(Form form, Image image) + /// + public static void BeginInvoke(Control control, Action action) { - if ((form != null) && (image != null)) - { - Bitmap vbitmap; - if ((form.Width != image.Width) || (form.Height != image.Height)) - { - vbitmap = new Bitmap(image.GetThumbnailImage(form.Width, form.Height, null, IntPtr.Zero)); - } - else - { - vbitmap = new Bitmap(image); - } + if (control == null || action == null) return; - var screendc = User32.GetDC(IntPtr.Zero); - var location = new Internals.Interop.Point(form.Left, form.Top); - var size = new Internals.Interop.Size(form.Width, form.Height); - var compatibledc = Gdi32.CreateCompatibleDC(screendc); - var handle = vbitmap.GetHbitmap(Color.FromArgb(0)); - var oldbitmap = Gdi32.SelectObject(compatibledc, handle); - var srcloc = new Internals.Interop.Point(0, 0); - var blendfunction = new BlendFunction(); + control.BeginInvoke(new Action(delegate () + { + action.Invoke(); + })); + } - blendfunction.blendop = Constant.AC_SRC_OVER; - blendfunction.sourceconstantalpha = byte.Parse("255"); - blendfunction.alphaformat = Constant.AC_SRC_ALPHA; - blendfunction.blendflags = 0; - User32.UpdateLayeredWindow(form.Handle, screendc, ref location, ref size, compatibledc, ref srcloc, 0, ref blendfunction, Constant.ULW_ALPHA); + /// 设置窗体置顶。 + public static void SetTopMost(IntPtr form, bool value = true) + { + if (form == null || form == IntPtr.Zero) return; + User32.SetWindowPos(form, new IntPtr(value ? -1 : -2), 0, 0, 0, 0, 3); + } - if (handle != IntPtr.Zero) - { - Gdi32.SelectObject(compatibledc, oldbitmap); - Gdi32.DeleteObject(handle); - } - User32.ReleaseDC(IntPtr.Zero, screendc); - Gdi32.DeleteDC(compatibledc); - } + /// 设置窗体置顶。 + public static void SetTopMost(Form form, bool value = true) + { + if (form != null) SetTopMost(form.Handle, value); } - /// 为窗体启用阴影。 - /// 要启用阴影的窗体。 - public static void EnableShadow(Form form) +#endif + + #endregion + + #region 绘图。 + +#if NETFX || NETCORE + + /// 绘制内边框。 + /// 源图像。 + /// 边框颜色。 + public static bool PaintBorder(ref Image image, Color border) { - if (form == null) return; - int vformclass = User32.GetClassLong(form.Handle, Constant.GCL_STYLE); - User32.SetClassLong(form.Handle, Constant.GCL_STYLE, vformclass | Constant.CS_DROPSHADOW); + if (image != null) + { + var g = Graphics.FromImage(image); + var p = new Pen(border); + + g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1); + p.Dispose(); + g.Dispose(); + return true; + } + else return false; } - /// 获取屏幕的截图。 - public static Bitmap[] ScreenShot() + /// 绘制内边框。 + /// 源图像。 + /// 边框颜色。 + public static bool PaintBorder(ref Bitmap image, Color border) { - var list = new List(); - var all = Screen.AllScreens; - foreach (var screen in all) + if (image != null) { - int vw = screen.Bounds.Width; - int vh = screen.Bounds.Height; - int vd = screen.BitsPerPixel; - Bitmap b = new Bitmap(vw, vh, PixelFormat.Format32bppArgb); - Graphics g = Graphics.FromImage(b); - g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(vw, vh)); + var g = Graphics.FromImage(image); + var p = new Pen(border); + + g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1); + p.Dispose(); g.Dispose(); - list.Add(b); + return true; } - return list.ToArray(); + else return false; } - /// 获取指定屏幕的截图。 - /// 屏幕号。 - internal static Bitmap ScreenShot(int screen) + /// 绘制内边框。 + /// 源图像。 + /// 边框颜色。 + /// 背景颜色。 + public static bool PaintBorder(ref Image image, Color border, Color wall) { - var a = Screen.AllScreens; - if ((a.Length > 0) && (screen >= 0) && (screen < a.Length)) + if (image != null) { - try - { - int w = a[screen].Bounds.Width; - int h = a[screen].Bounds.Height; - int d = a[screen].BitsPerPixel; - Bitmap b = new Bitmap(w, h, PixelFormat.Format32bppArgb); - Graphics g = Graphics.FromImage(b); - g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(w, h)); - g.Dispose(); - return b; - } - catch { } + var g = Graphics.FromImage(image); + var p = new Pen(border); + + g.Clear(wall); + + g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1); + p.Dispose(); + g.Dispose(); + return true; } - return new Bitmap(0, 0, PixelFormat.Format32bppArgb); + else return false; } - /// 获取指定屏幕的截图。 - /// 屏幕,若为 Null 则选择主屏幕。 - internal static Bitmap ScreenShot(Screen screen) + /// 建立带有圆角样式的路径。 + /// 建立矩形路径的区域。 + /// 圆角的大小。 + /// 建立的路径。 + public static GraphicsPath CreatePath(Rectangle rect, int radius = 0) { - if (screen == null) + GraphicsPath path = new GraphicsPath(); + int r = (radius < 0) ? 0 : radius; + switch (r) { - try - { - int w = Screen.PrimaryScreen.Bounds.Width; - int h = Screen.PrimaryScreen.Bounds.Height; - int d = Screen.PrimaryScreen.BitsPerPixel; - Bitmap b = new Bitmap(w, h, PixelFormat.Format32bppArgb); - Graphics g = Graphics.FromImage(b); - g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(w, h)); - g.Dispose(); - return b; - } - catch { } + case 0: + path.AddRectangle(rect); + break; + default: + path.AddArc(rect.X, rect.Y, r, r, 180, 90); + path.AddArc(rect.Right - r - 1, rect.Y, r, r, 270, 90); + path.AddArc(rect.Right - r - 1, rect.Bottom - r - 1, r, r, 0, 90); + path.AddArc(rect.X, rect.Bottom - r - 1, r, r, 90, 90); + break; } - return new Bitmap(0, 0, PixelFormat.Format32bppArgb); + path.CloseFigure(); + return path; } /// @@ -731,61 +738,6 @@ namespace Apewer.Surface return path; } - /// 从文件加载字体,并获取字体。 - public static FontFamily LoadFont(string path) - { - if (!File.Exists(path)) return null; - var vpfc = new PrivateFontCollection(); - vpfc.AddFontFile(path); - var vff = vpfc.Families[0]; - return vff; - } - - /// - public static void Invoke(Control control, Action action, bool async = false) - { - if (control == null || action == null) return; - // control.Invoke(action); - if (async) - { - control.BeginInvoke(new Action(delegate () - { - action.Invoke(); - })); - } - else - { - control.Invoke(new Action(delegate () - { - action.Invoke(); - })); - } - } - - /// - public static void BeginInvoke(Control control, Action action) - { - if (control == null || action == null) return; - - control.BeginInvoke(new Action(delegate () - { - action.Invoke(); - })); - } - - /// 设置窗体置顶。 - public static void SetTopMost(IntPtr form, bool value = true) - { - if (form == null || form == IntPtr.Zero) return; - User32.SetWindowPos(form, new IntPtr(value ? -1 : -2), 0, 0, 0, 0, 3); - } - - /// 设置窗体置顶。 - public static void SetTopMost(Form form, bool value = true) - { - if (form != null) SetTopMost(form.Handle, value); - } - /// 获取指定文件中的图标总数。 public static int GetIconsCount(string path) { @@ -830,6 +782,216 @@ namespace Apewer.Surface #endif + #endregion + + #region 字体。 + + private const string FontYahei = "Microsoft Yahei"; + private const string FontSimsun = "Simsun"; + + private static string _fontname = ""; + + /// 存在微软雅黑字体。 + public static bool MsyhExist + { + get { return File.Exists("c:\\windows\\fonts\\msyh.ttc"); } + } + + /// 获取默认字体名称。 + public static string DefaultFontName + { + get + { + if (!string.IsNullOrEmpty(_fontname)) return _fontname; + try + { + if (File.Exists("c:\\windows\\fonts\\msyh.ttc")) return FontYahei; + else return FontSimsun; + } + catch { return FontSimsun; } + } + } + +#if NETFX || NETCORE + + /// 获取默认字体。 + public static Font DefaultFont + { + get { return new Font(DefaultFontName, 9); } + } + + /// 获取大小为 9 的默认字体。 + public static Font NewFont() + { + return new Font(DefaultFontName, 9); + } + + /// 获取指定大小的默认字体。 + public static Font NewFont(float size) + { + return new Font(DefaultFontName, size); + } + + /// 获取指定大小的默认字体。 + public static Font NewFont(float size, bool bold) + { + return new Font(DefaultFontName, size, bold ? FontStyle.Bold : FontStyle.Regular); + } + + /// 从文件加载字体,并获取指定字体。 + /// 文件路径。 + /// 文件中的 Font Family 索引,默认取第一个(索引 0)。 + /// 已存在的 Font Family,如果指定的索引处不存在 Font Family,则返回 NULL 值。 + public static FontFamily LoadFont(string path, int index = 0) + { + if (index < 0) return null; + if (string.IsNullOrEmpty(path)) return null; + if (!File.Exists(path)) return null; + + try + { + var pfc = new PrivateFontCollection(); + pfc.AddFontFile(path); + var fs = pfc.Families; + if (fs.Length > 0 && index < fs.Length) return fs[index]; + } + catch { } + return null; + } + +#if NET40 || NET461 + + /// + public static List ListFileFont(string path) + { + try + { + var collection = System.Windows.Media.Fonts.GetFontFamilies(path); + var list = new List(collection.Count); + foreach (var item in collection) list.Add(item); + return list; + } + catch { } + return new List(); + } + + /// + public static List ListSystemFont() + { + var collection = System.Windows.Media.Fonts.SystemFontFamilies; + var list = new List(collection.Count); + foreach (var item in collection) list.Add(item); + return list; + } + + /// 枚举指定字体中的所有字符。 + public static List EnumerateFontChars(IEnumerable typefaces) + { + var chars = new List(); + if (typefaces != null) + { + foreach (var typeface in typefaces) + { + var subs = EnumerateFontChars(typeface); + if (subs != null) chars.AddRange(subs); + } + } + return chars; + } + + /// 枚举指定字体中的所有字符。 + public static List EnumerateFontChars(System.Windows.Media.Typeface typeface) + { + System.Windows.Media.GlyphTypeface glyph; + var tried = typeface.TryGetGlyphTypeface(out glyph); + if (glyph == null) return null; + + var map = glyph.CharacterToGlyphMap; + var keys = map.Keys; + var chars = new List(keys.Count); + for (int i = 0; i < keys.Count; i++) + { + var index = System.Linq.Enumerable.ElementAt(keys, i); + try + { + var c = Convert.ToChar(index); + chars.Add(c.ToString()); + } + catch { } + } + return chars; + } + +#endif + + /// 获取已安装的字体。 + public static List ListInstalledFonts() + { + var list = new List(); + int ret = 0; // Win32 API 返回值,非零值均为异常。 + + // 初始化 FontCollection。 + var collection = new Internals.FontCollection(); + ret = GdiPlus.GdipNewInstalledFontCollection(out collection.NativePointer); + if (ret != 0) return list; + + // 获取字体总数。 + int found1 = 0; + ret = GdiPlus.GdipGetFontCollectionFamilyCount(new HandleRef(collection, collection.NativePointer), out found1); + if (ret != 0) return list; + + // 获取字体指针。 + var ptrs = new IntPtr[found1]; + int found2 = 0; + ret = GdiPlus.GdipGetFontCollectionFamilyList(new HandleRef(collection, collection.NativePointer), found1, ptrs, out found2); + if (ret != 0) return list; + + // 获取字体列表。 + list.Capacity = found2; + for (int i = 0; i < found2; i++) + { + IntPtr cloned; + GdiPlus.GdipCloneFontFamily(new HandleRef(null, ptrs[i]), out cloned); + try + { + var flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance; + var args = new object[] { cloned }; + var instance = Activator.CreateInstance(typeof(FontFamily), flags, null, args, null, null); + var item = instance as FontFamily; + if (item != null) list.Add(item); + } + catch { } + } + + list.Capacity = list.Count; + return list; + } + + private static bool GlyphExists(char c, Font font) + { + using (var dummy = Graphics.FromImage(new Bitmap(1, 1))) + { + IntPtr hdc = dummy.GetHdc(); + var pgi = new ushort[1]; + try + { + IntPtr hfont = font.ToHfont(); + Gdi32.SelectObject(hdc, hfont); + string str = c.ToString(); + Gdi32.GetGlyphIndices(hdc, str, str.Length, pgi, Constant.GGI_MARK_NONEXISTING_GLYPHS); + } + catch { } + dummy.ReleaseHdc(hdc); + + // 0xFFFF 表示字形不存在。 + return (pgi[0] != 0xffff); + } + } + +#endif + + #endregion + } } diff --git a/Apewer/Web/ApiProcessor.cs b/Apewer/Web/ApiProcessor.cs index bcbef68..89a51c6 100644 --- a/Apewer/Web/ApiProcessor.cs +++ b/Apewer/Web/ApiProcessor.cs @@ -452,15 +452,15 @@ namespace Apewer.Web var ps = new List(); foreach (var kvp in cookies) { - var k = kvp.Key; - var v = kvp.Value; + var k = kvp.Key ?? ""; + var v = kvp.Value ?? ""; if (k.IsEmpty()) continue; - ps.Add(TextUtility.Merge(k, "="), v); + ps.Add(TextUtility.Merge(k, "=", v)); } if (ps.Count < 1) return null; - var value = TextUtility.Merge("; ", ps); + var value = TextUtility.Join("; ", ps); return AddHeader("Set-Cookie", value); } diff --git a/Apewer/_ChangeLog.md b/Apewer/_ChangeLog.md index 6f12933..183a601 100644 --- a/Apewer/_ChangeLog.md +++ b/Apewer/_ChangeLog.md @@ -1,6 +1,12 @@  ### 最新提交 +### 6.3.2 +- RuntimeUtility:调整了 Assembly 的方法名称; +- Surface:迁移获取字形的方法到 FormsUtility,不再提供 FontInstance 类; +- Source:调整 ColumnAttribute 和 Record 的默认字段长度从 255 到 191; +- Web:修正无法设置 Cookie 的问题。 + ### 6.3.1 - Source:修正了多次获取 Access 密码会报错的问题; - Web:对 ApiResponse 中增加 Indented,支持对单个 API 的响应强制缩进排版。