Browse Source

Apewer-6.3.3:恢复 .NET Standard 2.0 的目标框架。

dev
Elivo 4 years ago
parent
commit
32ee38a7b0
  1. 45
      Apewer.Run/Apewer.Run.csproj
  2. 10
      Apewer/Apewer.csproj
  3. 3
      Apewer/BinaryUtility.cs
  4. 81
      Apewer/ChinaUtility.cs
  5. 2
      Apewer/Externals/Newtonsoft.Json-11.0.1/Serialization/JsonPropertyCollection.cs
  6. 11
      Apewer/Internals/Interop/AdvApi32.cs
  7. 107
      Apewer/Internals/Interop/Constant.cs
  8. 24
      Apewer/Internals/Interop/DWM_BLURBEHIND.cs
  9. 27
      Apewer/Internals/Interop/DWM_THUMBNAIL_PROPERTIES.cs
  10. 44
      Apewer/Internals/Interop/DwmApi.cs
  11. 18
      Apewer/Internals/Interop/MARGINS.cs
  12. 26
      Apewer/Internals/Interop/RECT.cs
  13. 27
      Apewer/Internals/Interop/SHCore.cs
  14. 8
      Apewer/Internals/Interop/User32.cs
  15. 62
      Apewer/Logger.cs
  16. 13
      Apewer/NetworkUtility.cs
  17. 8
      Apewer/ObjectSet.cs
  18. 39
      Apewer/RuntimeUtility.cs
  19. 86
      Apewer/StorageUtility.cs
  20. 40
      Apewer/Surface/FormsUtility.cs
  21. 66
      Apewer/Surface/NormalForm.cs
  22. 83
      Apewer/SystemUtility.cs
  23. 36
      Apewer/Web/ApiProgram.cs
  24. 2
      Apewer/Web/CronLog.cs
  25. 244
      Apewer/Web/StaticController.cs
  26. 6
      Apewer/_ChangeLog.md

45
Apewer.Run/Apewer.Run.csproj

@ -1,15 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<!--<TargetFrameworks>net20</TargetFrameworks>-->
<!--<TargetFrameworks>net40</TargetFrameworks>-->
<!--<TargetFrameworks>net461</TargetFrameworks>-->
<TargetFrameworks>net461</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Apewer\Apewer.csproj" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<!--<TargetFrameworks>net20</TargetFrameworks>-->
<!--<TargetFrameworks>net40</TargetFrameworks>-->
<!--<TargetFrameworks>net461</TargetFrameworks>-->
<TargetFrameworks>net461</TargetFrameworks>
</PropertyGroup>
<!-- .NET Framework 4.6.1 -->
<PropertyGroup Condition="'$(TargetFramework)'=='net461'">
<AssemblyTitle>$(AssemblyName) - .NET Framework 4.6.1</AssemblyTitle>
<DefineConstants>NETFX;NET461;NET45;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net461'">
<Reference Include="CustomMarshalers" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="PresentationCore" />
<Reference Include="System.Core" />
<Reference Include="System.Configuration" />
<Reference Include="System.Design" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.Runtime.Caching" />
<Reference Include="System.Security" />
<Reference Include="System.Speech" />
<Reference Include="System.Transactions" />
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Apewer\Apewer.csproj" />
</ItemGroup>
</Project>

10
Apewer/Apewer.csproj

@ -9,7 +9,7 @@
<LangVersion>latest</LangVersion>
<NoWarn>CS0108,CS0162,CS0414,CS0612,CS0618,CS0649,CS1589,CS1570,CS1572,CS1573,CS3019,CS3021</NoWarn>
<OutputType>Library</OutputType>
<TargetFrameworks>netcoreapp3.1;netstandard2.1;net461;net40;net20</TargetFrameworks>
<TargetFrameworks>netcoreapp3.1;netstandard2.1;netstandard2.0;net461;net40;net20</TargetFrameworks>
</PropertyGroup>
<!-- 程序集信息 -->
@ -20,7 +20,7 @@
<Description></Description>
<RootNamespace>Apewer</RootNamespace>
<Product>Apewer Libraries</Product>
<Version>6.3.2</Version>
<Version>6.3.3</Version>
</PropertyGroup>
<!-- NuGet -->
@ -43,6 +43,12 @@
<DefineConstants>NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<!-- .NET Standard 2.0 -->
<PropertyGroup Condition="'$(TargetFramework)'=='netstandard2.0'">
<AssemblyTitle>$(AssemblyName) - .NET Standard 2.0</AssemblyTitle>
<DefineConstants>NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants)</DefineConstants>
</PropertyGroup>
<!-- .NET Framework 2.0 -->
<PropertyGroup Condition="'$(TargetFramework)'=='net20'">
<AssemblyTitle>$(AssemblyName) - .NET Framework 2.0</AssemblyTitle>

3
Apewer/BinaryUtility.cs

@ -153,6 +153,9 @@ namespace Apewer
return wiped;
}
/// <summary>生成新的 GUID 数据。</summary>
public static byte[] NewGuid() => Guid.NewGuid().ToByteArray();
#endregion
#region Text

81
Apewer/ChinaUtility.cs

@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Apewer
{
/// <summary></summary>
public class ChinaUtility
{
private static bool CheckIdCode18(string idCode18)
{
// GB11643-1999
if (string.IsNullOrEmpty(idCode18) || idCode18.Length != 18) return false;
var code = idCode18;
// 数字。
var n = 0L;
if (long.TryParse(code.Remove(17), out n) == false) return false;
if (n < Math.Pow(10, 16)) return false;
if (long.TryParse(code.Replace('x', '0').Replace('X', '0'), out n) == false) return false;
// 省份。
var address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91";
if (address.IndexOf(code.Remove(2)) < 0) return false;
// 生日。
var birth = code.Substring(6, 8).Insert(6, "-").Insert(4, "-");
var time = new DateTime();
if (DateTime.TryParse(birth, out time) == false) return false;
// 校验码。
var cc = "10x98765432".ToCharArray();
var wi = "7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2".Split(',');
var ai = code.Remove(17).ToCharArray();
var sum = 0;
for (int i = 0; i < 17; i++)
{
sum += int.Parse(wi[i]) * int.Parse(ai[i].ToString());
}
var y = sum % 11;
if (cc[y] != code[17]) return false;
return true;
}
private static bool CheckIdCode15(string idCode15)
{
if (string.IsNullOrEmpty(idCode15) || idCode15.Length != 15) return false;
var code = idCode15;
// 数字。
var n = 0L;
if (long.TryParse(code, out n) == false || n < Math.Pow(10, 14)) return false;
// 省份。
var address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91";
if (address.IndexOf(code.Remove(2)) == -1) return false;
// 生日。
var birth = code.Substring(6, 6).Insert(4, "-").Insert(2, "-");
var time = new DateTime();
if (DateTime.TryParse(birth, out time) == false) return false;
return true;
}
/// <summary></summary>
public static bool CheckIdCode(string idCode)
{
if (string.IsNullOrEmpty(idCode)) return false;
if (idCode.Length == 18) return CheckIdCode18(idCode);
if (idCode.Length == 15) return CheckIdCode15(idCode);
return false;
}
}
}

