diff --git a/Apewer.Windows/Apewer.Windows.csproj b/Apewer.Windows/Apewer.Windows.csproj
index 02d7562..bd46bb5 100644
--- a/Apewer.Windows/Apewer.Windows.csproj
+++ b/Apewer.Windows/Apewer.Windows.csproj
@@ -1,64 +1,66 @@
-
+
-
- CS0108;CS0612
- net461;net40;net20;netcoreapp3.1
-
+
+ CS0108;CS0612
+ net461;net40;net20;netcoreapp3.1
+
-
-
- 实现 Windows 程序功能。
-
+
+
+ 实现 Windows 程序功能。
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ DRAWING;$(DefineConstants);$(AdditionalConstants)
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Apewer.Windows/WindowsUtility.cs b/Apewer.Windows/WindowsUtility.cs
index e0410b2..270d19d 100644
--- a/Apewer.Windows/WindowsUtility.cs
+++ b/Apewer.Windows/WindowsUtility.cs
@@ -1039,26 +1039,30 @@ namespace Apewer
#if NETFX
- /// 创建快捷方式。
- /// 快捷方式路径。
+ /// 创建快捷方式,生成 .lnk 文件。
+ /// 快捷方式路径,以 .lnk 结尾。
/// 快捷方式图标。可使用 c:\source.exe,0 格式。
/// 快捷方式说明。
/// 源路径。
/// 源参数。
/// 工作目录。
+ ///
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);
+ if (linkPath.IsEmpty()) throw new ArgumentNullException(nameof(linkPath));
+ if (sourcePath.IsEmpty()) throw new ArgumentNullException(nameof(sourcePath));
+
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.Arguments = sourceArgs ?? "";
+ shortcut.Description = linkDescription ?? "";
shortcut.WorkingDirectory = directory ?? "";
- shortcut.IconLocation = linkIcon;
+ shortcut.IconLocation = linkIcon ?? sourcePath;
shortcut.WindowStyle = 1;
// shortcut.WorkingDirectory = "";
// shortcut.RelativePath = "";
@@ -1067,6 +1071,36 @@ namespace Apewer
#endif
+ /// 创建 URL 快捷方式,生成 .url 文件。
+ /// 快捷方式路径,以 .url 结尾。
+ /// URL。
+ /// 快捷方式图标。
+ /// 快捷方式图标索引。
+ ///
+ public static void CreateUrlShortCut(string linkPath, string url, string iconFilePath = null, int iconIndex = 0)
+ {
+ if (linkPath.IsEmpty()) throw new ArgumentNullException(nameof(linkPath));
+ if (url.IsEmpty()) throw new ArgumentNullException(nameof(url));
+
+ var lines = new List();
+ lines.Add("[{000214A0-0000-0000-C000-000000000046}]");
+ lines.Add("Prop3=19,11");
+ lines.Add("");
+ lines.Add("[InternetShortcut]");
+ lines.Add("IDList=");
+ lines.Add($"URL={url}");
+ if (StorageUtility.FileExists(iconFilePath))
+ {
+ lines.Add($"IconIndex={iconIndex}");
+ lines.Add("HotKey=0");
+ lines.Add($"IconFile={iconFilePath}");
+ }
+
+ var text = lines.Join("\r\n") + "\r\n";
+ var bytes = text.Bytes(Encoding.Default);
+ StorageUtility.WriteFile(linkPath, bytes);
+ }
+
#endregion
}
diff --git a/Apewer/Apewer.csproj b/Apewer/Apewer.csproj
index 8f32c8d..77ca79c 100644
--- a/Apewer/Apewer.csproj
+++ b/Apewer/Apewer.csproj
@@ -1,53 +1,53 @@
-
-
-
- true
- 实现通用的实用功能。
- netstandard2.0;netcoreapp3.1;net461;net40;net20
-
-
-
-
- NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)
-
-
-
-
- NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)
-
-
-
-
- NETFX;NET20;$(DefineConstants);$(AdditionalConstants)
-
-
-
-
-
-
-
-
- NETFX;NET40;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)
-
-
-
-
-
-
-
-
- NETFX;NET461;NET45;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)
-
-
-
-
-
-
-
-
- HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)
-
+
+
+
+ true
+ 实现通用的实用功能。
+ netstandard2.0;netcoreapp3.1;net461;net40;net20
+
+
+
+
+ NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)
+
+
+
+
+ NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)
+
+
+
+
+ NETFX;NET20;DRAWING;$(DefineConstants);$(AdditionalConstants)
+
+
+
+
+
+
+
+
+ NETFX;NET40;DRAWING;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)
+
+
+
+
+
+
+
+
+ NETFX;NET461;NET45;DRAWING;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)
+
+
+
+
+
+
+
+
+ HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)
+
diff --git a/Apewer/BytesUtility.cs b/Apewer/BytesUtility.cs
index 20b682c..68371d0 100644
--- a/Apewer/BytesUtility.cs
+++ b/Apewer/BytesUtility.cs
@@ -271,7 +271,7 @@ namespace Apewer
/// 转换字节数组为文本,默认使用 UTF-8 代码页。
public static string ToText(byte[] bytes, Encoding encoding = null)
{
- if (bytes.Length < 1) return Constant.EmptyString;
+ if (bytes == null || bytes.Length < 1) return Constant.EmptyString;
try { return (encoding ?? Encoding.UTF8).GetString(bytes); }
catch { return Constant.EmptyString; }
}
@@ -464,26 +464,23 @@ namespace Apewer
{
if (files == null) return null;
- var output = new MemoryStream();
-
- var input = null as Stream;
- var ex = ToZip(files.Keys, output, (name) =>
+ using (var output = new MemoryStream())
{
- RuntimeUtility.Dispose(input);
- if (name.IsEmpty()) return null;
+ var ex = ToZip(files.Keys, output, (name) =>
+ {
+ if (name.IsEmpty()) return null;
- var bytes = files[name];
- if (bytes == null || bytes.LongLength < 1L) return null;
+ var bytes = files[name];
+ if (bytes == null || bytes.LongLength < 1L) return null;
- input = new MemoryStream();
- Write(input, bytes);
- return input;
- }, null, true);
- RuntimeUtility.Dispose(input);
+ var input = new MemoryStream();
+ Write(input, bytes);
+ input.Position = 0;
+ return input;
+ }, null, true);
- var result = output.ToArray();
- RuntimeUtility.Dispose(result);
- return result;
+ return output.ToArray();
+ }
}
/// 解压 ZIP 文件。
@@ -997,7 +994,7 @@ namespace Apewer
///
public static byte[] AesDecrypt(byte[] cipher, byte[] key, CipherMode cipherMode = CipherMode.ECB, PaddingMode paddingMode = PaddingMode.PKCS7)
{
- return UseAes(cipher, key, null, cipherMode, paddingMode, (rijndael) => rijndael.CreateEncryptor(rijndael.Key, rijndael.IV));
+ return UseAes(cipher, key, null, cipherMode, paddingMode, (rijndael) => rijndael.CreateDecryptor(rijndael.Key, rijndael.IV));
}
/// 执行 AES 128/192/256 解密。
@@ -1012,7 +1009,7 @@ namespace Apewer
///
public static byte[] AesDecrypt(byte[] cipher, byte[] key, byte[] iv, CipherMode cipherMode = CipherMode.ECB, PaddingMode paddingMode = PaddingMode.PKCS7)
{
- return UseAes(cipher, key, iv, cipherMode, paddingMode, (rijndael) => rijndael.CreateEncryptor(rijndael.Key, rijndael.IV));
+ return UseAes(cipher, key, iv, cipherMode, paddingMode, (rijndael) => rijndael.CreateDecryptor(rijndael.Key, rijndael.IV));
}
#endregion
diff --git a/Apewer/CollectionUtility.cs b/Apewer/CollectionUtility.cs
index 51997a9..e809a2e 100644
--- a/Apewer/CollectionUtility.cs
+++ b/Apewer/CollectionUtility.cs
@@ -1,4 +1,5 @@
-using System;
+using Newtonsoft.Json.Linq;
+using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -126,6 +127,12 @@ namespace Apewer
}
}
+ /// 检查当前元素是否存在于集合。
+ public static bool In(this T item, IEnumerable collection) => Contains(collection, item);
+
+ /// 检查当前元素是否存在于集合。
+ public static bool In(this T item, params T[] collection) => Contains(collection, item);
+
#endregion
#region 类型转换
@@ -474,21 +481,71 @@ namespace Apewer
#region 排序
/// 对列表中的元素排序。
- public static List Sort(List list, Func comparison)
+ /// 返回排序的数组,用于链式写法。
+ ///
+ public static List Sort(this List list, params Comparison[] comparisons)
{
- if (list == null) return null;
- if (comparison == null) return list;
- list.Sort(new Comparison(comparison));
+ if (list == null) throw new ArgumentNullException(nameof(list));
+ if (comparisons == null) throw new ArgumentNullException(nameof(comparisons));
+
+ var count = comparisons.Length;
+ if (count < 1) return list;
+ for (var i = 0; i < count; i++)
+ {
+ if (comparisons[i] == null) throw new ArgumentNullException(nameof(comparisons), $"Comparisons[{i}] is null.");
+ }
+
+ list.Sort((a, b) =>
+ {
+ for (var i = 0; i < count; i++)
+ {
+ var compare = comparisons[i].Invoke(a, b);
+ if (compare != 0) return compare;
+ }
+
+ return Comparer.Default.Compare(a, b);
+ });
+
return list;
}
/// 对数组排序。
- ///
- public static T[] Sort(T[] array, Func comparison)
+ /// 返回排序的数组,用于链式写法。
+ ///
+ ///
+ public static T[] Sort(this T[] array)
{
- if (array == null) return array;
- if (comparison == null) return array;
- System.Array.Sort(array, new Comparison(comparison));
+ System.Array.Sort(array);
+ return array;
+ }
+
+ /// 对数组排序。
+ /// 返回排序的数组,用于链式写法。
+ ///
+ ///
+ public static T[] Sort(this T[] array, params Comparison[] comparisons)
+ {
+ if (array == null) throw new ArgumentNullException(nameof(array));
+ if (comparisons == null) throw new ArgumentNullException(nameof(comparisons));
+
+ var count = comparisons.Length;
+ if (count < 1) return array;
+ for (var i = 0; i < count; i++)
+ {
+ if (comparisons[i] == null) throw new ArgumentNullException(nameof(comparisons), $"Comparisons[{i}] is null.");
+ }
+
+ System.Array.Sort(array, (a, b) =>
+ {
+ for (var i = 0; i < count; i++)
+ {
+ var compare = comparisons[i].Invoke(a, b);
+ if (compare != 0) return compare;
+ }
+
+ return Comparer.Default.Compare(a, b);
+ });
+
return array;
}
@@ -655,7 +712,7 @@ namespace Apewer
/// 根据条件筛选,将符合条件的元素组成新数组。
public static T[] FindAll(this IEnumerable collection, Predicate match)
{
- if (collection == null) new ArgumentNullException(nameof(collection));
+ if (collection == null) throw new ArgumentNullException(nameof(collection));
if (match == null) throw new ArgumentNullException(nameof(match));
if (collection is T[] array)
@@ -765,7 +822,7 @@ namespace Apewer
if (capacity == count)
{
capacity += 1024;
- list.Capacity += capacity;
+ list.Capacity = capacity;
}
list.Add(selector.Invoke(item, count));
count += 1;
@@ -999,7 +1056,7 @@ namespace Apewer
// 生成新数组
var result = new T[array.Length];
for (var i = 0; i < result.Length; i++) result[i] = array[i];
- result[index] = value;
+ result[offset] = value;
return result;
}
diff --git a/Apewer/DrawingUtility.cs b/Apewer/DrawingUtility.cs
new file mode 100644
index 0000000..79d6b99
--- /dev/null
+++ b/Apewer/DrawingUtility.cs
@@ -0,0 +1,123 @@
+#if DRAWING
+
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System.IO;
+
+namespace Apewer
+{
+
+ /// 绘图。
+ public static class DrawingUtility
+ {
+
+ /// 优化 Graphics 对象的属性,提升绘图质量。
+ public static Graphics Optimize(this Graphics graphics)
+ {
+ if (graphics != null)
+ {
+ graphics.CompositingMode = CompositingMode.SourceOver;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+ graphics.SmoothingMode = SmoothingMode.AntiAlias;
+ }
+ return graphics;
+ }
+
+ /// 保存图像为文件。
+ ///
+ public static byte[] Save(this Image image, ImageFormat format)
+ {
+ if (image == null) throw new ArgumentNullException(nameof(image));
+ if (format == null) throw new ArgumentNullException(nameof(format));
+
+ using (var memory = new MemoryStream())
+ {
+ image.Save(memory, format);
+ return memory.ToArray();
+ }
+ }
+
+ /// 保存为 JPEG 文件。
+ /// Image 实例。
+ /// JPEG 质量,0 为最低质量,100 为最高质量。
+ ///
+ ///
+ ///
+ public static byte[] SaveAsJpeg(this Image image, int quality = 100)
+ {
+ if (image == null) throw new ArgumentNullException(nameof(image));
+ if (quality < 0 || quality > 100) throw new ArgumentOutOfRangeException(nameof(quality));
+
+ var codec = ImageCodecInfo.GetImageDecoders().Find(x => x.FormatID == ImageFormat.Jpeg.Guid);
+ if (codec == null) throw new System.Runtime.InteropServices.ExternalException($"系统中不存在 JPEG 编码器。");
+
+ var parameters = new EncoderParameters(1);
+ parameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
+
+ using (var memory = new MemoryStream())
+ {
+ image.Save(memory, codec, parameters);
+ return memory.ToArray();
+ }
+ }
+
+ /// 缩放图像,生成新图像。
+ /// 原始图像。
+ /// 新图像的大小。
+ /// 填充新图像背景色。
+ ///
+ ///
+ public static Bitmap Scale(this Image image, Size size, Color? backgroundColor = null) => Scale(image, size.Width, size.Height, backgroundColor);
+
+ /// 缩放图像,生成新图像。
+ /// 原始图像。
+ /// 新图像的宽度。
+ /// 新图像的高度。
+ /// 填充新图像背景色。
+ ///
+ ///
+ static Bitmap Scale(this Image image, int width, int height, Color? backgroundColor = null)
+ {
+ if (image == null) throw new ArgumentNullException(nameof(image));
+ if (width < 1) throw new ArgumentOutOfRangeException(nameof(width));
+ if (height < 1) throw new ArgumentOutOfRangeException(nameof(height));
+
+ // 检查原始图像是否为透明格式
+ var rawFormat = image.RawFormat;
+ var isTransparentFormat = rawFormat.Equals(ImageFormat.Png) || rawFormat.Equals(ImageFormat.Gif);
+ var pixelFormat = isTransparentFormat ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb;
+
+ var bitmap = new Bitmap(width, height, pixelFormat);
+ try
+ {
+ using (var graphic = Graphics.FromImage(bitmap))
+ {
+ graphic.CompositingMode = CompositingMode.SourceOver;
+ graphic.CompositingQuality = CompositingQuality.HighQuality;
+ graphic.SmoothingMode = SmoothingMode.AntiAlias;
+
+ // 填充背景色
+ if (isTransparentFormat)
+ {
+ if (backgroundColor != null && backgroundColor.HasValue) graphic.Clear(backgroundColor.Value);
+ }
+
+ // 绘制新图像
+ graphic.DrawImage(image, 0, 0, width, height);
+ }
+ return bitmap;
+ }
+ catch
+ {
+ bitmap.Dispose();
+ throw;
+ }
+ }
+
+ }
+
+}
+
+#endif
diff --git a/Apewer/Logger.cs b/Apewer/Logger.cs
index 6ab5467..4964265 100644
--- a/Apewer/Logger.cs
+++ b/Apewer/Logger.cs
@@ -365,7 +365,7 @@ namespace Apewer
if (bytes.Length > 0)
{
var gzipData = BytesUtility.ToGzip(bytes);
- if (gzipData != null || gzipData.Length > 0)
+ if (gzipData != null && gzipData.Length > 0)
{
var gzipPath = path + ".gzip";
StorageUtility.WriteFile(gzipPath, gzipData);
diff --git a/Apewer/NumberUtility.cs b/Apewer/NumberUtility.cs
index 52b6fa2..d6706a9 100644
--- a/Apewer/NumberUtility.cs
+++ b/Apewer/NumberUtility.cs
@@ -428,7 +428,6 @@ namespace Apewer
foreach (var value in values)
{
up += (value - avg) * (value - avg);
- count++;
}
}
diff --git a/Apewer/Source/Execute.cs b/Apewer/Source/Execute.cs
index 80df06a..c5cfa78 100644
--- a/Apewer/Source/Execute.cs
+++ b/Apewer/Source/Execute.cs
@@ -24,7 +24,7 @@ namespace Apewer.Source
/// 创建实例。
public Execute(bool success, string message)
{
- _success = false;
+ _success = success;
_message = message;
}
diff --git a/Apewer/Source/Query.cs b/Apewer/Source/Query.cs
index d1fc953..44e1d7e 100644
--- a/Apewer/Source/Query.cs
+++ b/Apewer/Source/Query.cs
@@ -22,7 +22,7 @@ namespace Apewer.Source
/// 创建实例,默认状态为失败。
public Query(bool success = false, string message = null)
{
- _success = false;
+ _success = success;
_message = message;
}
diff --git a/Apewer/Source/SourceUtility.cs b/Apewer/Source/SourceUtility.cs
index d5a7834..c0ae115 100644
--- a/Apewer/Source/SourceUtility.cs
+++ b/Apewer/Source/SourceUtility.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Data;
using System.Reflection;
+using System.Runtime.InteropServices.ComTypes;
using System.Text;
namespace Apewer.Source
@@ -598,7 +599,6 @@ namespace Apewer.Source
}
}
-
/// 查询。
/// 数据库连接。
/// SQL 语句。
@@ -629,6 +629,353 @@ namespace Apewer.Source
}
}
+#if !NET20
+
+ /// 执行查询,将结果输出为元组数组。
+ /// 元组中的值类型。
+ /// 数据库连接。
+ /// SQL 语句。
+ /// SQL 参数。
+ /// 获取第一个值的回调函数。
+ /// 由元组组成的数组。
+ ///
+ ///
+ public static Tuple[] Query(this IDbAdo dbClient, string sql, object parameters, Func