From beb1dd645c32a320172b8e1068d8d936867fe91a Mon Sep 17 00:00:00 2001 From: Aigio Liu Date: Wed, 24 Feb 2021 04:03:32 +0800 Subject: [PATCH] migrate ing... --- Directory.Build.props | 13 +- Packager/Form1.Designer.cs | 123 ++++++++++++ Packager/Form1.cs | 180 ++++++++++++++++++ Packager/Form1.resx | 60 ++++++ Packager/Packager.csproj | 35 ++++ Packager/Program.cs | 23 +++ SteamToolsV1.2+.sln | 7 + .../App.axaml.cs | 8 + .../Program.cs | 31 ++- ...amTools.Client.Desktop.Avalonia.App.csproj | 16 +- .../Windows/MessageBox.cs | 7 + .../LinuxDesktopPlatformServiceImpl.cs | 8 +- .../MacDesktopPlatformServiceImpl.cs | 9 +- .../WindowsDesktopPlatformServiceImpl.cs | 23 ++- ...ols.Client.Desktop.Platform.Windows.csproj | 4 + .../IDesktopPlatformService.cs | 13 +- .../DesktopPlatformServiceImpl.cs | 9 - .../Extensions/ProcessExtensions.cs | 26 +++ .../Extensions/StartupArgsExtensions.cs | 52 +++++ .../ServiceCollectionExtensions.cs | 16 +- .../Services/OperationResult.cs | 102 ++++++++++ .../Services/OperationResultType.cs | 65 +++++++ ...plication.SteamTools.Client.Desktop.csproj | 12 +- .../TarGZipHelper.cs | 108 +++++++++++ .../UI/AppHelper.cs | 109 ++++++++++- .../nlog.config | 22 +++ System.Application.SteamTools/Constants.cs | 11 ++ .../Extensions/AsymmetricCipherKeyPair.cs | 6 + .../Extensions/X509Certificate2Extensions.cs | 69 +++++++ .../System.Application.SteamTools.csproj | 6 +- System.Common.CoreLib/DeviceIdiom.cs | 2 +- .../Extensions/EnumerableExtensions.cs | 54 ++++++ .../Extensions/MatchExtensions.cs | 24 +++ .../Extensions/StreamExtensions.cs | 93 +++++++++ .../Extensions/StringExtensions.Trim.cs | 30 +++ .../Extensions/StringExtensions.cs | 152 ++++++++++++--- System.Common.CoreLib/Platform.cs | 2 +- .../System.Common.CoreLib.csproj | 20 +- System.Common.CoreLib/UnixTimestamp.cs | 19 +- Win7Troubleshoot/NullableAttributes.cs | 17 ++ Win7Troubleshoot/Program.cs | 17 +- Win7Troubleshoot/Properties/SR.Designer.cs | 9 + Win7Troubleshoot/Properties/SR.en.resx | 3 + Win7Troubleshoot/Properties/SR.resx | 3 + Win7Troubleshoot/Properties/SR.zh-Hant.resx | 3 + source/SteamTool.Core/Common/Common.cs | 5 +- source/SteamTool.Core/Common/EnumerableEx.cs | 91 ++++----- source/SteamTool.Core/Common/GuidRandom.cs | 1 + source/SteamTool.Core/Common/Md5Method.cs | 1 + 49 files changed, 1581 insertions(+), 138 deletions(-) create mode 100644 Packager/Form1.Designer.cs create mode 100644 Packager/Form1.cs create mode 100644 Packager/Form1.resx create mode 100644 Packager/Packager.csproj create mode 100644 Packager/Program.cs delete mode 100644 System.Application.SteamTools.Client.Desktop.Platform/Implementation/DesktopPlatformServiceImpl.cs create mode 100644 System.Application.SteamTools.Client.Desktop/Extensions/ProcessExtensions.cs create mode 100644 System.Application.SteamTools.Client.Desktop/Extensions/StartupArgsExtensions.cs create mode 100644 System.Application.SteamTools.Client.Desktop/Services/OperationResult.cs create mode 100644 System.Application.SteamTools.Client.Desktop/Services/OperationResultType.cs create mode 100644 System.Application.SteamTools.Client.Desktop/TarGZipHelper.cs create mode 100644 System.Application.SteamTools.Client.Desktop/nlog.config create mode 100644 System.Application.SteamTools/Constants.cs create mode 100644 System.Application.SteamTools/Extensions/AsymmetricCipherKeyPair.cs create mode 100644 System.Application.SteamTools/Extensions/X509Certificate2Extensions.cs create mode 100644 System.Common.CoreLib/Extensions/MatchExtensions.cs create mode 100644 System.Common.CoreLib/Extensions/StreamExtensions.cs create mode 100644 System.Common.CoreLib/Extensions/StringExtensions.Trim.cs create mode 100644 Win7Troubleshoot/NullableAttributes.cs diff --git a/Directory.Build.props b/Directory.Build.props index 932b68adea9..080b20f8835 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,16 +1,19 @@ - - none - false - 9.0 enable false - + + + SIGN_ASSEMBLY;$(DefineConstants) true false ..\Unicorn.pfx + + + none + false + \ No newline at end of file diff --git a/Packager/Form1.Designer.cs b/Packager/Form1.Designer.cs new file mode 100644 index 00000000000..0b7e39a27d0 --- /dev/null +++ b/Packager/Form1.Designer.cs @@ -0,0 +1,123 @@ + +namespace Packager +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.button1 = new System.Windows.Forms.Button(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); + this.button2 = new System.Windows.Forms.Button(); + this.richTextBox1 = new System.Windows.Forms.RichTextBox(); + this.button3 = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // button1 + // + this.button1.Location = new System.Drawing.Point(12, 12); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(64, 72); + this.button1.TabIndex = 0; + this.button1.Text = "Select Folder"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.OnBtnSelectPathClick); + // + // textBox1 + // + this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBox1.Location = new System.Drawing.Point(82, 12); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(706, 72); + this.textBox1.TabIndex = 1; + // + // openFileDialog1 + // + this.openFileDialog1.FileName = "openFileDialog1"; + // + // button2 + // + this.button2.Location = new System.Drawing.Point(12, 90); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(64, 72); + this.button2.TabIndex = 2; + this.button2.Text = "Create"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.OnBtnCreateClick); + // + // richTextBox1 + // + this.richTextBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.richTextBox1.Location = new System.Drawing.Point(82, 90); + this.richTextBox1.Name = "richTextBox1"; + this.richTextBox1.Size = new System.Drawing.Size(706, 348); + this.richTextBox1.TabIndex = 3; + this.richTextBox1.Text = ""; + // + // button3 + // + this.button3.Location = new System.Drawing.Point(12, 168); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(64, 72); + this.button3.TabIndex = 4; + this.button3.Text = "Unpack"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.OnBtnUnpackClick); + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.button3); + this.Controls.Add(this.richTextBox1); + this.Controls.Add(this.button2); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.button1); + this.Name = "Form1"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Packager"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button button1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.OpenFileDialog openFileDialog1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.RichTextBox richTextBox1; + private System.Windows.Forms.Button button3; + } +} + diff --git a/Packager/Form1.cs b/Packager/Form1.cs new file mode 100644 index 00000000000..861d9d0e5e3 --- /dev/null +++ b/Packager/Form1.cs @@ -0,0 +1,180 @@ +using ICSharpCode.SharpZipLib.Tar; +using System; +using System.Application; +using System.IO; +using System.Linq; +using System.Windows.Forms; + +namespace Packager +{ + public partial class Form1 : Form + { + readonly string app_path = @"\System.Application.SteamTools.Client.Desktop.Avalonia.App\bin\Release\Publish\win-x64"; + + static string GetPath(string path) + { + if (Path.DirectorySeparatorChar == '\\') return path; + return path.Replace('\\', Path.DirectorySeparatorChar); + } + + public Form1() + { + InitializeComponent(); + textBox1.Text = GetPath(GetProjectPath() + app_path); + } + + static string GetProjectPath(string? path = null) + { + path ??= AppContext.BaseDirectory; + if (!Directory.GetFiles(path, "*.sln").Any()) + { + var parent = Directory.GetParent(path); + if (parent == null) return string.Empty; + return GetProjectPath(parent.FullName); + } + return path; + } + + void OnBtnSelectPathClick(object sender, EventArgs e) + { + if (openFileDialog1.ShowDialog() == DialogResult.OK) + { + textBox1.Text = Path.GetDirectoryName(openFileDialog1.FileName); + } + } + + string? filePath = null; + + private void OnBtnCreateClick(object sender, EventArgs e) + { + var dirPath = textBox1.Text; + var parent = Directory.GetParent(dirPath)?.FullName; + if (parent != null) + { + filePath = Path.Combine(parent, DateTime.Now.ToString("yyyyMMddHHmmssfffffff")) + FileEx.TAR_GZ; + TarGZipHelper.Create(filePath, dirPath, progress: ShowTarProgressMessage); + } + else + { + richTextBox1.AppendText("Fail, Parent is null"); + richTextBox1.AppendText(Environment.NewLine); + } + } + + void ShowTarProgressMessage(TarArchive archive, TarEntry entry, string message) + { + if (entry.TarHeader.TypeFlag != TarHeader.LF_NORMAL && entry.TarHeader.TypeFlag != TarHeader.LF_OLDNORM) + { + richTextBox1.AppendText("Entry type " + (char)entry.TarHeader.TypeFlag + " found!"); + richTextBox1.AppendText(Environment.NewLine); + } + richTextBox1.AppendText(entry.Name + " " + message); + richTextBox1.AppendText(Environment.NewLine); + string modeString = DecodeType(entry.TarHeader.TypeFlag, entry.Name.EndsWith("/")) + DecodeMode(entry.TarHeader.Mode); + string userString = (string.IsNullOrEmpty(entry.UserName)) ? entry.UserId.ToString() : entry.UserName; + string groupString = (string.IsNullOrEmpty(entry.GroupName)) ? entry.GroupId.ToString() : entry.GroupName; + richTextBox1.AppendText(string.Format("{0} {1}/{2} {3,8} {4:yyyy-MM-dd HH:mm:ss}", modeString, userString, groupString, entry.Size, entry.ModTime.ToLocalTime())); + richTextBox1.AppendText(Environment.NewLine); + } + + static string DecodeType(int type, bool slashTerminated) + { + string result = "?"; + switch (type) + { + case TarHeader.LF_OLDNORM: // -jr- TODO this decoding is incomplete, not all possible known values are decoded... + case TarHeader.LF_NORMAL: + case TarHeader.LF_LINK: + if (slashTerminated) + result = "d"; + else + result = "-"; + break; + + case TarHeader.LF_DIR: + result = "d"; + break; + + case TarHeader.LF_GNU_VOLHDR: + result = "V"; + break; + + case TarHeader.LF_GNU_MULTIVOL: + result = "M"; + break; + + case TarHeader.LF_CONTIG: + result = "C"; + break; + + case TarHeader.LF_FIFO: + result = "p"; + break; + + case TarHeader.LF_SYMLINK: + result = "l"; + break; + + case TarHeader.LF_CHR: + result = "c"; + break; + + case TarHeader.LF_BLK: + result = "b"; + break; + } + + return result; + } + + static string DecodeMode(int mode) + { + + const int S_ISUID = 0x0800; + const int S_ISGID = 0x0400; + const int S_ISVTX = 0x0200; + + const int S_IRUSR = 0x0100; + const int S_IWUSR = 0x0080; + const int S_IXUSR = 0x0040; + + const int S_IRGRP = 0x0020; + const int S_IWGRP = 0x0010; + const int S_IXGRP = 0x0008; + + const int S_IROTH = 0x0004; + const int S_IWOTH = 0x0002; + const int S_IXOTH = 0x0001; + + + var result = new System.Text.StringBuilder(); + result.Append((mode & S_IRUSR) != 0 ? 'r' : '-'); + result.Append((mode & S_IWUSR) != 0 ? 'w' : '-'); + result.Append((mode & S_ISUID) != 0 + ? ((mode & S_IXUSR) != 0 ? 's' : 'S') + : ((mode & S_IXUSR) != 0 ? 'x' : '-')); + result.Append((mode & S_IRGRP) != 0 ? 'r' : '-'); + result.Append((mode & S_IWGRP) != 0 ? 'w' : '-'); + result.Append((mode & S_ISGID) != 0 + ? ((mode & S_IXGRP) != 0 ? 's' : 'S') + : ((mode & S_IXGRP) != 0 ? 'x' : '-')); + result.Append((mode & S_IROTH) != 0 ? 'r' : '-'); + result.Append((mode & S_IWOTH) != 0 ? 'w' : '-'); + result.Append((mode & S_ISVTX) != 0 + ? ((mode & S_IXOTH) != 0 ? 't' : 'T') + : ((mode & S_IXOTH) != 0 ? 'x' : '-')); + + return result.ToString(); + } + + private void OnBtnUnpackClick(object sender, EventArgs e) + { + if (filePath != null) + { + var dirName = Path.GetFileName(filePath).Split('.').First(); + TarGZipHelper.Unpack(filePath, + Path.Combine(Path.GetDirectoryName(filePath).ThrowIsNull(nameof(filePath)), dirName), ShowTarProgressMessage); + } + } + } +} \ No newline at end of file diff --git a/Packager/Form1.resx b/Packager/Form1.resx new file mode 100644 index 00000000000..f298a7be809 --- /dev/null +++ b/Packager/Form1.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Packager/Packager.csproj b/Packager/Packager.csproj new file mode 100644 index 00000000000..beeff6c71c3 --- /dev/null +++ b/Packager/Packager.csproj @@ -0,0 +1,35 @@ + + + + WinExe + net5.0-windows + true + ..\System.Application.SteamTools.Client.Desktop.Avalonia.App\Assets\Icon.ico + + + + + Properties\AssemblyInfo.cs + + + Properties\ThisAssembly.cs + + + Utils\TarGZipHelper.cs + + + Utils\ObjectExtensions.cs + + + Utils\StringExtensions.Trim.cs + + + Utils\FileEx.cs + + + + + + + + \ No newline at end of file diff --git a/Packager/Program.cs b/Packager/Program.cs new file mode 100644 index 00000000000..72c4c634022 --- /dev/null +++ b/Packager/Program.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Packager +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/SteamToolsV1.2+.sln b/SteamToolsV1.2+.sln index 8936e4ab241..736ef08a0ee 100644 --- a/SteamToolsV1.2+.sln +++ b/SteamToolsV1.2+.sln @@ -67,6 +67,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Application.SteamToo EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Win7Troubleshoot", "Win7Troubleshoot\Win7Troubleshoot.csproj", "{60530AF8-4790-4A85-BCE2-C5673E9C601B}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Packager", "Packager\Packager.csproj", "{5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -155,6 +157,10 @@ Global {60530AF8-4790-4A85-BCE2-C5673E9C601B}.Debug|Any CPU.Build.0 = Debug|Any CPU {60530AF8-4790-4A85-BCE2-C5673E9C601B}.Release|Any CPU.ActiveCfg = Release|Any CPU {60530AF8-4790-4A85-BCE2-C5673E9C601B}.Release|Any CPU.Build.0 = Release|Any CPU + {5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5A539932-2EB9-40F6-A4C1-94E5ECAB3B34}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -186,6 +192,7 @@ Global {948C1EA8-12DB-4F8A-A190-8615DFBD9FE4} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3} {141532E1-540E-4E50-8723-96936C191281} = {B43459A1-709B-4623-9677-AAC2FEE4FBA3} {60530AF8-4790-4A85-BCE2-C5673E9C601B} = {1460800B-D9ED-4147-B1E7-ABF502BEF59A} + {5A539932-2EB9-40F6-A4C1-94E5ECAB3B34} = {1460800B-D9ED-4147-B1E7-ABF502BEF59A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3833E7C5-69BC-4CB3-92CE-A8854AA35D8A} diff --git a/System.Application.SteamTools.Client.Desktop.Avalonia.App/App.axaml.cs b/System.Application.SteamTools.Client.Desktop.Avalonia.App/App.axaml.cs index d269ceda50d..19b8f91519f 100644 --- a/System.Application.SteamTools.Client.Desktop.Avalonia.App/App.axaml.cs +++ b/System.Application.SteamTools.Client.Desktop.Avalonia.App/App.axaml.cs @@ -4,6 +4,7 @@ using System.Application.UI.ViewModels; using System.Application.UI.Views; using System.IO; +using System.Windows; using AvaloniaApplication = Avalonia.Application; namespace System.Application.UI @@ -30,6 +31,13 @@ public override void OnFrameworkInitializationCompleted() if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { + if (!AppHelper.IsOfficialChannelPackage) + { + MessageBox.Show("The program currently running is not from the official channel.", "Warning", + MessageBoxButton.OK, + MessageBoxImage.Warning); + } + desktop.MainWindow = new MainWindow { DataContext = DataContext = DI.Get(), diff --git a/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs b/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs index de1e239033c..32eb1c13dbc 100644 --- a/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs +++ b/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs @@ -1,8 +1,7 @@ using Avalonia; using Avalonia.ReactiveUI; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; +using NLog; using System.Application.Models; using System.Application.Services.Implementation; using System.Application.UI.ViewModels; @@ -17,10 +16,26 @@ static class Program [STAThread] static void Main(string[] args) { - FileSystemDesktop.InitFileSystem(); - ModelValidatorProvider.Init(); - DI.Init(ConfigureServices); - BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + var logger = LogManager.GetCurrentClassLogger(); + try + { + FileSystemDesktop.InitFileSystem(); + ModelValidatorProvider.Init(); + DI.Init(ConfigureServices); + BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + } + catch (Exception ex) + { + AppHelper.EnableLogger = true; + // NLog: catch any exception and log it. + logger.Error(ex, "Stopped program because of exception"); + throw; + } + finally + { + // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux) + LogManager.Shutdown(); + } } // Avalonia configuration, don't remove; also used by visual designer. @@ -34,8 +49,8 @@ static AppBuilder BuildAvaloniaApp() static void ConfigureServices(IServiceCollection services) { - // 空日志实现,需要写一个实现替换 - services.AddLogging(l => l.AddProvider(NullLoggerProvider.Instance)); + // 添加日志实现 + services.AddDesktopLogging(); // 模型验证框架 services.TryAddModelValidator(); diff --git a/System.Application.SteamTools.Client.Desktop.Avalonia.App/System.Application.SteamTools.Client.Desktop.Avalonia.App.csproj b/System.Application.SteamTools.Client.Desktop.Avalonia.App/System.Application.SteamTools.Client.Desktop.Avalonia.App.csproj index 64658bdcfc7..f44323eda9a 100644 --- a/System.Application.SteamTools.Client.Desktop.Avalonia.App/System.Application.SteamTools.Client.Desktop.Avalonia.App.csproj +++ b/System.Application.SteamTools.Client.Desktop.Avalonia.App/System.Application.SteamTools.Client.Desktop.Avalonia.App.csproj @@ -18,22 +18,22 @@ - - - - + + + + - + - + - + @@ -49,7 +49,7 @@ Designer - + diff --git a/System.Application.SteamTools.Client.Desktop.Avalonia/Windows/MessageBox.cs b/System.Application.SteamTools.Client.Desktop.Avalonia/Windows/MessageBox.cs index 6c2119c5563..72e68e480d3 100644 --- a/System.Application.SteamTools.Client.Desktop.Avalonia/Windows/MessageBox.cs +++ b/System.Application.SteamTools.Client.Desktop.Avalonia/Windows/MessageBox.cs @@ -97,6 +97,13 @@ public static async Task ShowAsync( return GetResult(result); } + /// + public static async void Show( + string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon) + { + await ShowAsync(messageBoxText, caption, button, icon); + } + static Window? GetWindow(IMsBoxWindow window) { var _window = window.GetType().GetField("_window", BindingFlags.NonPublic | BindingFlags.Instance); diff --git a/System.Application.SteamTools.Client.Desktop.Platform.Linux/Implementation/LinuxDesktopPlatformServiceImpl.cs b/System.Application.SteamTools.Client.Desktop.Platform.Linux/Implementation/LinuxDesktopPlatformServiceImpl.cs index 157df67d040..e49170de0ac 100644 --- a/System.Application.SteamTools.Client.Desktop.Platform.Linux/Implementation/LinuxDesktopPlatformServiceImpl.cs +++ b/System.Application.SteamTools.Client.Desktop.Platform.Linux/Implementation/LinuxDesktopPlatformServiceImpl.cs @@ -1,10 +1,16 @@ -namespace System.Application.Services.Implementation +using System.Diagnostics; + +namespace System.Application.Services.Implementation { internal sealed class LinuxDesktopPlatformServiceImpl : IDesktopPlatformService { public void SetResizeMode(IntPtr hWnd, int value) { + } + public string GetCommandLineArgs(Process process) + { + return string.Empty; } } } \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop.Platform.Mac/Implementation/MacDesktopPlatformServiceImpl.cs b/System.Application.SteamTools.Client.Desktop.Platform.Mac/Implementation/MacDesktopPlatformServiceImpl.cs index 3a3fb55f5fb..b7ebb71bdb0 100644 --- a/System.Application.SteamTools.Client.Desktop.Platform.Mac/Implementation/MacDesktopPlatformServiceImpl.cs +++ b/System.Application.SteamTools.Client.Desktop.Platform.Mac/Implementation/MacDesktopPlatformServiceImpl.cs @@ -1,9 +1,16 @@ -namespace System.Application.Services.Implementation +using System.Diagnostics; + +namespace System.Application.Services.Implementation { internal sealed class MacDesktopPlatformServiceImpl : IDesktopPlatformService { public void SetResizeMode(IntPtr hWnd, int value) { } + + public string GetCommandLineArgs(Process process) + { + return string.Empty; + } } } \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop.Platform.Windows/Implementation/WindowsDesktopPlatformServiceImpl.cs b/System.Application.SteamTools.Client.Desktop.Platform.Windows/Implementation/WindowsDesktopPlatformServiceImpl.cs index 88201cc013c..0e33d8fca12 100644 --- a/System.Application.SteamTools.Client.Desktop.Platform.Windows/Implementation/WindowsDesktopPlatformServiceImpl.cs +++ b/System.Application.SteamTools.Client.Desktop.Platform.Windows/Implementation/WindowsDesktopPlatformServiceImpl.cs @@ -1,4 +1,8 @@ -using System.Runtime.InteropServices; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Management; +using System.Runtime.InteropServices; using System.Runtime.Versioning; namespace System.Application.Services.Implementation @@ -86,5 +90,22 @@ public void SetResizeMode(IntPtr hWnd, int value) } #endregion + + public string GetCommandLineArgs(Process process) + { + try + { + using var searcher = new ManagementObjectSearcher( + "SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + process.Id); + using var objects = searcher.Get(); + var @object = objects.Cast().SingleOrDefault(); + return @object?["CommandLine"]?.ToString() ?? ""; + } + catch (Win32Exception ex) when ((uint)ex.ErrorCode == 0x80004005) + { + // 没有对该进程的安全访问权限。 + return string.Empty; + } + } } } \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop.Platform.Windows/System.Application.SteamTools.Client.Desktop.Platform.Windows.csproj b/System.Application.SteamTools.Client.Desktop.Platform.Windows/System.Application.SteamTools.Client.Desktop.Platform.Windows.csproj index 941710b1428..fedd00562cb 100644 --- a/System.Application.SteamTools.Client.Desktop.Platform.Windows/System.Application.SteamTools.Client.Desktop.Platform.Windows.csproj +++ b/System.Application.SteamTools.Client.Desktop.Platform.Windows/System.Application.SteamTools.Client.Desktop.Platform.Windows.csproj @@ -11,6 +11,10 @@ + + + + diff --git a/System.Application.SteamTools.Client.Desktop.Platform/IDesktopPlatformService.cs b/System.Application.SteamTools.Client.Desktop.Platform/IDesktopPlatformService.cs index f8ebaef50f2..19cf4e6317f 100644 --- a/System.Application.SteamTools.Client.Desktop.Platform/IDesktopPlatformService.cs +++ b/System.Application.SteamTools.Client.Desktop.Platform/IDesktopPlatformService.cs @@ -1,4 +1,5 @@ -using ResizeMode = System.Int32; +using System.Diagnostics; +using ResizeMode = System.Int32; namespace System.Application.Services { @@ -6,6 +7,16 @@ public interface IDesktopPlatformService { void SetResizeMode(IntPtr hWnd, ResizeMode value); + /// + /// 获取一个正在运行的进程的命令行参数。 + /// 与 一样,使用此方法获取的参数是包含应用程序路径的。 + /// 关于 可参见: + /// .NET 命令行参数包含应用程序路径吗?https://blog.walterlv.com/post/when-will-the-command-line-args-contain-the-executable-path.html + /// + /// 一个正在运行的进程。 + /// 表示应用程序运行命令行参数的字符串。 + string GetCommandLineArgs(Process process); + public const ResizeMode ResizeMode_NoResize = 0; public const ResizeMode ResizeMode_CanMinimize = 1; public const ResizeMode ResizeMode_CanResize = 2; diff --git a/System.Application.SteamTools.Client.Desktop.Platform/Implementation/DesktopPlatformServiceImpl.cs b/System.Application.SteamTools.Client.Desktop.Platform/Implementation/DesktopPlatformServiceImpl.cs deleted file mode 100644 index c6512b0ff1c..00000000000 --- a/System.Application.SteamTools.Client.Desktop.Platform/Implementation/DesktopPlatformServiceImpl.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace System.Application.Services.Implementation -{ - public class DesktopPlatformServiceImpl : IDesktopPlatformService - { - public void SetResizeMode(IntPtr hWnd, int value) - { - } - } -} \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop/Extensions/ProcessExtensions.cs b/System.Application.SteamTools.Client.Desktop/Extensions/ProcessExtensions.cs new file mode 100644 index 00000000000..eb8be93399d --- /dev/null +++ b/System.Application.SteamTools.Client.Desktop/Extensions/ProcessExtensions.cs @@ -0,0 +1,26 @@ +using System.Application.Services; +using System.Diagnostics; + +namespace System.Application.Extensions +{ + /// + /// 为 类型提供扩展方法 + /// + public static class ProcessExtensions + { + /// + public static string GetCommandLineArgs(this Process process) + { + try + { + var p = DI.Get(); + return p.GetCommandLineArgs(process); + } + catch (InvalidOperationException) + { + // 进程已退出。 + return string.Empty; + } + } + } +} \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop/Extensions/StartupArgsExtensions.cs b/System.Application.SteamTools.Client.Desktop/Extensions/StartupArgsExtensions.cs new file mode 100644 index 00000000000..5a8c3d28803 --- /dev/null +++ b/System.Application.SteamTools.Client.Desktop/Extensions/StartupArgsExtensions.cs @@ -0,0 +1,52 @@ +// ReSharper disable once CheckNamespace +namespace System.Application +{ + public static class StartupArgsExtensions + { + public static bool ContainsArg(this string[] args, string arg) + { + for (var i = 0; i < args.Length; i++) + { + if (string.Equals(args[i], arg, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + return false; + } + + public static bool ContainsArg(this string[] args, string arg, out string value) + { + value = ""; + for (var i = 0; i < args.Length; i++) + { + if (string.Equals(args[i], arg, StringComparison.OrdinalIgnoreCase)) + { + if (args.Length > i + 1) + { + value = args[i + 1]; + return true; + } + } + } + return false; + } + + public static bool ContainsArg(this string[] args, string arg, out int value) + { + value = 0; + for (var i = 0; i < args.Length; i++) + { + if (string.Equals(args[i], arg, StringComparison.OrdinalIgnoreCase)) + { + if (args.Length > i + 1 && int.TryParse(args[i + 1], out int val)) + { + value = val; + return true; + } + } + } + return false; + } + } +} \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs b/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs index f4f1126fc81..eef5e5a2f9a 100644 --- a/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs +++ b/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs @@ -1,8 +1,7 @@ -using Microsoft.Extensions.DependencyInjection.Extensions; -using System.Application.Services; +using System.Application.Services; using System.Application.Services.Implementation; +using System.Application.UI; using System.Application.UI.ViewModels; -using System.Security; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection @@ -43,5 +42,16 @@ public static IServiceCollection AddViewModel(this IServiceCollectio services.AddSingleton(); return services; } + + /// + /// 添加桌面端日志实现 + /// + /// + /// + public static IServiceCollection AddDesktopLogging(this IServiceCollection services) + { + services.AddLogging(AppHelper.Configure); + return services; + } } } \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop/Services/OperationResult.cs b/System.Application.SteamTools.Client.Desktop/Services/OperationResult.cs new file mode 100644 index 00000000000..ab02126e8cc --- /dev/null +++ b/System.Application.SteamTools.Client.Desktop/Services/OperationResult.cs @@ -0,0 +1,102 @@ +namespace System.Application.Services +{ + /// + /// 操作结果信息类,对操作结果进行封装 + /// + /// + public class OperationResult + { + #region 构造函数 + + public OperationResult() + { + ResultType = OperationResultType.Error; + } + + /// + /// 初始化一个 操作结果信息类 的新实例 + /// + /// 操作结果类型 + public OperationResult(OperationResultType resultType) + { + ResultType = resultType; + } + + /// + /// 初始化一个 定义返回消息的操作结果信息类 的新实例 + /// + /// 操作结果类型 + /// 返回消息 + public OperationResult(OperationResultType resultType, string message) + : this(resultType) + { + Message = message; + } + + /// + /// 初始化一个 定义返回消息与附加数据的操作结果信息类 的新实例 + /// + /// 操作结果类型 + /// 返回消息 + /// 返回数据 + public OperationResult(OperationResultType resultType, string message, T appendData) + : this(resultType, message) + { + AppendData = appendData; + } + + /// + /// 初始化一个 定义返回消息与日志消息的操作结果信息类 的新实例 + /// + /// 操作结果类型 + /// 返回消息 + /// 日志记录消息 + public OperationResult(OperationResultType resultType, string message, string logMessage) + : this(resultType, message) + { + LogMessage = logMessage; + } + + /// + /// 初始化一个 定义返回消息、日志消息与附加数据的操作结果信息类 的新实例 + /// + /// 操作结果类型 + /// 返回消息 + /// 日志记录消息 + /// 返回数据 + public OperationResult(OperationResultType resultType, string message, string logMessage, T appendData) + : this(resultType, message, logMessage) + { + AppendData = appendData; + } + + #endregion + + #region 属性 + + /// + /// 获取或设置 操作结果类型 + /// + public OperationResultType ResultType { get; set; } + + /// + /// 获取或设置 操作返回信息 + /// + public string? Message { get; set; } + + /// + /// 获取或设置 操作返回的日志消息,用于记录日志 + /// + public string? LogMessage { get; set; } + + /// + /// 获取或设置 操作结果附加信息 + /// + public T? AppendData { get; set; } + + #endregion + } + + /// + public class OperationResult : OperationResult { } +} \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop/Services/OperationResultType.cs b/System.Application.SteamTools.Client.Desktop/Services/OperationResultType.cs new file mode 100644 index 00000000000..d748c7d0d48 --- /dev/null +++ b/System.Application.SteamTools.Client.Desktop/Services/OperationResultType.cs @@ -0,0 +1,65 @@ +using System.ComponentModel; + +namespace System.Application.Services +{ + /// + /// 表示操作结果的枚举 + /// + [Description("操作结果的枚举")] + public enum OperationResultType + { + /// + /// 0 - 操作成功 + /// + [Description("操作成功。")] + Success, + + /// + /// 1 - 操作取消或操作没引发任何变化 + /// + [Description("操作没有引发任何变化,提交取消。")] + NoChanged, + + /// + /// 2 - 参数错误 + /// + [Description("参数错误。")] + ParamError, + + /// + /// 3 - 指定参数的数据不存在 + /// + [Description("指定参数的数据不存在。")] + QueryNull, + + /// + /// 4 - 权限不足 + /// + [Description("当前用户权限不足,不能继续操作。")] + PurviewLack, + + /// + /// 5 - 登录超时 + /// + [Description("登录超时")] + LoginTimeOut, + + /// + /// 6 - 非法操作 + /// + [Description("非法操作。")] + IllegalOperation, + + /// + /// 7 - 警告 + /// + [Description("警告")] + Warning, + + /// + /// 8 - 操作引发错误 + /// + [Description("操作引发错误。")] + Error, + } +} \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop/System.Application.SteamTools.Client.Desktop.csproj b/System.Application.SteamTools.Client.Desktop/System.Application.SteamTools.Client.Desktop.csproj index f02a4ca4b1d..64bd1401612 100644 --- a/System.Application.SteamTools.Client.Desktop/System.Application.SteamTools.Client.Desktop.csproj +++ b/System.Application.SteamTools.Client.Desktop/System.Application.SteamTools.Client.Desktop.csproj @@ -1,4 +1,4 @@ - + net5.0 @@ -12,7 +12,10 @@ + + + @@ -37,7 +40,8 @@ - + + PreserveNewest + - - + \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop/TarGZipHelper.cs b/System.Application.SteamTools.Client.Desktop/TarGZipHelper.cs new file mode 100644 index 00000000000..dc7d9b8bf44 --- /dev/null +++ b/System.Application.SteamTools.Client.Desktop/TarGZipHelper.cs @@ -0,0 +1,108 @@ +using ICSharpCode.SharpZipLib.GZip; +using ICSharpCode.SharpZipLib.Tar; +using ICSharpCode.SharpZipLib.Zip.Compression; +using System.IO; +using System.Text; + +namespace System.Application +{ + public static class TarGZipHelper + { + /// + /// 创建压缩包文件 + /// + /// 要创建的文件路径 + /// 要打包的目录 + /// 压缩等级,取值范围在 ~ + /// + public static bool Create(string filePath, string dirPath, int level = Deflater.BEST_COMPRESSION, ProgressMessageHandler? progress = null) + { + if (!filePath.EndsWith(FileEx.TAR_GZ)) filePath += FileEx.TAR_GZ; + if (File.Exists(filePath)) return false; + if (!Directory.Exists(dirPath)) return false; + + using var fs = File.Create(filePath); + using var s = new GZipOutputStream(fs); + s.SetLevel(level); + using var archive = TarArchive.CreateOutputTarArchive(s, TarBuffer.DefaultBlockFactor, Encoding.UTF8); + if (progress != null) archive.ProgressMessageEvent += progress; + + HandleFiles(dirPath); + HandleDirs(dirPath); + + void HandleFiles(string dirPath_) + { + foreach (var file in Directory.GetFiles(dirPath_)) + { + var entry = TarEntry.CreateEntryFromFile(file); + entry.Name = file.TrimStart(dirPath).Trim(Path.DirectorySeparatorChar); + archive.WriteEntry(entry, false); + } + } + + void HandleDirs(string dirPath_) + { + foreach (var dir in Directory.GetDirectories(dirPath_)) + { + HandleFiles(dir); + } + } + + return true; + } + + /// + /// 解压压缩包文件 + /// + /// + /// + /// + public static bool Unpack(string filePath, string dirPath, ProgressMessageHandler? progress = null) + { + if (!File.Exists(filePath)) return false; + if (Directory.Exists(dirPath)) return false; + + using var fs = File.OpenRead(filePath); + Directory.CreateDirectory(dirPath); + using var s = new GZipInputStream(fs); + using var archive = TarArchive.CreateInputTarArchive(s, Encoding.UTF8); + if (progress != null) archive.ProgressMessageEvent += progress; + archive.ExtractContents(dirPath); + return true; + } + } + +#if DEBUG + + [Obsolete("use TarGZipHelper", true)] + public static class ZipHelper + { + [Obsolete("use TarGZipHelper.Create", true)] + public static void PackFiles(string filename, string directory) + { + } + + [Obsolete("use TarGZipHelper.Unpack", true)] + public static bool UnpackFiles(string file, string dir) + { + return default; + } + } + + [Obsolete("use TarGZipHelper", true)] + public static class ClassZip + { + [Obsolete("use TarGZipHelper.Create", true)] + public static bool Zip(string FileToZip, string ZipedFile, int level) + { + return default; + } + + [Obsolete("use TarGZipHelper.Unpack", true)] + public static void UnZip(string FileToUpZip, string ZipedFolder) + { + } + } + +#endif +} \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop/UI/AppHelper.cs b/System.Application.SteamTools.Client.Desktop/UI/AppHelper.cs index 4062c0fa56b..aaa45b44c71 100644 --- a/System.Application.SteamTools.Client.Desktop/UI/AppHelper.cs +++ b/System.Application.SteamTools.Client.Desktop/UI/AppHelper.cs @@ -1,5 +1,14 @@ -using System.Diagnostics; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using NLog.Extensions.Logging; +using System.Diagnostics; using System.IO; +using System.Linq; +using System.Properties; +using LogLevel = Microsoft.Extensions.Logging.LogLevel; +using NInternalLogger = NLog.Common.InternalLogger; +using NLogLevel = NLog.LogLevel; +using NLogManager = NLog.LogManager; namespace System.Application.UI { @@ -23,5 +32,103 @@ static AppHelper() /// 获取当前主程序文件名,例如word.exe /// public static string ProgramName { get; } + + #region Logger + + const LogLevel DefaultLoggerMinLevel = ThisAssembly.Debuggable ? LogLevel.Debug : LogLevel.Error; + + /// + /// Convert log level to NLog variant. + /// + /// level to be converted. + /// + static NLogLevel ConvertLogLevel(LogLevel logLevel) => logLevel switch + { + // https://github.com/NLog/NLog.Extensions.Logging/blob/v1.7.0/src/NLog.Extensions.Logging/Logging/NLogLogger.cs#L416 + LogLevel.Trace => NLogLevel.Trace, + LogLevel.Debug => NLogLevel.Debug, + LogLevel.Information => NLogLevel.Info, + LogLevel.Warning => NLogLevel.Warn, + LogLevel.Error => NLogLevel.Error, + LogLevel.Critical => NLogLevel.Fatal, + LogLevel.None => NLogLevel.Off, + _ => NLogLevel.Debug, + }; + + static void SetNLoggerMinLevel(LogLevel logLevel) => SetNLoggerMinLevel(ConvertLogLevel(logLevel)); + + static void SetNLoggerMinLevel(NLogLevel logLevel) + { + NLogManager.GlobalThreshold = logLevel; + NInternalLogger.LogLevel = logLevel; + } + + /// + /// 日志过滤选项 + /// + static LoggerFilterOptions LoggerFilterOptions => DI.Get>().Value; + + internal static void Configure(ILoggingBuilder builder) + { + var logLevel = DefaultLoggerMinLevel; + builder.SetMinimumLevel(logLevel); + SetNLoggerMinLevel(logLevel); + + // 可以多个日志提供同时用,比如还可以在 Win 平台再添加一个 Windows 事件日志 + + builder.AddNLog(); // 添加 NLog 日志 + } + + /// + /// 日志最低等级 + /// + public static LogLevel LoggerMinLevel + { + get => LoggerFilterOptions.MinLevel; + set + { + LoggerFilterOptions.MinLevel = value; + SetNLoggerMinLevel(value); + } + } + + /// + /// 启用日志 + /// + public static bool EnableLogger + { + get => LoggerMinLevel < LogLevel.None; + set + { + LoggerMinLevel = value ? DefaultLoggerMinLevel : LogLevel.None; + } + } + + #endregion + + /// + /// 当前运行程序是否为官方渠道包 + /// + public static bool IsOfficialChannelPackage + { + get + { + var pk = typeof(AppHelper).Assembly.GetName().GetPublicKey(); + if (pk == null) return false; + var pkStr = ", PublicKey=" + string.Join(string.Empty, pk.Select(x => x.ToString("x2"))); + return pkStr == ThisAssembly.PublicKey; + } + } + +#if DEBUG + + [Obsolete("use EnableLogger", true)] + public static bool EnableTextLog + { + get => EnableLogger; + set => EnableLogger = value; + } + +#endif } } \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop/nlog.config b/System.Application.SteamTools.Client.Desktop/nlog.config new file mode 100644 index 00000000000..c7fa4bf1c65 --- /dev/null +++ b/System.Application.SteamTools.Client.Desktop/nlog.config @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System.Application.SteamTools/Constants.cs b/System.Application.SteamTools/Constants.cs new file mode 100644 index 00000000000..9e391a17306 --- /dev/null +++ b/System.Application.SteamTools/Constants.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Application +{ + public static class Constants + { + public const string HOST_TAG = "#Steam++"; + } +} diff --git a/System.Application.SteamTools/Extensions/AsymmetricCipherKeyPair.cs b/System.Application.SteamTools/Extensions/AsymmetricCipherKeyPair.cs new file mode 100644 index 00000000000..8f177aa9ca0 --- /dev/null +++ b/System.Application.SteamTools/Extensions/AsymmetricCipherKeyPair.cs @@ -0,0 +1,6 @@ +namespace System +{ + internal class AsymmetricCipherKeyPair + { + } +} \ No newline at end of file diff --git a/System.Application.SteamTools/Extensions/X509Certificate2Extensions.cs b/System.Application.SteamTools/Extensions/X509Certificate2Extensions.cs new file mode 100644 index 00000000000..4cfda64e6a1 --- /dev/null +++ b/System.Application.SteamTools/Extensions/X509Certificate2Extensions.cs @@ -0,0 +1,69 @@ +using Org.BouncyCastle.OpenSsl; +using Org.BouncyCastle.Security; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; + +// ReSharper disable once CheckNamespace +namespace System.Application +{ + public static class X509Certificate2Extensions + { + public static string GetPublicPemCertificateString(this X509Certificate2 @this) + { + StringBuilder builder = new StringBuilder(); + builder.AppendLine(Constants.HOST_TAG); + builder.AppendLine("-----BEGIN CERTIFICATE-----"); + builder.AppendLine( + Convert.ToBase64String(@this.RawData, Base64FormattingOptions.InsertLineBreaks)); + builder.AppendLine("-----END CERTIFICATE-----"); + builder.AppendLine(Constants.HOST_TAG); + return builder.ToString(); + } + + public static string GetPrivatePemCertificateString(this X509Certificate2 @this) + { + if (@this.PrivateKey is RSACryptoServiceProvider pkey) + { + var keyPair = DotNetUtilities.GetRsaKeyPair(pkey); + using TextWriter tw = new StreamWriter(Path.Combine(AppContext.BaseDirectory, @this.IssuerName.Name + ".key"), false, new UTF8Encoding(false)); + PemWriter pw = new PemWriter(tw); + pw.WriteObject(keyPair.Private); + tw.Flush(); + return tw.ToString(); + } + else + { + throw new InvalidCastException(nameof(X509Certificate2.PrivateKey)); + } + } + + public static List GetSubjectAlternativeNames(this X509Certificate2 certificate) + { + foreach (X509Extension extension in certificate.Extensions) + { + // Create an AsnEncodedData object using the extensions information. + AsnEncodedData asndata = new AsnEncodedData(extension.Oid, extension.RawData); + if (string.Equals(extension.Oid.FriendlyName, "Subject Alternative Name")) + { + return new List( + asndata.Format(true).Split(new string[] { Environment.NewLine, "DNS Name=" }, + StringSplitOptions.RemoveEmptyEntries)); + } + } + return new List(); + } + + public static void SaveCerCertificateFile(this X509Certificate2 @this, string pathOrName) + { + StringBuilder builder = new StringBuilder(); + builder.AppendLine("-----BEGIN CERTIFICATE-----"); + builder.AppendLine( + Convert.ToBase64String(@this.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks)); + builder.AppendLine("-----END CERTIFICATE-----"); + File.WriteAllText(pathOrName, builder.ToString(), new UTF8Encoding(false)); + } + } +} \ No newline at end of file diff --git a/System.Application.SteamTools/System.Application.SteamTools.csproj b/System.Application.SteamTools/System.Application.SteamTools.csproj index fe3aded4660..0bed1621fc0 100644 --- a/System.Application.SteamTools/System.Application.SteamTools.csproj +++ b/System.Application.SteamTools/System.Application.SteamTools.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -11,6 +11,10 @@ + + + + diff --git a/System.Common.CoreLib/DeviceIdiom.cs b/System.Common.CoreLib/DeviceIdiom.cs index adf66d4d594..245255cac61 100644 --- a/System.Common.CoreLib/DeviceIdiom.cs +++ b/System.Common.CoreLib/DeviceIdiom.cs @@ -12,7 +12,7 @@ public enum DeviceIdiom /// /// 未知 /// - Unknown = 0, + Unknown = 1, /// /// 手机 diff --git a/System.Common.CoreLib/Extensions/EnumerableExtensions.cs b/System.Common.CoreLib/Extensions/EnumerableExtensions.cs index d615d0c7936..7f45601cdc3 100644 --- a/System.Common.CoreLib/Extensions/EnumerableExtensions.cs +++ b/System.Common.CoreLib/Extensions/EnumerableExtensions.cs @@ -67,5 +67,59 @@ public static void AddRange(this IList ts, IEnumerable collection) } } } + + public static IEnumerable Distinct(this IEnumerable source, Func keySelector) + { + var set = new HashSet(EqualityComparer.Default); + + foreach (var item in source) + { + var key = keySelector(item); + if (set.Add(key)) yield return item; + } + } + + public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) + { + HashSet seenKeys = new HashSet(); + foreach (TSource element in source) + { + if (seenKeys.Add(keySelector(element))) + { + yield return element; + } + } + } + + /// + /// コレクションを展開し、メンバーの文字列表現を指定した区切り文字で連結した文字列を返します。 + /// + /// コレクションに含まれる任意の型。 + /// 対象のコレクション。 + /// セパレーターとして使用する文字列。 + /// コレクションの文字列表現を展開し、指定したセパレーターで連結した文字列。 + public static string ToString(this IEnumerable source, string separator) => string.Join(separator, source); + + /// + /// コレクションを展開し、メンバーの文字列表現を指定した区切り文字で連結した文字列を返します。 + /// + /// コレクションに含まれる任意の型。 + /// 対象のコレクション。 + /// セパレーターとして使用する文字列。 + /// コレクションの文字列表現を展開し、指定したセパレーターで連結した文字列。 + public static string ToString(this IEnumerable source, char separator) => string.Join(separator, source); + +#if DEBUG + + /// + /// シーケンスが null でなく、1 つ以上の要素を含んでいるかどうかを確認します。 + /// + [Obsolete("use Any_Nullable()", true)] + public static bool HasItems(this IEnumerable? source) + { + return source != null && source.Any(); + } + +#endif } } \ No newline at end of file diff --git a/System.Common.CoreLib/Extensions/MatchExtensions.cs b/System.Common.CoreLib/Extensions/MatchExtensions.cs new file mode 100644 index 00000000000..3f7f84d5186 --- /dev/null +++ b/System.Common.CoreLib/Extensions/MatchExtensions.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Text.RegularExpressions; + +// ReSharper disable once CheckNamespace +namespace System +{ + public static partial class MatchExtensions + { + public static string GetValue(this Match match, Func action) + { + if (action.Invoke(match)) return match.Value.Trim(); + else return ""; + } + + public static IEnumerable GetValues(this MatchCollection match, Func action) + { + foreach (Match item in match) + { + if (action.Invoke(item)) + yield return item.Value.Trim(); + } + } + } +} \ No newline at end of file diff --git a/System.Common.CoreLib/Extensions/StreamExtensions.cs b/System.Common.CoreLib/Extensions/StreamExtensions.cs new file mode 100644 index 00000000000..e174c3b8b6d --- /dev/null +++ b/System.Common.CoreLib/Extensions/StreamExtensions.cs @@ -0,0 +1,93 @@ +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; + +// ReSharper disable once CheckNamespace +namespace System +{ + public static class StreamExtensions + { + public static byte ReadValueU8(this Stream stream) + { + return (byte)stream.ReadByte(); + } + + public static int ReadValueS32(this Stream stream) + { + var data = new byte[4]; + int read = stream.Read(data, 0, 4); + Debug.Assert(read == 4); + return BitConverter.ToInt32(data, 0); + } + + public static uint ReadValueU32(this Stream stream) + { + var data = new byte[4]; + int read = stream.Read(data, 0, 4); + Debug.Assert(read == 4); + return BitConverter.ToUInt32(data, 0); + } + + public static ulong ReadValueU64(this Stream stream) + { + var data = new byte[8]; + int read = stream.Read(data, 0, 8); + Debug.Assert(read == 8); + return BitConverter.ToUInt64(data, 0); + } + + public static float ReadValueF32(this Stream stream) + { + var data = new byte[4]; + int read = stream.Read(data, 0, 4); + Debug.Assert(read == 4); + return BitConverter.ToSingle(data, 0); + } + + internal static string ReadStringInternalDynamic(this Stream stream, Encoding encoding, char end) + { + int characterSize = encoding.GetByteCount("e"); + Debug.Assert(characterSize == 1 || characterSize == 2 || characterSize == 4); + string characterEnd = end.ToString(CultureInfo.InvariantCulture); + + int i = 0; + var data = new byte[128 * characterSize]; + + while (true) + { + if (i + characterSize > data.Length) + { + Array.Resize(ref data, data.Length + (128 * characterSize)); + } + + int read = stream.Read(data, i, characterSize); + Debug.Assert(read == characterSize); + + if (encoding.GetString(data, i, characterSize) == characterEnd) + { + break; + } + + i += characterSize; + } + + if (i == 0) + { + return ""; + } + + return encoding.GetString(data, 0, i); + } + + public static string ReadStringAscii(this Stream stream) + { + return stream.ReadStringInternalDynamic(Encoding.ASCII, '\0'); + } + + public static string ReadStringUnicode(this Stream stream) + { + return stream.ReadStringInternalDynamic(Encoding.UTF8, '\0'); + } + } +} \ No newline at end of file diff --git a/System.Common.CoreLib/Extensions/StringExtensions.Trim.cs b/System.Common.CoreLib/Extensions/StringExtensions.Trim.cs new file mode 100644 index 00000000000..5abdda65616 --- /dev/null +++ b/System.Common.CoreLib/Extensions/StringExtensions.Trim.cs @@ -0,0 +1,30 @@ +// ReSharper disable once CheckNamespace +namespace System +{ + public static partial class StringExtensions + { + public static string TrimStart(this string s, string trimString) + { + if (trimString.StartsWith(trimString)) + { + return s[trimString.Length..]; + } + else + { + return s; + } + } + + public static string TrimEnd(this string s, string trimString) + { + if (trimString.EndsWith(trimString)) + { + return s.Substring(0, s.Length - trimString.Length); + } + else + { + return s; + } + } + } +} \ No newline at end of file diff --git a/System.Common.CoreLib/Extensions/StringExtensions.cs b/System.Common.CoreLib/Extensions/StringExtensions.cs index c92d08ebad0..4266c6662a8 100644 --- a/System.Common.CoreLib/Extensions/StringExtensions.cs +++ b/System.Common.CoreLib/Extensions/StringExtensions.cs @@ -1,5 +1,9 @@ using System.Collections.Generic; +using System.IO; +using System.IO.Compression; using System.Linq; +using System.Text; +using System.Text.RegularExpressions; // ReSharper disable once CheckNamespace namespace System @@ -151,30 +155,6 @@ static IEnumerable GetVersion(string s) #endregion - public static string TrimStart(this string s, string trimString) - { - if (trimString.StartsWith(trimString)) - { - return s[trimString.Length..]; - } - else - { - return s; - } - } - - public static string TrimEnd(this string s, string trimString) - { - if (trimString.EndsWith(trimString)) - { - return s.Substring(0, s.Length - trimString.Length); - } - else - { - return s; - } - } - #region 数字字母判断 /// @@ -215,5 +195,129 @@ public static string TrimEnd(this string s, string trimString) public static bool HasOther(this string input) => input?.Any(x => !(x >= 'a' && x <= 'z' || x >= 'A' && x <= 'Z' || x >= '0' && x <= '9')) ?? false; #endregion + + /// + /// 返回当前最后相对URL + /// + /// + /// + public static string GetLastRelativeUrl(this string url) + { + int index = url.LastIndexOf("/"); + + if (index != -1) + { + return url.Substring(0, index) + "/"; + } + else + { + return ""; + } + } + + /// + /// 移除字符串内所有\r \n \t + /// + /// + /// + public static string RemovePattern(this string s) + => s.Replace("\t", "").Replace("\r", "").Replace("\n", ""); + + /// + /// 获取两个字符串中间的字符串 + /// + /// 要处理的字符串,例 ABCD + /// 第1个字符串,例 AB + /// 第2个字符串,例 D + /// 是否包含标志字符串 + /// 例 返回C + public static string Substring(this string s, string left, string right, bool isContains = false) + { + int i1 = s.IndexOf(left); + if (i1 < 0) // 找不到返回空 + { + return ""; + } + + int i2 = s.IndexOf(right, i1 + left.Length); // 从找到的第1个字符串后再去找 + if (i2 < 0) // 找不到返回空 + { + return ""; + } + + if (isContains) return s.Substring(i1, i2 - i1 + left.Length); + else return s.Substring(i1 + left.Length, i2 - i1 - left.Length); + } + + /// + /// Converts a wildcard to a regex. + /// + /// The wildcard pattern to convert. + /// A regex equivalent of the given wildcard. + public static bool IsWildcard(this string str, string pattern) + => Regex.IsMatch(str, "^" + Regex.Escape(pattern) + .Replace("\\*", ".*") + .Replace("\\?", ".") + "$"); + + #region Compressor + + /// + /// Compresses the string. + /// + /// The text. + /// + public static string? CompressString(this string? text) + { + if (string.IsNullOrEmpty(text)) return null; + byte[] buffer = Encoding.UTF8.GetBytes(text); + var memoryStream = new MemoryStream(); + using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true)) + { + gZipStream.Write(buffer, 0, buffer.Length); + } + + memoryStream.Position = 0; + + var compressedData = new byte[memoryStream.Length]; + memoryStream.Read(compressedData, 0, compressedData.Length); + + var gZipBuffer = new byte[compressedData.Length + 4]; + Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length); + Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4); + return Convert.ToBase64String(gZipBuffer); + } + + /// + /// Decompresses the string. + /// + /// The compressed text. + /// + public static string? DecompressString(this string? compressedText) + { + if (string.IsNullOrEmpty(compressedText)) return null; + byte[] gZipBuffer = Convert.FromBase64String(compressedText); + using var memoryStream = new MemoryStream(); + int dataLength = BitConverter.ToInt32(gZipBuffer, 0); + memoryStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4); + + var buffer = new byte[dataLength]; + + memoryStream.Position = 0; + using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress)) + { + gZipStream.Read(buffer, 0, buffer.Length); + } + + return Encoding.UTF8.GetString(buffer); + } + + #endregion + +#if DEBUG + + [Obsolete("use GetLastRelativeUrl", true)] + public static string GetCurrentPath(this string url) => GetCurrentPath(url); + +#endif } } \ No newline at end of file diff --git a/System.Common.CoreLib/Platform.cs b/System.Common.CoreLib/Platform.cs index 11569fa7db8..044d187f691 100644 --- a/System.Common.CoreLib/Platform.cs +++ b/System.Common.CoreLib/Platform.cs @@ -12,7 +12,7 @@ public enum Platform /// /// 未知 /// - Unknown = 0, + Unknown = 1, /// /// Microsoft Windows / UWP(Universal Windows Platform) diff --git a/System.Common.CoreLib/System.Common.CoreLib.csproj b/System.Common.CoreLib/System.Common.CoreLib.csproj index 1f64c54fd6b..3a4562ad84d 100644 --- a/System.Common.CoreLib/System.Common.CoreLib.csproj +++ b/System.Common.CoreLib/System.Common.CoreLib.csproj @@ -6,16 +6,16 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/System.Common.CoreLib/UnixTimestamp.cs b/System.Common.CoreLib/UnixTimestamp.cs index 9edd78e7501..5833c99da43 100644 --- a/System.Common.CoreLib/UnixTimestamp.cs +++ b/System.Common.CoreLib/UnixTimestamp.cs @@ -46,13 +46,13 @@ static long GetTicks(int timestamp) return ticks; } - static DateTime GetDateTime(long ticks, bool convertLocalTime = false) + static DateTime GetDateTime(long ticks, bool convertLocalTime = true) { var dt = new DateTime(ticks, DateTimeKind.Utc); return convertLocalTime ? dt.ToLocalTime() : dt; } - static DateTimeOffset GetDateTimeOffset(long ticks, bool convertLocalTime = false) + static DateTimeOffset GetDateTimeOffset(long ticks, bool convertLocalTime = true) { var dt = new DateTimeOffset(ticks, TimeSpan.Zero); return convertLocalTime ? dt.ToLocalTime() : dt; @@ -64,7 +64,7 @@ static DateTimeOffset GetDateTimeOffset(long ticks, bool convertLocalTime = fals /// /// /// - public static DateTime ToDateTime(long timestamp, bool convertLocalTime = false) + public static DateTime ToDateTime(this long timestamp, bool convertLocalTime = true) { var ticks = GetTicks(timestamp); return GetDateTime(ticks, convertLocalTime); @@ -76,7 +76,7 @@ public static DateTime ToDateTime(long timestamp, bool convertLocalTime = false) /// /// /// - public static DateTime ToDateTime(int timestamp, bool convertLocalTime = false) + public static DateTime ToDateTime(this int timestamp, bool convertLocalTime = true) { var ticks = GetTicks(timestamp); return GetDateTime(ticks, convertLocalTime); @@ -88,7 +88,7 @@ public static DateTime ToDateTime(int timestamp, bool convertLocalTime = false) /// /// /// - public static DateTimeOffset ToDateTimeOffset(long timestamp, bool convertLocalTime = false) + public static DateTimeOffset ToDateTimeOffset(this long timestamp, bool convertLocalTime = true) { var ticks = GetTicks(timestamp); return GetDateTimeOffset(ticks, convertLocalTime); @@ -100,10 +100,17 @@ public static DateTimeOffset ToDateTimeOffset(long timestamp, bool convertLocalT /// /// /// - public static DateTimeOffset ToDateTimeOffset(int timestamp, bool convertLocalTime = false) + public static DateTimeOffset ToDateTimeOffset(this int timestamp, bool convertLocalTime = true) { var ticks = GetTicks(timestamp); return GetDateTimeOffset(ticks, convertLocalTime); } + +#if DEBUG + + [Obsolete("use ToTimestamp", true)] + public static long CurrentMillis(this DateTime dateTime) => ToTimestamp(dateTime); + +#endif } } \ No newline at end of file diff --git a/Win7Troubleshoot/NullableAttributes.cs b/Win7Troubleshoot/NullableAttributes.cs new file mode 100644 index 00000000000..af214b1904b --- /dev/null +++ b/Win7Troubleshoot/NullableAttributes.cs @@ -0,0 +1,17 @@ +// ReSharper disable once CheckNamespace +namespace System.Diagnostics.CodeAnalysis +{ + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } +} \ No newline at end of file diff --git a/Win7Troubleshoot/Program.cs b/Win7Troubleshoot/Program.cs index a3d16bf1426..d7119718f41 100644 --- a/Win7Troubleshoot/Program.cs +++ b/Win7Troubleshoot/Program.cs @@ -11,6 +11,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Threading; @@ -28,14 +29,14 @@ static class Program static void Main(string[] args) #pragma warning restore IDE0060 // 删除未使用的参数 { - if (Environment.OSVersion.Platform != PlatformID.Win32NT) - throw new PlatformNotSupportedException(); mutex = new Mutex(true, Process.GetCurrentProcess().ProcessName, out var isNotRunning); if (isNotRunning) { try { - var r = IsWin7SP1OrNotSupportedPlatform(); + if (Environment.OSVersion.Platform != PlatformID.Win32NT) + throw new PlatformNotSupportedException(); + var r = IsWin7SP1OrNotSupportedPlatform(out var error); if (r.HasValue) { if (r.Value) // Win7SP1 @@ -56,7 +57,7 @@ static void Main(string[] args) else // NotSupportedPlatform - For example, WinXP/Win2000 { MessageBox.Show( - SR.NotSupportedPlatformError, + error, SR.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); @@ -126,9 +127,11 @@ static void AppRun() /// 当前运行的操作系统不支持 /// 当前运行的操作系统为Win8或更高 /// + /// /// - static bool? IsWin7SP1OrNotSupportedPlatform() + static bool? IsWin7SP1OrNotSupportedPlatform([NotNullWhen(false)] out string? error) { + error = null; if (Environment.OSVersion.Version.Major == 6) { if (Environment.OSVersion.Version.Minor == 1) // NT 6.1 / Win7 / WinServer 2008 R2 @@ -137,6 +140,7 @@ static void AppRun() } else if (Environment.OSVersion.Version.Minor == 2) // NT 6.2 / Win8 / WinServer 2012 { + error = SR.NotSupportedWin8PlatformError; return false; } else if (Environment.OSVersion.Version.Minor == 3) // NT 6.3 / Win8.1 / WinServer 2012 R2 @@ -145,11 +149,12 @@ static void AppRun() } else { - return false; + throw new PlatformNotSupportedException(); } } else if (Environment.OSVersion.Version.Major < 6) { + error = SR.NotSupportedPlatformError; return false; } return null; diff --git a/Win7Troubleshoot/Properties/SR.Designer.cs b/Win7Troubleshoot/Properties/SR.Designer.cs index 56f6bddbad6..3b95bafffe8 100644 --- a/Win7Troubleshoot/Properties/SR.Designer.cs +++ b/Win7Troubleshoot/Properties/SR.Designer.cs @@ -86,5 +86,14 @@ internal static string NotSupportedPlatformError { return ResourceManager.GetString("NotSupportedPlatformError", resourceCulture); } } + + /// + /// 查找类似 由于微软官方对 Windows 8 的支持已结束,故本程序无法在此操作系统上运行,建议升级到 Windows 8.1 或 Windows 10 的本地化字符串。 + /// + internal static string NotSupportedWin8PlatformError { + get { + return ResourceManager.GetString("NotSupportedWin8PlatformError", resourceCulture); + } + } } } diff --git a/Win7Troubleshoot/Properties/SR.en.resx b/Win7Troubleshoot/Properties/SR.en.resx index 06fa7a5dc4b..c84644041af 100644 --- a/Win7Troubleshoot/Properties/SR.en.resx +++ b/Win7Troubleshoot/Properties/SR.en.resx @@ -123,6 +123,9 @@ The minimum requirement of operating system is Windows 7 SP1 + + Because Microsoft's official support for Windows 8 has ended, this program cannot run on this operating system. It is recommended to upgrade to Windows 8.1 or Windows 10 + Due to the lack of necessary patch KB3063858 in the operating system, the program cannot run. Do you want to open the download address with a browser and install it manually? diff --git a/Win7Troubleshoot/Properties/SR.resx b/Win7Troubleshoot/Properties/SR.resx index 75e6df952c5..a7499251de5 100644 --- a/Win7Troubleshoot/Properties/SR.resx +++ b/Win7Troubleshoot/Properties/SR.resx @@ -123,6 +123,9 @@ 操作系统最低需要 Windows 7 SP1 + + 由于微软官方对 Windows 8 的支持已结束,故本程序无法在此操作系统上运行,建议升级到 Windows 8.1 或 Windows 10 + 操作系统中缺少必要的补丁 KB3063858 导致程序无法运行,是否使用浏览器打开下载地址并手动安装? diff --git a/Win7Troubleshoot/Properties/SR.zh-Hant.resx b/Win7Troubleshoot/Properties/SR.zh-Hant.resx index b8334cb6850..8a3b72e3d2b 100644 --- a/Win7Troubleshoot/Properties/SR.zh-Hant.resx +++ b/Win7Troubleshoot/Properties/SR.zh-Hant.resx @@ -123,6 +123,9 @@ 作業系統最低需要Windows 7 SP1 + + 由於微軟官方對 Windows 8 的支持已結束,故本程式無法在此作業系統上運行,建議陞級到 Windows 8.1 或 Windows 10 + 作業系統中缺少必要的補丁 KB3063858 導致程式無法運行,是否使用瀏覽器打開下載地址並手動安裝? diff --git a/source/SteamTool.Core/Common/Common.cs b/source/SteamTool.Core/Common/Common.cs index be28f05a1ec..c13b29df3dd 100644 --- a/source/SteamTool.Core/Common/Common.cs +++ b/source/SteamTool.Core/Common/Common.cs @@ -15,7 +15,7 @@ public static class Common /// public static DateTime ToDateTime(this long timestamp) { - return TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(timestamp), TimeZoneInfo.Local); + return TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(timestamp), TimeZoneInfo.Local); } /// @@ -51,7 +51,7 @@ public static string GetCurrentPath(this string url) /// /// /// - public static string RemovePattern(this string inputString) + public static string RemovePattern(this string inputString) { return inputString.Replace("\t", "").Replace("\r", "").Replace("\n", ""); } @@ -119,6 +119,7 @@ public static bool IsWildcard(this string str, string pattern) /// /// /// + [Obsolete("V2 中使用 MessagePack反序列化与序列化进行拷贝,同时仅扩展序列化接口,避免扩展大范围全局污染")] public static T Clone(this T source) { //如果是字符串或值类型则直接返回 diff --git a/source/SteamTool.Core/Common/EnumerableEx.cs b/source/SteamTool.Core/Common/EnumerableEx.cs index 7877721f8e5..d8b15432504 100644 --- a/source/SteamTool.Core/Common/EnumerableEx.cs +++ b/source/SteamTool.Core/Common/EnumerableEx.cs @@ -5,54 +5,55 @@ namespace SteamTool.Core.Common { - public static class EnumerableEx - { - public static IEnumerable Return(TResult value) - { - yield return value; - } + public static class EnumerableEx + { + [Obsolete("", true)] + public static IEnumerable Return(TResult value) + { + yield return value; + } - public static IEnumerable Distinct(this IEnumerable source, Func keySelector) - { - var set = new HashSet(EqualityComparer.Default); + public static IEnumerable Distinct(this IEnumerable source, Func keySelector) + { + var set = new HashSet(EqualityComparer.Default); - foreach (var item in source) - { - var key = keySelector(item); - if (set.Add(key)) yield return item; - } - } + foreach (var item in source) + { + var key = keySelector(item); + if (set.Add(key)) yield return item; + } + } - public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) - { - HashSet seenKeys = new HashSet(); - foreach (TSource element in source) - { - if (seenKeys.Add(keySelector(element))) - { - yield return element; - } - } - } + public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) + { + HashSet seenKeys = new HashSet(); + foreach (TSource element in source) + { + if (seenKeys.Add(keySelector(element))) + { + yield return element; + } + } + } - /// - /// コレクションを展開し、メンバーの文字列表現を指定した区切り文字で連結した文字列を返します。 - /// - /// コレクションに含まれる任意の型。 - /// 対象のコレクション。 - /// セパレーターとして使用する文字列。 - /// コレクションの文字列表現を展開し、指定したセパレーターで連結した文字列。 - public static string ToString(this IEnumerable source, string separator) - { - return string.Join(separator, source); - } + /// + /// コレクションを展開し、メンバーの文字列表現を指定した区切り文字で連結した文字列を返します。 + /// + /// コレクションに含まれる任意の型。 + /// 対象のコレクション。 + /// セパレーターとして使用する文字列。 + /// コレクションの文字列表現を展開し、指定したセパレーターで連結した文字列。 + public static string ToString(this IEnumerable source, string separator) + { + return string.Join(separator, source); + } - /// - /// シーケンスが null でなく、1 つ以上の要素を含んでいるかどうかを確認します。 - /// - public static bool HasItems(this IEnumerable source) - { - return source != null && source.Any(); - } - } + /// + /// シーケンスが null でなく、1 つ以上の要素を含んでいるかどうかを確認します。 + /// + public static bool HasItems(this IEnumerable source) + { + return source != null && source.Any(); + } + } } diff --git a/source/SteamTool.Core/Common/GuidRandom.cs b/source/SteamTool.Core/Common/GuidRandom.cs index 721e01c90a3..dbf75cd557c 100644 --- a/source/SteamTool.Core/Common/GuidRandom.cs +++ b/source/SteamTool.Core/Common/GuidRandom.cs @@ -4,6 +4,7 @@ namespace SteamTool.Core.Common { + [Obsolete("", true)] public static class GuidRandom { public static Random GetGuidRandom(this Random random) diff --git a/source/SteamTool.Core/Common/Md5Method.cs b/source/SteamTool.Core/Common/Md5Method.cs index c9bc09f7fe6..6eb5b5130f2 100644 --- a/source/SteamTool.Core/Common/Md5Method.cs +++ b/source/SteamTool.Core/Common/Md5Method.cs @@ -10,6 +10,7 @@ namespace SteamTool.Core.Common /// 类名 :MD5加密
/// 说明 :
///
+ [Obsolete("use System.Security.Cryptography.Hashs.String(ByteArray).MD5", true)] public static class Md5Method { ///