2
Apewer/Externals/Newtonsoft.Json-11.0.1/Serialization/JsonPropertyCollection.cs

@ -140,7 +140,7 @@ namespace Newtonsoft.Json.Serialization
return property;
}
#if NETFX
#if NETFX || NETSTANDARD2_0
private bool TryGetValue(string key, out JsonProperty item)
#else
private new bool TryGetValue(string key, out JsonProperty item)

11
Apewer/Internals/Interop/AdvApi32.cs

@ -9,15 +9,16 @@ namespace Apewer.Internals.Interop
{
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokenPrivilege newst, int len, IntPtr prev, IntPtr relen);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValueA
(string host, string name, ref long pluid);
internal static extern bool LookupPrivilegeValueA(string host, string name, ref long pluid);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool
AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokenPrivilege newst, int len, IntPtr prev, IntPtr relen);
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
}

107
Apewer/Internals/Interop/Constant.cs

@ -218,6 +218,8 @@ namespace Apewer.Internals.Interop
public const int DMDO_180 = 2;
public const int DMDO_270 = 3;
#region 电源。
public const int SE_PRIVILEGE_ENABLED = 0x00000002;
public const int TOKEN_QUERY = 0x00000008;
public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
@ -230,6 +232,8 @@ namespace Apewer.Internals.Interop
public const int EWX_POWEROFF = 0x00000008;
public const int EWX_FORCEIFHUNG = 0x00000010;
#endregion
#region Windows Hook
/// <summary>
@ -327,6 +331,109 @@ namespace Apewer.Internals.Interop
#endregion
#region vbKey 按键事件
public const byte vbKeyLButton = 0x1; // 鼠标左键
public const byte vbKeyRButton = 0x2; // 鼠标右键
public const byte vbKeyCancel = 0x3; // CANCEL 键
public const byte vbKeyMButton = 0x4; // 鼠标中键
public const byte vbKeyBack = 0x8; // BACKSPACE 键
public const byte vbKeyTab = 0x9; // TAB 键
public const byte vbKeyClear = 0xC; // CLEAR 键
public const byte vbKeyReturn = 0xD; // ENTER 键
public const byte vbKeyShift = 0x10; // SHIFT 键
public const byte vbKeyControl = 0x11; // CTRL 键
public const byte vbKeyAlt = 18; // Alt 键 (键码18)
public const byte vbKeyMenu = 0x12; // MENU 键
public const byte vbKeyPause = 0x13; // PAUSE 键
public const byte vbKeyCapital = 0x14; // CAPS LOCK 键
public const byte vbKeyEscape = 0x1B; // ESC 键
public const byte vbKeySpace = 0x20; // SPACEBAR 键
public const byte vbKeyPageUp = 0x21; // PAGE UP 键
public const byte vbKeyEnd = 0x23; // End 键
public const byte vbKeyHome = 0x24; // HOME 键
public const byte vbKeyLeft = 0x25; // LEFT ARROW 键
public const byte vbKeyUp = 0x26; // UP ARROW 键
public const byte vbKeyRight = 0x27; // RIGHT ARROW 键
public const byte vbKeyDown = 0x28; // DOWN ARROW 键
public const byte vbKeySelect = 0x29; // Select 键
public const byte vbKeyPrint = 0x2A; // PRINT SCREEN 键
public const byte vbKeyExecute = 0x2B; // EXECUTE 键
public const byte vbKeySnapshot = 0x2C; // SNAPSHOT 键
public const byte vbKeyDelete = 0x2E; // Delete 键
public const byte vbKeyHelp = 0x2F; // HELP 键
public const byte vbKeyNumlock = 0x90; // NUM LOCK 键
public const byte vbKeyA = 65;
public const byte vbKeyB = 66;
public const byte vbKeyC = 67;
public const byte vbKeyD = 68;
public const byte vbKeyE = 69;
public const byte vbKeyF = 70;
public const byte vbKeyG = 71;
public const byte vbKeyH = 72;
public const byte vbKeyI = 73;
public const byte vbKeyJ = 74;
public const byte vbKeyK = 75;
public const byte vbKeyL = 76;
public const byte vbKeyM = 77;
public const byte vbKeyN = 78;
public const byte vbKeyO = 79;
public const byte vbKeyP = 80;
public const byte vbKeyQ = 81;
public const byte vbKeyR = 82;
public const byte vbKeyS = 83;
public const byte vbKeyT = 84;
public const byte vbKeyU = 85;
public const byte vbKeyV = 86;
public const byte vbKeyW = 87;
public const byte vbKeyX = 88;
public const byte vbKeyY = 89;
public const byte vbKeyZ = 90;
public const byte vbKey0 = 48;
public const byte vbKey1 = 49;
public const byte vbKey2 = 50;
public const byte vbKey3 = 51;
public const byte vbKey4 = 52;
public const byte vbKey5 = 53;
public const byte vbKey6 = 54;
public const byte vbKey7 = 55;
public const byte vbKey8 = 56;
public const byte vbKey9 = 57;
public const byte vbKeyNumpad0 = 0x60;
public const byte vbKeyNumpad1 = 0x61;
public const byte vbKeyNumpad2 = 0x62;
public const byte vbKeyNumpad3 = 0x63;
public const byte vbKeyNumpad4 = 0x64;
public const byte vbKeyNumpad5 = 0x65;
public const byte vbKeyNumpad6 = 0x66;
public const byte vbKeyNumpad7 = 0x67;
public const byte vbKeyNumpad8 = 0x68;
public const byte vbKeyNumpad9 = 0x69;
public const byte vbKeyMultiply = 0x6A; // MULTIPLICATIONSIGN (*)
public const byte vbKeyAdd = 0x6B; // PLUS SIGN (+)
public const byte vbKeySeparator = 0x6C; // ENTER
public const byte vbKeySubtract = 0x6D; // MINUS SIGN (-)
public const byte vbKeyDecimal = 0x6E; // DECIMAL POINT (.)
public const byte vbKeyDivide = 0x6F; // DIVISION SIGN (/)
public const byte vbKeyF1 = 0x70;
public const byte vbKeyF2 = 0x71;
public const byte vbKeyF3 = 0x72;
public const byte vbKeyF4 = 0x73;
public const byte vbKeyF5 = 0x74;
public const byte vbKeyF6 = 0x75;
public const byte vbKeyF7 = 0x76;
public const byte vbKeyF8 = 0x77;
public const byte vbKeyF9 = 0x78;
public const byte vbKeyF10 = 0x79;
public const byte vbKeyF11 = 0x7A;
public const byte vbKeyF12 = 0x7B;
#endregion
}
}

24
Apewer/Internals/Interop/DWM_BLURBEHIND.cs

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace Apewer.Internals.Interop
{
[StructLayout(LayoutKind.Sequential)]
internal class DWM_BLURBEHIND
{
public uint dwFlags;
[MarshalAs(UnmanagedType.Bool)]
public bool fEnable;
public IntPtr hRegionBlur;
[MarshalAs(UnmanagedType.Bool)]
public bool fTransitionOnMaximized;
public const uint DWM_BB_ENABLE = 0x00000001;
public const uint DWM_BB_BLURREGION = 0x00000002;
public const uint DWM_BB_TRANSITIONONMAXIMIZED = 0x00000004;
}
}

27
Apewer/Internals/Interop/DWM_THUMBNAIL_PROPERTIES.cs

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace Apewer.Internals.Interop
{
[StructLayout(LayoutKind.Sequential)]
internal class DWM_THUMBNAIL_PROPERTIES
{
public uint dwFlags;
public RECT rcDestination;
public RECT rcSource;
public byte opacity;
[MarshalAs(UnmanagedType.Bool)]
public bool fVisible;
[MarshalAs(UnmanagedType.Bool)]
public bool fSourceClientAreaOnly;
public const uint DWM_TNP_RECTDESTINATION = 0x00000001;
public const uint DWM_TNP_RECTSOURCE = 0x00000002;
public const uint DWM_TNP_OPACITY = 0x00000004;
public const uint DWM_TNP_VISIBLE = 0x00000008;
public const uint DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010;
}
}

44
Apewer/Internals/Interop/DwmApi.cs

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace Apewer.Internals.Interop
{
class DwmApi
{
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmEnableBlurBehindWindow(IntPtr hWnd, DWM_BLURBEHIND pBlurBehind);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmEnableComposition(bool bEnable);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, MARGINS pMargins);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmGetColorizationColor(out int pcrColorization, [MarshalAs(UnmanagedType.Bool)] out bool pfOpaqueBlend);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern bool DwmIsCompositionEnabled();
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmQueryThumbnailSourceSize(IntPtr hThumbnail, out Size size);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern IntPtr DwmRegisterThumbnail(IntPtr dest, IntPtr source);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmUnregisterThumbnail(IntPtr hThumbnail);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmUpdateThumbnailProperties(IntPtr hThumbnail, DWM_THUMBNAIL_PROPERTIES props);
}
}

18
Apewer/Internals/Interop/MARGINS.cs

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace Apewer.Internals.Interop
{
[StructLayout(LayoutKind.Sequential)]
internal struct MARGINS
{
public int Left;
public int Right;
public int Top;
public int Bottom;
}
}

26
Apewer/Internals/Interop/RECT.cs

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace Apewer.Internals.Interop
{
[StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public RECT(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
}
}

27
Apewer/Internals/Interop/SHCore.cs

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace Apewer.Internals.Interop
{
internal class SHCore
{
[DllImport("SHCore.dll", SetLastError = true)]
public static extern bool SetProcessDpiAwareness(PROCESS_DPI_AWARENESS awareness);
[DllImport("SHCore.dll", SetLastError = true)]
public static extern void GetProcessDpiAwareness(IntPtr hprocess, out PROCESS_DPI_AWARENESS awareness);
public enum PROCESS_DPI_AWARENESS
{
Process_DPI_Unaware = 0,
Process_System_DPI_Aware = 1,
Process_Per_Monitor_DPI_Aware = 2
}
}
}

8
Apewer/Internals/Interop/User32.cs

@ -131,6 +131,14 @@ namespace Apewer.Internals.Interop
[DllImport("user32.dll")]
public static extern void keybd_Callback(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
/// <summary>发送键盘事件。</summary>
/// <param name="bVk" >按键的虚拟键值</param>
/// <param name= "bScan" >扫描码,一般不用设置,用 0 代替。</param>
/// <param name= "dwFlags" >选项标志:0 按下,2 释放。</param>
/// <param name= "dwExtraInfo">扩展信息,默认为 0。</param>
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
/// <summary></summary>
/// <param name="type"></param>
/// <returns></returns>

62
Apewer/Logger.cs

@ -16,7 +16,6 @@ namespace Apewer
public class Logger
{
private string _key = Guid.NewGuid().ToString("n");
private string _target = "";
private bool _enabled = true;
private Func<string, bool> _preoutput = null;
@ -25,15 +24,15 @@ namespace Apewer
private bool _usefile = false;
private bool _uselock = false;
/// <summary>当前日志记录器的名称。</summary>
public virtual string Name { get; set; }
/// <summary>已启用。</summary>
public virtual bool Enabled { get; set; }
/// <summary>在后台线程处理日志。默认值:FALSE。</summary>
internal virtual bool Background { get; set; } = false;
/// <summary>捕获并丢弃事件中的异常。默认值:FALSE。</summary>
public virtual bool Catch { get; set; } = false;
/// <summary>使用控制台输出。默认值:TRUE。</summary>
public virtual bool UseConsole
{
@ -70,15 +69,17 @@ namespace Apewer
{
if (Background)
{
RuntimeUtility.InBackground(action);
RuntimeUtility.InBackground(action, true);
return;
}
action.Invoke();
try { action.Invoke(); } catch { }
}
/// <summary>记录异常。</summary>
public virtual void Exception(object sender, Exception exception) => Invoke(() =>
{
if (!Enabled) return;
if (OnException != null)
{
OnException(sender, exception);
@ -109,11 +110,13 @@ namespace Apewer
}
if (UseConsole) ToConsole(item);
if (UseFile) ToFile(item);
if (UseFile) ToFile(item, this);
});
private void Colorful(object sender, string tag, Nullable<ConsoleColor> color, object[] content, Event<string> defined) => Invoke(() =>
{
if (!Enabled) return;
if (defined != null)
{
defined.Invoke(sender, MergeContent(content));
@ -127,7 +130,7 @@ namespace Apewer
item.Content = MergeContent(content);
if (UseConsole) ToConsole(item);
if (UseFile) ToFile(item);
if (UseFile) ToFile(item, this);
});
/// <summary>记录错误。多个 Content 参数将以“ | ”分隔。</summary>
@ -149,8 +152,9 @@ namespace Apewer
/// <summary>创建新实例。</summary>
public Logger() { }
internal Logger(bool useConsole, bool useFile, bool enabled)
private Logger(string name, bool useConsole, bool useFile, bool enabled)
{
Name = name;
_useconsole = useConsole;
_usefile = useFile;
_uselock = true;
@ -162,6 +166,9 @@ namespace Apewer
internal static object FileLocker = new object();
internal static object ConsoleLocker = new object();
/// <summary>获取用于保存日志文件的路径。</summary>
public static Func<string> FilePathGetter { get; set; }
private static string MergeContent(params object[] content) => TextUtility.Join(" | ", content);
private static string FormatSender(object sender)
@ -254,29 +261,30 @@ namespace Apewer
}
// 向日志文件输出文本,文件名按日期自动生成。
private static string ToFile(string plain)
private static string ToFile(string plain, Logger logger)
{
var text2 = TextUtility.Trim(plain) + "\r\n";
lock (FileLocker)
{
var path = GetFileDir();
var path = GetFilePath(logger);
if (string.IsNullOrEmpty(path)) return "写入日志文件失败:无法获取日志文件路径。";
var bytes = TextUtility.ToBinary(TextUtility.Merge(plain, "\r\n"));
if (!StorageUtility.AppendFile(path, bytes)) return "写入日志文件失败。";
}
return null;
}
// 向日志文件输出文本,文件名按日期自动生成。
private static string ToFile(LogItem item) => ToFile(ToText(item));
private static string ToFile(LogItem item, Logger logger) => ToFile(ToText(item), logger);
/// <summary>获取日志文件路径发生错误时返回 NULL 值。</summary>
/// <remarks>d:\app\log\2020-02-02.log</remarks>
/// <remarks>d:\www\app_data\log\2020-02-02.log</remarks>
public static string GetFileDir()
/// <remarks>默认例:<br/>d:\app\log\1970-01-01.log<br/>d:\www\app_data\log\1970-01-01.log</remarks>
public static string GetFilePath(Logger logger = null)
{
var getter = FilePathGetter;
if (getter != null) try { return getter.Invoke(); } catch { }
// 找到 App_Data 目录。
var appDir = RuntimeUtility.ApplicationPath;
var dataDir = Path.Combine(appDir, "app_data");
@ -303,18 +311,18 @@ namespace Apewer
#region 默认实列。
private static Logger _default = new Logger(true, false, true);
private static Logger _console = new Logger(true, false, true);
private static Logger _web = new Logger(true, false, true);
private static Logger _default = new Logger("Apewer.Logger.Default", true, false, true);
private static Logger _console = new Logger("Apewer.Logger.Console", true, false, true);
private static Logger _web = new Logger("Apewer.Logger.Web", true, false, true);
#if DEBUG
internal static Logger _internals = new Logger(true, true, true);
internal static Logger _internals = new Logger("Apewer.Logger.Internals", true, true, true);
#else
internal static Logger _internals = new Logger(true, false, false);
internal static Logger _internals = new Logger("Apewer.Logger.Internals", true, false, false);
#endif
/// <summary>内部的日志记录程序。</summary>
public static Logger Internals { get => _internals; }
internal static Logger Internals { get => _internals; }
/// <summary>默认的日志记录程序。</summary>
public static Logger Default { get => _default; }
@ -325,9 +333,9 @@ namespace Apewer
/// <summary>用于 Web 的日志记录程序。</summary>
public static Logger Web { get => _web; }
#endregion
#endregion
#region 静态调用。
#region 静态调用。
/// <summary>使用 Logger.Default 写入日志,自动添加时间和日期,多个 Content 参数将以“ | ”分隔。</summary>
public static void Write(params object[] content) => Default.Invoke(() =>
@ -340,7 +348,7 @@ namespace Apewer
item.Content = MergeContent(content);
if (console) ToConsole(item);
if (file) ToFile(item);
if (file) ToFile(item, Default);
}
});
@ -356,11 +364,11 @@ namespace Apewer
item.Content = MergeContent(content);
if (console) ToConsole(item);
if (file) ToFile(item);
if (file) ToFile(item, Default);
}
});
#endregion
#endregion
}

13
Apewer/NetworkUtility.cs

@ -69,9 +69,7 @@ namespace Apewer
return GetUtcFromNtp(endpoint, timeout);
}
}
catch (Exception ex)
{
}
catch { }
return ClockUtility.Zero;
}
@ -103,9 +101,7 @@ namespace Apewer
var utc = (new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds(milliseconds);
return utc;
}
catch (Exception ex)
{
}
catch { }
return ClockUtility.Zero;
}
@ -122,10 +118,9 @@ namespace Apewer
#region ARP
#if NET40 || NET461
/// <summary>发送 ARP 请求,获取目标 IP 地址对应设备的 MAC 地址,MAC 格式为 01-23-45-67-89-AB。</summary>
/// <param name="ip">目标 IP 地址。</param>
/// <remarks>注:<br />仅 Windows 可用。</remarks>
/// <returns>MAC 地址。</returns>
public static string SendARP(string ip)
{
@ -146,8 +141,6 @@ namespace Apewer
return "";
}
#endif
#endregion
#region Puny Code

8
Apewer/ObjectSet.cs

@ -14,9 +14,9 @@ namespace Apewer
{
/// <summary></summary>
public ObjectSet(bool autotrim)
public ObjectSet(bool autoTrim)
{
AutoTrim = autotrim;
AutoTrim = autoTrim;
}
/// <summary></summary>
@ -62,9 +62,9 @@ namespace Apewer
}
/// <summary>构造函数。</summary>
public ObjectSet(bool autotrim)
public ObjectSet(bool autoTrim)
{
_autotrim = autotrim;
_autotrim = autoTrim;
_origin = new Dictionary<string, T>();
}

39
Apewer/RuntimeUtility.cs

@ -707,40 +707,35 @@ namespace Apewer
if (milliseconds > 0) Thread.Sleep(milliseconds);
}
/// <summary>在后台线程中执行,指定 Try 将忽略异常。</summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public static Thread InBackground(Action action, bool @try = false)
private static void Invoke(Action action, bool @try = false)
{
if (action == null) return null;
Thread thread;
if (action == null) return;
if (@try)
{
thread = new Thread(delegate (object v)
{
try
{
((Action)v)();
}
catch { }
});
try { action.Invoke(); } catch { }
}
else
else { action.Invoke(); }
}
/// <summary>在后台线程中执行,指定 Try 将忽略 Action 抛出的异常。</summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public static Thread InBackground(Action action, bool @try = false)
{
if (action == null) return null;
var thread = new Thread(delegate (object v)
{
thread = new Thread(delegate (object v)
{
((Action)v)();
});
}
Invoke(() => ((Action)v)(), @try);
});
thread.IsBackground = true;
thread.Start(action);
return thread;
}
/// <summary>启动线程。</summary>
public static Thread StartThread(Action action, bool background = true)
/// <summary>启动线程,指定 Try 将忽略 Action 抛出的异常。</summary>
public static Thread StartThread(Action action, bool background = true, bool @try = false)
{
if (action == null) return null;
var thread = new Thread(new ThreadStart(action));
var thread = new Thread(new ThreadStart(() => Invoke(action, @try)));
thread.IsBackground = background;
thread.Start();
return thread;

86
Apewer/StorageUtility.cs

@ -172,43 +172,42 @@ namespace Apewer
}
/// <summary>获取指定目录的子目录,可指定递归子目录。</summary>
public static List<string> GetSubDirectories(string directory, bool recursive = false, bool recurPrecedence = true) => GetSubDirectories(directory, recursive ? -1 : 0, recurPrecedence);
public static List<string> GetSubDirectories(string dirPath, bool recursive = false, bool recurPrecedence = true) => GetSubDirectories(dirPath, recursive ? -1 : 0, recurPrecedence);
/// <summary>获取指定目录下子目录的路径。</summary>
/// <param name="directory">顶级目录。</param>
/// <param name="dirPath">顶级目录。</param>
/// <param name="recurDepth">子目录递归深度,指定为 0 时不递归,指定为 -1 时无限递归。</param>
/// <param name="recurPrecedence">优先排列递归项。</param>
public static List<string> GetSubDirectories(string directory, int recurDepth, bool recurPrecedence = true)
public static List<string> GetSubDirectories(string dirPath, int recurDepth, bool recurPrecedence = true)
{
var list = new List<string>();
if (string.IsNullOrEmpty(directory)) return list;
if (string.IsNullOrEmpty(dirPath)) return list;
var directories = new string[0];
try
{
directories = Directory.GetDirectories(directory);
directories = Directory.GetDirectories(dirPath);
}
catch { }
foreach (var d in directories)
foreach (var dir in directories)
{
var recurlist = new List<string>();
if (recurDepth != 0)
{
var depth = (recurDepth > 0) ? recurDepth - 1 : recurDepth;
var subrecur = GetSubDirectories(d, depth, recurPrecedence);
var subrecur = GetSubDirectories(dir, depth, recurPrecedence);
recurlist.AddRange(subrecur);
}
if (recurPrecedence)
{
list.AddRange(recurlist);
list.Add(d);
list.Add(dir);
}
else
{
list.Add(d);
list.Add(dir);
list.AddRange(recurlist);
}
}
@ -217,33 +216,33 @@ namespace Apewer
}
/// <summary>获取指定目录的子文件,可指定递归子目录。</summary>
public static List<string> GetSubFiles(string path, bool recursive = false, bool recurPrecedence = true) => GetSubFiles(path, recursive ? -1 : 0, recurPrecedence);
public static List<string> GetSubFiles(string dirPath, bool recursive = false, bool recurPrecedence = true) => GetSubFiles(dirPath, recursive ? -1 : 0, recurPrecedence);
/// <summary>获取指定目录下子文件的路径。</summary>
/// <param name="directory">顶级目录。</param>
/// <param name="dirPath">顶级目录。</param>
/// <param name="recurDepth">子目录递归深度,指定为 0 时不递归,指定为 -1 时无限递归。</param>
/// <param name="recurPrecedence">优先排列递归项。</param>
public static List<string> GetSubFiles(string directory, int recurDepth, bool recurPrecedence = true)
public static List<string> GetSubFiles(string dirPath, int recurDepth, bool recurPrecedence = true)
{
var list = new List<string>();
if (string.IsNullOrEmpty(directory)) return list;
if (string.IsNullOrEmpty(dirPath)) return list;
var dirs = new List<string>();
if (recurDepth == 0)
{
dirs.Add(directory);
dirs.Add(dirPath);
}
else
{
var recurdicrotylist = GetSubDirectories(directory, recurDepth, recurPrecedence);
var recurdicrotylist = GetSubDirectories(dirPath, recurDepth, recurPrecedence);
if (recurPrecedence)
{
dirs.AddRange(recurdicrotylist);
dirs.Add(directory);
dirs.Add(dirPath);
}
else
{
dirs.Add(directory);
dirs.Add(dirPath);
dirs.AddRange(recurdicrotylist);
}
}
@ -459,16 +458,61 @@ namespace Apewer
}
/// <summary>读取文件,获取文件内容。当文件为 UTF-8 文本文件时,可去除 BOM 头。</summary>
/// <remarks>注:<br />字节数组最大为 2GB;<br />此方法不抛出异常,读取失时返回空字节数组。</remarks>
public static byte[] ReadFile(string path, bool wipeBom = false)
{
const int Buffer = 1048576;
if (!FileExists(path)) return Constant.EmptyBytes;
lock (Locker)
{
try
{
var bytes = File.ReadAllBytes(path);
if (wipeBom) bytes = BinaryUtility.WipeTextBom(bytes);
return bytes;
var result = new byte[0];
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
if (!stream.CanRead) return Constant.EmptyBytes;
stream.Position = 0;
var length = stream.Length;
if (length < 1) return Constant.EmptyBytes;
if (length > int.MaxValue) return Constant.EmptyBytes;
var offset = 0L;
if (wipeBom && length >= 3)
{
var head = new byte[3];
stream.Read(head, 0, 3);
if (BinaryUtility.ContainsBOM(head))
{
var capacity = length - 3;
result = new byte[capacity];
}
else
{
result = new byte[length];
result[0] = head[0];
result[1] = head[1];
result[2] = head[2];
offset = 3;
}
}
else
{
result = new byte[length];
}
var block = new byte[Buffer];
while (true)
{
var read = stream.Read(block, 0, Buffer);
if (read < 1) break;
Array.Copy(block, 0, result, offset, read);
offset += read;
}
}
return result;
}
catch { }
}

40
Apewer/Surface/FormsUtility.cs

@ -6,6 +6,7 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Reflection;
using System.Diagnostics;
#if NETFX || NETCORE
using System.Drawing.Drawing2D;
@ -14,6 +15,8 @@ using System.Drawing.Text;
using System.Windows.Forms;
#endif
using static Apewer.Internals.Interop.SHCore;
namespace Apewer.Surface
{
@ -25,15 +28,40 @@ namespace Apewer.Surface
/// <summary>线程锁。</summary>
public static object ThreadLocker = new object();
/// <summary>已使用系统 DPI 设置。</summary>
public static bool UsedSystemDPI { get; private set; }
internal static Nullable<float> DpiScale { get; set; }
#if NETFX || NETCORE
/// <summary>窗体启动初始化。</summary>
[STAThread]
public static void StartInitialization()
public static void StartInitialization(bool useSystemDPI = false)
{
Control.CheckForIllegalCrossThreadCalls = false;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Application.SetCompatibleTextRenderingDefault(true);
if (useSystemDPI) UseSystemDPI();
}
/// <summary>使用系统的 DPI 设置。</summary>
public static void UseSystemDPI()
{
if (UsedSystemDPI) return;
UsedSystemDPI = true;
#if NETCORE
Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
#else
SetProcessDpiAwareness(PROCESS_DPI_AWARENESS.Process_System_DPI_Aware);
Marshal.GetLastWin32Error();
PROCESS_DPI_AWARENESS awareness;
GetProcessDpiAwareness(Process.GetCurrentProcess().Handle, out awareness);
Marshal.GetLastWin32Error();
#endif
}
/// <summary>禁用跨线程调用检查。</summary>
@ -376,6 +404,16 @@ namespace Apewer.Surface
#endregion
#region Aero
/// <summary>获取 DWM 的 Composition 启用状态。</summary>
public static bool DwmIsCompositionEnabled
{
get => DwmApi.DwmIsCompositionEnabled();
}
#endregion
#region 窗体。
#if NETFX || NETCORE

66
Apewer/Surface/NormalForm.cs

@ -1,8 +1,11 @@
#if NETFX || NETCORE
using Apewer.Internals.Interop;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace Apewer.Surface
{
@ -47,6 +50,69 @@ namespace Apewer.Surface
InitializeComponent();
}
/// <summary>获取 DPI 缩放比例。</summary>
public double DpiScale
{
get
{
if (FormsUtility.DpiScale == null)
{
using (var g = CreateGraphics())
{
FormsUtility.DpiScale = g.DpiX / 96F;
}
}
return FormsUtility.DpiScale.Value;
}
}
/// <summary>
///
/// </summary>
/// <param name="m"></param>
protected override void WndProc(ref Message m)
{
// WM_DPICHANGED = 0x02E0
base.WndProc(ref m);
}
#region Aero
private bool AeroEnabled = false;
/// <summary>启用 Aero 透明效果。</summary>
private void EnableAero()
{
AeroEnabled = true;
Load += (s, e) =>
{
if (!FormsUtility.DwmIsCompositionEnabled) return;
var width = Width;
var height = Height;
var margins = new MARGINS();
// margins.Right = -1; // 全窗体透明。
margins.Right = margins.Left = margins.Top = margins.Bottom = width + height;
DwmApi.DwmExtendFrameIntoClientArea(Handle, ref margins);
};
}
/// <summary></summary>
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
if (AeroEnabled)
{
if (FormsUtility.DwmIsCompositionEnabled)
{
e.Graphics.Clear(Color.Black);
}
}
}
#endregion
}
}

83
Apewer/SystemUtility.cs

@ -18,6 +18,11 @@ using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using static Apewer.Internals.Interop.Constant;
using static Apewer.Internals.Interop.AdvApi32;
using static Apewer.Internals.Interop.Kernel32;
using static Apewer.Internals.Interop.User32;
namespace Apewer
{
@ -48,6 +53,36 @@ namespace Apewer
/// <summary>当前操作系统是 Linux。</summary>
public static bool IsLinux { get => CheckOsType() == 3; }
#if NETFX
/// <summary>获取内存容量。</summary>
public static long RamTotal
{
get
{
try
{
var mos = new ManagementObjectSearcher();
mos.Query = new SelectQuery("win32_physicalmemory", "", new string[] { "capacity" });
var moc = mos.Get();
var total = 0L;
foreach (var mbo in moc)
{
var value = mbo.Properties["capacity"].Value;
if (value != null)
{
total += long.Parse(value.ToString());
}
}
return total;
}
catch { }
return 0;
}
}
#endif
#endregion
#region 进程。
@ -323,40 +358,30 @@ namespace Apewer
#endregion
#region 硬件。
#region 硬件 & 电源
private static void ExitWindows(int flag)
{
bool ok;
TokenPrivilege tp;
IntPtr hproc = Kernel32.GetCurrentProcess();
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
ok = AdvApi32.OpenProcessToken(hproc, Constant.TOKEN_ADJUST_PRIVILEGES | Constant.TOKEN_QUERY, ref htok);
OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = Constant.SE_PRIVILEGE_ENABLED;
ok = AdvApi32.LookupPrivilegeValueA(null, Constant.SE_SHUTDOWN_NAME, ref tp.Luid);
ok = AdvApi32.AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
ok = User32.ExitWindowsEx(flag, 0);
tp.Attr = SE_PRIVILEGE_ENABLED;
LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);
AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
ExitWindowsEx(flag, 0);
}
/// <summary>强制关机。</summary>
public static void Shutdown()
{
ExitWindows(Constant.EWX_FORCE | Constant.EWX_POWEROFF);
}
/// <summary>关机。</summary>
public static void Shutdown() => ExitWindows(EWX_FORCE | EWX_POWEROFF);
/// <summary>强制重启。</summary>
public static void Reboot()
{
ExitWindows(Constant.EWX_FORCE | Constant.EWX_REBOOT);
}
/// <summary>重启。</summary>
public static void Reboot() => ExitWindows(EWX_FORCE | EWX_REBOOT);
/// <summary>强制注销。</summary>
public static void LogOff()
{
ExitWindows(Constant.EWX_FORCE | Constant.EWX_LOGOFF);
}
/// <summary>注销。</summary>
public static void LogOff() => ExitWindows(EWX_FORCE | EWX_LOGOFF);
#if NETFX
@ -561,12 +586,22 @@ namespace Apewer
User32.mouse_Callback(MouseCallbackFlag.RightUp, x, y, 0, UIntPtr.Zero);
}
private static IntPtr GetHINSTANCE(Module m)
{
if ((object)m == null)
{
throw new ArgumentNullException("m");
}
return (IntPtr)(-1);
}
/// <summary>钩住鼠标。当前线程必须具有消息循环。</summary>
private static int HookMouse(Func<MouseEvent, bool> func)
{
if (func == null) return 0;
var proc = new HookProc(LowLevelMouseProc);
var hInstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);
// var hInstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);
var hInstance = GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);
var hook = 0;
hook = User32.SetWindowsHookEx(Constant.WH_MOUSE_LL, (int nCode, IntPtr wParam, IntPtr lParam) =>
{

36
Apewer/Web/ApiProgram.cs

@ -23,7 +23,7 @@ namespace Apewer.Web
#if NETFX || NETCORE
/// <summary>在当前线程运行标准应用程序消息循环。</summary>
public static void RunMessageLoop() => Application.Run();
protected static void RunMessageLoop() => Application.Run();
#endif
@ -106,7 +106,6 @@ namespace Apewer.Web
public partial class ApiProgram : IHttpHandler, IHttpModule
{
private bool _initialized = false;
private Action _before = null;
/// <summary>仅运行在 IIS 中时会对此类型创建实例。</summary>
@ -116,7 +115,25 @@ namespace Apewer.Web
_before = before;
}
#region IHttpHandler
#region Initialize
private static object InitLocker = new object();
private bool _initialized = false;
private void Initialize(Action action)
{
if (_initialized) return;
lock (InitLocker)
{
if (_initialized) return;
action?.Invoke();
_initialized = true;
}
}
#endregion
#region IHttpHandler
/// <summary></summary>
public bool IsReusable { get { return false; } }
@ -138,18 +155,13 @@ namespace Apewer.Web
// return;
//}
if (!_initialized)
{
_initialized = true;
var before = _before;
before?.Invoke();
}
Initialize(_before);
ApiInvoker.IIS(context);
}
#endregion
#endregion
#region IHttpModule
#region IHttpModule
/// <summary></summary>
public void Dispose() { }
@ -166,7 +178,7 @@ namespace Apewer.Web
};
}
#endregion
#endregion
}

2
Apewer/Web/CronLog.cs

@ -44,7 +44,7 @@ namespace Apewer.Web
}
/// <summary>向控制台写入文本的 Log 处理程序。</summary>
public static void Console(string text) => Logger.Console.Text(nameof (CronLog), text);
public static void Console(string text) => Logger.Web.Text("Cron", text);
}

244
Apewer/Web/StaticController.cs

@ -14,11 +14,28 @@ namespace Apewer.Web
public StaticController()
{
AllowFunction = false;
AfterInitialized = Execute;
AfterInitialized = () =>
{
if (Request == null || Request.Url == null) return;
var path = MapPath(Request.Url.AbsolutePath);
if (StorageUtility.DirectoryExists(path))
{
ExecuteDirectory(path);
return;
}
if (StorageUtility.FileExists(path))
{
ExecuteFile(path);
return;
}
Respond404(path);
};
}
#region property
/// <summary>获取此静态站点的目录。</summary>
public virtual string GetSiteDirectory()
protected virtual string GetSiteDirectory()
{
var app = WebUtility.AppDirectory;
var www = StorageUtility.CombinePath(app, "www");
@ -26,6 +43,34 @@ namespace Apewer.Web
return www;
}
/// <summary>响应 403 状态。</summary>
protected virtual void Respond403(string path) => Response.Error("403");
/// <summary>响应 404 状态。</summary>
protected virtual void Respond404(string path) => Response.Error("404");
/// <summary>从扩展名获取内容类型。</summary>
/// <remarks>例:<br/>GetContentType("txt") = "text/plain"</remarks>
protected virtual string GetContentType(string extension) => Mime(extension);
/// <summary>按扩展名获取过期时间,单位为秒。默认值为 0(不缓存)。</summary>
/// <remarks>例:<br/>GetExpires("txt") = 0</remarks>
protected virtual int GetExpires(string extension) => 0;
/// <summary>访问目录时,允许列出子项。默认值:false,不允许。</summary>
protected virtual bool AllowListChildren() => false;
string PrivateGetContentType(string extension)
{
var result = GetContentType(extension);
if (string.IsNullOrEmpty(result)) result = Mime(extension);
return result;
}
#endregion
#region common
/// <summary>解析 URL 的路径,获取本地路径。</summary>
protected string MapPath(string urlPath)
{
@ -43,24 +88,6 @@ namespace Apewer.Web
return path;
}
/// <summary>处理请求。</summary>
public virtual void Execute()
{
if (Request == null || Request.Url == null) return;
var path = MapPath(Request.Url.AbsolutePath);
if (StorageUtility.DirectoryExists(path))
{
ExecuteDirectory(path);
return;
}
if (StorageUtility.FileExists(path))
{
ExecuteFile(path);
return;
}
Respond404(path);
}
void ExecuteFile(string path)
{
if (!File.Exists(path))
@ -78,8 +105,7 @@ namespace Apewer.Web
if (expires > 0) Response.Expires = expires;
// 按扩展名获取 Content-Type。
var type = GetContentType(ext);
// var name = Path.GetFileName(path);
var type = PrivateGetContentType(ext);
// Server Side Includes
if (ext == "html" || ext == "htm" || ext == "shtml")
@ -101,13 +127,89 @@ namespace Apewer.Web
Respond404(path);
return;
}
var @default = GetDefaultFile(path);
if (string.IsNullOrEmpty(@default)) Respond403(path);
else ExecuteFile(@default);
if (!string.IsNullOrEmpty(@default))
{
ExecuteFile(@default);
return;
}
if (AllowListChildren())
{
Response.Data = ListChildren(path);
}
Respond403(path);
}
// Server Side Includes
string ReadWithSSI(string path, int recursive = 0)
{
if (recursive > 10) return "";
var input = StorageUtility.ReadFile(path, true);
if (input == null || input.LongLength < 1) return "";
// 尝试以 UTF-8 解码。
var html = TextUtility.FromBinary(input);
if (string.IsNullOrEmpty(html)) return "";
// 按首尾截取。
const string left = "<!--";
const string right = "-->";
const string head = "#include virtual=";
var sb = new StringBuilder();
var text = html;
while (true)
{
var offset = text.IndexOf(left);
if (offset < 0)
{
sb.Append(text);
break;
}
if (offset > 0)
{
sb.Append(text.Substring(0, offset));
text = text.Substring(offset + left.Length);
}
else text = text.Substring(left.Length);
var length = text.IndexOf(right);
if (length < 1)
{
sb.Append(left);
sb.Append(text);
break;
}
var inner = text.Substring(0, length);
var temp = inner.SafeTrim();
if (temp.StartsWith(head))
{
temp = temp.Substring(head.Length);
temp = temp.Replace("\"", "");
var subPath = MapPath(temp);
var subText = ReadWithSSI(subPath, recursive + 1);
if (subText != null && subText.Length > 0) sb.Append(subText);
}
else
{
sb.Append(left);
sb.Append(inner);
sb.Append(right);
}
text = text.Substring(length + right.Length);
}
var output = sb.ToString();
return output;
}
#endregion
#region static
// 获取目录中的默认文件,返回文件的完整路径。
string GetDefaultFile(string directory)
static string GetDefaultFile(string directory)
{
var subs = StorageUtility.GetSubFiles(directory);
if (subs.Count < 0) return null;
@ -130,18 +232,16 @@ namespace Apewer.Web
}
/// <summary>列出子项。可指定筛选器,传入完整路径。</summary>
public void ListChildren(string directory)
static Json ListChildren(string directory)
{
if (!Directory.Exists(directory)) return;
if (!Directory.Exists(directory)) return null;
var json = Json.NewObject();
json.SetProperty("directories", ListDirectories(directory));
json.SetProperty("files", ListFiles(directory));
Response.Data = json;
return json;
}
Json ListDirectories(string directory)
static Json ListDirectories(string directory)
{
var array = Json.NewArray();
var subs = StorageUtility.GetSubDirectories(directory);
@ -171,7 +271,7 @@ namespace Apewer.Web
return array;
}
Json ListFiles(string directory)
static Json ListFiles(string directory)
{
var array = Json.NewArray();
var subs = StorageUtility.GetSubFiles(directory);
@ -199,20 +299,7 @@ namespace Apewer.Web
return array;
}
/// <summary>响应 403 状态。</summary>
public virtual void Respond403(string path)
{
Response.Error("403");
}
/// <summary>响应 404 状态。</summary>
public virtual void Respond404(string path)
{
Response.Error("404");
}
/// <summary>按扩展名获取 Content-Type。</summary>
public virtual string GetContentType(string extension)
static string Mime(string extension)
{
if (!string.IsNullOrEmpty(extension))
{
@ -335,70 +422,7 @@ namespace Apewer.Web
return "application/octet-stream";
}
/// <summary>按扩展名获取过期时间,单位为秒,默认值为 0(不缓存)。</summary>
public virtual int GetExpires(string extension) => 0;
// Server Side Includes
string ReadWithSSI(string path, int recursive = 0)
{
if (recursive > 10) return "";
var input = StorageUtility.ReadFile(path, true);
if (input == null || input.LongLength < 1) return "";
// 尝试以 UTF-8 解码。
var html = TextUtility.FromBinary(input);
if (string.IsNullOrEmpty(html)) return "";
// 按首尾截取。
const string left = "<!--";
const string right = "-->";
const string head = "#include virtual=";
var sb = new StringBuilder();
var text = html;
while (true)
{
var offset = text.IndexOf(left);
if (offset < 0)
{
sb.Append(text);
break;
}
if (offset > 0)
{
sb.Append(text.Substring(0, offset));
text = text.Substring(offset + left.Length);
}
else text = text.Substring(left.Length);
var length = text.IndexOf(right);
if (length < 1)
{
sb.Append(left);
sb.Append(text);
break;
}
var inner = text.Substring(0, length);
var temp = inner.SafeTrim();
if (temp.StartsWith(head))
{
temp = temp.Substring(head.Length);
temp = temp.Replace("\"", "");
var subPath = MapPath(temp);
var subText = ReadWithSSI(subPath, recursive + 1);
if (subText != null && subText.Length > 0) sb.Append(subText);
}
else
{
sb.Append(left);
sb.Append(inner);
sb.Append(right);
}
text = text.Substring(length + right.Length);
}
var output = sb.ToString();
return output;
}
#endregion
}

6
Apewer/_ChangeLog.md

@ -1,6 +1,12 @@

### 最新提交
### 6.3.3
- 全局:恢复 .NET Standard 2.0 的输出,用于支持 .NET Framework 4.6.1;
- StorageUtility:优化了 ReadFile 的内存占用;
- Web:优化 ApiProgram 的初始化,减少并发时的问题;
- Web:Static 控制器支持列出子项。
### 6.3.2
- RuntimeUtility:调整了 Assembly 的方法名称;
- Surface:迁移获取字形的方法到 FormsUtility,不再提供 FontInstance 类;

Loading…
Cancel
Save