From f44cdb576a5045ccceae9d0fcaea98de77043992 Mon Sep 17 00:00:00 2001 From: Aigio Liu Date: Wed, 28 Apr 2021 16:29:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20WebView3=20=E6=8B=96?= =?UTF-8?q?=E6=8B=BD=E9=80=89=E4=B8=AD=E5=86=85=E5=AE=B9=E6=97=B6=E9=97=AA?= =?UTF-8?q?=E9=80=80=20&=20=E8=B4=A6=E5=8F=B7=E5=88=87=E6=8D=A2=E5=A4=B4?= =?UTF-8?q?=E5=83=8F=E4=B8=8D=E6=98=BE=E7=A4=BA=20&=20=E4=B8=BB=E8=BF=9B?= =?UTF-8?q?=E7=A8=8B=E5=88=A4=E6=96=AD=E4=B8=8D=E6=AD=A3=E7=A1=AE=20&=20Ab?= =?UTF-8?q?andonedMutexException?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../App.axaml.cs | 8 +- .../ApplicationInstance.cs | 49 +++--- .../CommandLineTools.cs | 140 +++++++++--------- .../Program.BuildAvaloniaApp.cs | 21 +-- src/ST.Client.Desktop.Avalonia.App/Program.cs | 35 +++-- .../Properties/PublishProfiles/win-x86.pubxml | 4 +- .../ST.Client.Desktop.Avalonia.App.csproj | 9 +- .../Program.cs | 11 +- .../UI/MainApplication.cs | 33 ++--- src/ST.Client.Mobile.iOS/UI/AppDelegate.cs | 9 +- src/Startup2.cs | 19 ++- 11 files changed, 176 insertions(+), 162 deletions(-) diff --git a/src/ST.Client.Desktop.Avalonia.App/App.axaml.cs b/src/ST.Client.Desktop.Avalonia.App/App.axaml.cs index c79e44a50..5e3d1a741 100644 --- a/src/ST.Client.Desktop.Avalonia.App/App.axaml.cs +++ b/src/ST.Client.Desktop.Avalonia.App/App.axaml.cs @@ -1,4 +1,4 @@ -using Avalonia.Controls; +using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using ReactiveUI; @@ -188,7 +188,7 @@ namespace System.Application.UI AppDelegate.Init(); #endif - if (Startup.IsMainProcess) + if (Program.IsMainProcess) { if (Startup.HasNotifyIcon) { @@ -278,7 +278,7 @@ namespace System.Application.UI VisualStudioAppCenterSDK.Init(); #endif AppHelper.Initialized?.Invoke(); - if (Startup.IsMainProcess) + if (Program.IsMainProcess) { Startup.ActiveUserPost(ActiveUserType.OnStartup); IAppUpdateService.Instance.CheckUpdate(showIsExistUpdateFalse: false); @@ -416,4 +416,4 @@ namespace System.Application.UI #endregion } -} \ No newline at end of file +} diff --git a/src/ST.Client.Desktop.Avalonia.App/ApplicationInstance.cs b/src/ST.Client.Desktop.Avalonia.App/ApplicationInstance.cs index 268b39a40..c46260531 100644 --- a/src/ST.Client.Desktop.Avalonia.App/ApplicationInstance.cs +++ b/src/ST.Client.Desktop.Avalonia.App/ApplicationInstance.cs @@ -1,15 +1,5 @@ -using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Globalization; using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.Remoting; -using System.Runtime.Serialization.Formatters; -using System.Threading; -using System.Threading.Tasks; -using System.IO.Pipes; namespace System.Application.UI { @@ -18,7 +8,7 @@ namespace System.Application.UI /// public sealed class ApplicationInstance { - private readonly ApplicationInstanceMessage _appInstanceMessage; + private readonly ApplicationInstanceMessage? _appInstanceMessage; /// /// 获取一个值,该值指示此实例是否是第一个要启动的实例。 @@ -28,23 +18,39 @@ namespace System.Application.UI /// /// 在接收新启动的实例的命令行时发生。 /// - public event EventHandler CommandLineArgsReceived; + public event EventHandler? CommandLineArgsReceived; - public ApplicationInstance() : this(Assembly.GetEntryAssembly()) { } + //public ApplicationInstance() : this(Assembly.GetEntryAssembly() ?? typeof(ApplicationInstance).Assembly) { } - public ApplicationInstance(Assembly targetAssembly) - { + public ApplicationInstance(/*Assembly targetAssembly*/) + { // 获取应用程序的GUID - var portName = ((GuidAttribute)Attribute.GetCustomAttribute(targetAssembly, typeof(GuidAttribute))).Value; + //var portName = ((GuidAttribute)Attribute.GetCustomAttribute(targetAssembly, typeof(GuidAttribute))).Value; // 使用会话ID作为URI,以便它是每个会话URI //var uri = Process.GetCurrentProcess().SessionId.ToString(CultureInfo.InvariantCulture); // 如果成功创建了IPC服务器,则假定是首次创建使用指定端口的IPC通信。 // 如果创建失败,则说明另一个实例正在创建IPC服务器,因此在创建客户端时,Mutex会同时保护其免受这些操作的影响。 - using var mutex = new Mutex(true, typeof(ApplicationInstanceMessage).FullName + "_" + "b8335358-e2e6-4c32-b6e3-0bc501ad3e2f", out bool flag); - mutex.WaitOne(); - this.IsFirst = flag; + //using var mutex = new Mutex(true, typeof(ApplicationInstanceMessage).FullName + "_" + "b8335358-e2e6-4c32-b6e3-0bc501ad3e2f", out bool flag); + //mutex.WaitOne(); + //this.IsFirst = flag; + IsFirst = GetIsFirst(); + } + + static bool GetIsFirst() + { + var current = Process.GetCurrentProcess(); + var query = from p in Process.GetProcesses() + where p.Id != current.Id && + p.ProcessName == current.ProcessName && + (current.MainModule == null || + (p.MainModule != null && + p.MainModule.FileName == current.MainModule.FileName && + p.MainModule.ModuleName == current.MainModule.ModuleName)) + select p; + var r = query.Any(); + return !r; } /// @@ -62,10 +68,9 @@ namespace System.Application.UI /// 当前进程的命令行参数。 public void SendCommandLineArgs(string[] commandLineArgs) { - this._appInstanceMessage.OnMessageReceived(commandLineArgs); + this._appInstanceMessage?.OnMessageReceived(commandLineArgs); } - /// /// 存储所有进程共有的消息以及已发送和接收的消息。 /// @@ -74,7 +79,7 @@ namespace System.Application.UI /// /// 收到消息时发生。 /// - public event Action MessageReceived; + public event Action? MessageReceived; /// /// 引发一个事件。 diff --git a/src/ST.Client.Desktop.Avalonia.App/CommandLineTools.cs b/src/ST.Client.Desktop.Avalonia.App/CommandLineTools.cs index 14e6975dd..3351634c6 100644 --- a/src/ST.Client.Desktop.Avalonia.App/CommandLineTools.cs +++ b/src/ST.Client.Desktop.Avalonia.App/CommandLineTools.cs @@ -1,85 +1,87 @@ -using System.Application.Services; -using System.Application.UI; +using System.Application.Services; using System.CommandLine; using System.CommandLine.Invocation; -namespace System.Application +namespace System.Application.UI { - /// - /// 命令行工具(Command Line Tools/CLT) - /// - internal static class CommandLineTools + partial class Program { - public static int Main(string[] args, - Action initStartup, - Action initUIApp, - Action initCef) + /// + /// 命令行工具(Command Line Tools/CLT) + /// + static class CommandLineTools { - if (args.Length == 0) args = new[] { "-h" }; + public static int Main(string[] args, + Action initStartup, + Action initUIApp, + Action initCef) + { + if (args.Length == 0) args = new[] { "-h" }; - // https://docs.microsoft.com/zh-cn/archive/msdn-magazine/2019/march/net-parse-the-command-line-with-system-commandline - var rootCommand = new RootCommand("命令行工具(Command Line Tools/CLT)"); + // https://docs.microsoft.com/zh-cn/archive/msdn-magazine/2019/march/net-parse-the-command-line-with-system-commandline + var rootCommand = new RootCommand("命令行工具(Command Line Tools/CLT)"); #if DEBUG - // -clt debug -args 730 - var debug = new Command("debug", "调试"); - debug.AddOption(new Option("-args", () => "", "测试参数")); - debug.Handler = CommandHandler.Create((string args) => // 参数名与类型要与 Option 中一致! - { - //Console.WriteLine("-clt debug -args " + args); - // OutputType WinExe 导致控制台输入不会显示,只能附加一个新的控制台窗口显示内容,不合适 - // 如果能取消 管理员权限要求,改为运行时管理员权限, - // 则可尝试通过 Windows Terminal 或直接 Host 进行命令行模式 - initStartup(DILevel.MainProcess); - initCef(); - initUIApp(); - }); - rootCommand.AddCommand(debug); + // -clt debug -args 730 + var debug = new Command("debug", "调试"); + debug.AddOption(new Option("-args", () => "", "测试参数")); + debug.Handler = CommandHandler.Create((string args) => // 参数名与类型要与 Option 中一致! + { + //Console.WriteLine("-clt debug -args " + args); + // OutputType WinExe 导致控制台输入不会显示,只能附加一个新的控制台窗口显示内容,不合适 + // 如果能取消 管理员权限要求,改为运行时管理员权限, + // 则可尝试通过 Windows Terminal 或直接 Host 进行命令行模式 + initStartup(DILevel.MainProcess); + initCef(); + initUIApp(); + }); + rootCommand.AddCommand(debug); #endif - // -clt devtools - var devtools = new Command("devtools"); - devtools.Handler = CommandHandler.Create(() => - { - var appInstance = new ApplicationInstance(); - if (!appInstance.IsFirst) return; - Startup.IsMainProcess = true; - Program.IsCLTProcess = false; - AppHelper.EnableDevtools = true; - initStartup(DILevel.MainProcess); - initCef(); - initUIApp(); - }); - rootCommand.AddCommand(devtools); + // -clt devtools + var devtools = new Command("devtools"); + devtools.Handler = CommandHandler.Create(() => + { + var appInstance = new ApplicationInstance(); + if (!appInstance.IsFirst) return; + IsMainProcess = true; + IsCLTProcess = false; + AppHelper.EnableDevtools = true; + initStartup(DILevel.MainProcess); + initCef(); + initUIApp(); + }); + rootCommand.AddCommand(devtools); - // -clt c -silence - var common = new Command("c", "common"); - common.AddOption(new Option("-silence", "静默启动(不弹窗口)")); - common.Handler = CommandHandler.Create((bool silence) => - { - initStartup(DILevel.MainProcess); - initCef(); - Program.IsMinimize = silence; - initUIApp(); - }); - rootCommand.AddCommand(common); + // -clt c -silence + var common = new Command("c", "common"); + common.AddOption(new Option("-silence", "静默启动(不弹窗口)")); + common.Handler = CommandHandler.Create((bool silence) => + { + initStartup(DILevel.MainProcess); + initCef(); + IsMinimize = silence; + initUIApp(); + }); + rootCommand.AddCommand(common); - // -clt app -id 632360 - var unlock_achievement = new Command("app", "打开成就解锁窗口"); - unlock_achievement.AddOption(new Option("-id", "指定一个Steam游戏Id")); - unlock_achievement.AddOption(new Option("-silence", "静默启动(不弹窗口)")); - unlock_achievement.Handler = CommandHandler.Create((int id, bool silence) => - { - if (id <= 0) return; - initStartup(DILevel.GUI | DILevel.Steam | DILevel.HttpClientFactory); - IWindowService.Instance.InitUnlockAchievement(id); - Program.IsMinimize = silence; - initUIApp(); - }); - rootCommand.AddCommand(unlock_achievement); + // -clt app -id 632360 + var unlock_achievement = new Command("app", "打开成就解锁窗口"); + unlock_achievement.AddOption(new Option("-id", "指定一个Steam游戏Id")); + unlock_achievement.AddOption(new Option("-silence", "静默启动(不弹窗口)")); + unlock_achievement.Handler = CommandHandler.Create((int id, bool silence) => + { + if (id <= 0) return; + initStartup(DILevel.GUI | DILevel.Steam | DILevel.HttpClientFactory); + IWindowService.Instance.InitUnlockAchievement(id); + IsMinimize = silence; + initUIApp(); + }); + rootCommand.AddCommand(unlock_achievement); - var r = rootCommand.InvokeAsync(args).Result; - return r; + var r = rootCommand.InvokeAsync(args).Result; + return r; + } } } -} \ No newline at end of file +} diff --git a/src/ST.Client.Desktop.Avalonia.App/Program.BuildAvaloniaApp.cs b/src/ST.Client.Desktop.Avalonia.App/Program.BuildAvaloniaApp.cs index be0106ca4..2e9cf3ea3 100644 --- a/src/ST.Client.Desktop.Avalonia.App/Program.BuildAvaloniaApp.cs +++ b/src/ST.Client.Desktop.Avalonia.App/Program.BuildAvaloniaApp.cs @@ -1,4 +1,4 @@ -using Avalonia; +using Avalonia; using Avalonia.ReactiveUI; namespace System.Application.UI @@ -22,22 +22,5 @@ namespace System.Application.UI static void BuildAvaloniaAppAndStartWithClassicDesktopLifetime(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); - -#if DEBUG - /// - /// 当前是否是主进程 - /// - [Obsolete("use Startup.IsMainProcess", true)] - internal static bool IsMainProcess - { - get => Startup.IsMainProcess; - private set => Startup.IsMainProcess = value; - } -#endif - - /// - /// 当前是否是命令行工具进程 - /// - internal static bool IsCLTProcess { get; set; } } -} \ No newline at end of file +} diff --git a/src/ST.Client.Desktop.Avalonia.App/Program.cs b/src/ST.Client.Desktop.Avalonia.App/Program.cs index c26ac52c9..76714ebf9 100644 --- a/src/ST.Client.Desktop.Avalonia.App/Program.cs +++ b/src/ST.Client.Desktop.Avalonia.App/Program.cs @@ -1,10 +1,8 @@ -using NLog; +using NLog; using NLog.Config; -using System.Application.Models.Settings; using System.Application.Services; using System.IO; using System.Linq; -using System.Reflection; using LogLevel = Microsoft.Extensions.Logging.LogLevel; namespace System.Application.UI @@ -19,8 +17,8 @@ namespace System.Application.UI { // 目前桌面端默认使用 SystemTextJson 如果出现兼容性问题可取消下面这行代码 // Serializable.DefaultJsonImplType = Serializable.JsonImplType.NewtonsoftJson; - Startup.IsMainProcess = args.Length == 0; - IsCLTProcess = !Startup.IsMainProcess && args.FirstOrDefault() == "-clt"; + IsMainProcess = args.Length == 0; + IsCLTProcess = !IsMainProcess && args.FirstOrDefault() == "-clt"; var logDirPath = InitLogDir(); @@ -39,7 +37,7 @@ namespace System.Application.UI { Startup.Init(DILevel.MainProcess); - if (Startup.IsMainProcess) + if (IsMainProcess) { var appInstance = new ApplicationInstance(); if (!appInstance.IsFirst) goto exit; @@ -47,7 +45,7 @@ namespace System.Application.UI InitCefNetApp(); - if (Startup.IsMainProcess) + if (IsMainProcess) { InitAvaloniaApp(); } @@ -55,6 +53,7 @@ namespace System.Application.UI } catch (Exception ex) { + Console.WriteLine(ex); AppHelper.TrySetLoggerMinLevel(LogLevel.Trace); // NLog: catch any exception and log it. logger.Error(ex, "Stopped program because of exception"); @@ -116,11 +115,6 @@ namespace System.Application.UI exit: return 0; } - /// - /// 是否最小化 - /// - internal static bool IsMinimize { get; set; } - static string InitLogDir() { var logDirPath = Path.Combine(AppContext.BaseDirectory, "Logs"); @@ -155,5 +149,20 @@ namespace System.Application.UI return logDirPath; } + + /// + /// 是否最小化启动 + /// + public static bool IsMinimize { get; /*private*/ set; } + + /// + /// 当前是否是命令行工具进程 + /// + public static bool IsCLTProcess { get; private set; } + + /// + /// 当前是否是主进程 + /// + public static bool IsMainProcess { get; private set; } } -} \ No newline at end of file +} diff --git a/src/ST.Client.Desktop.Avalonia.App/Properties/PublishProfiles/win-x86.pubxml b/src/ST.Client.Desktop.Avalonia.App/Properties/PublishProfiles/win-x86.pubxml index 3ed8efcec..63f9b5040 100644 --- a/src/ST.Client.Desktop.Avalonia.App/Properties/PublishProfiles/win-x86.pubxml +++ b/src/ST.Client.Desktop.Avalonia.App/Properties/PublishProfiles/win-x86.pubxml @@ -1,4 +1,4 @@ - + @@ -13,4 +13,4 @@ https://go.microsoft.com/fwlink/?LinkID=208121. win7-x86 true - \ No newline at end of file + diff --git a/src/ST.Client.Desktop.Avalonia.App/ST.Client.Desktop.Avalonia.App.csproj b/src/ST.Client.Desktop.Avalonia.App/ST.Client.Desktop.Avalonia.App.csproj index a3e5a30d5..4f2f9b4eb 100644 --- a/src/ST.Client.Desktop.Avalonia.App/ST.Client.Desktop.Avalonia.App.csproj +++ b/src/ST.Client.Desktop.Avalonia.App/ST.Client.Desktop.Avalonia.App.csproj @@ -7,6 +7,7 @@ System.Application.UI Steam++ + Properties\app.manifest + false link true @@ -55,6 +57,11 @@ false + + diff --git a/src/ST.Client.Desktop.Avalonia.Demo.App/Program.cs b/src/ST.Client.Desktop.Avalonia.Demo.App/Program.cs index 630b1a930..c54e7586a 100644 --- a/src/ST.Client.Desktop.Avalonia.Demo.App/Program.cs +++ b/src/ST.Client.Desktop.Avalonia.Demo.App/Program.cs @@ -1,13 +1,18 @@ -namespace System.Application.UI +namespace System.Application.UI { static partial class Program { [STAThread] static void Main(string[] args) { - Startup.IsMainProcess = true; + IsMainProcess = true; Startup.Init(DILevel.MainProcess); BuildAvaloniaAppAndStartWithClassicDesktopLifetime(args); } + + /// + /// 当前是否是主进程 + /// + public static bool IsMainProcess { get; private set; } } -} \ No newline at end of file +} diff --git a/src/ST.Client.Mobile.Droid/UI/MainApplication.cs b/src/ST.Client.Mobile.Droid/UI/MainApplication.cs index 9d1e190fb..51991b30a 100644 --- a/src/ST.Client.Mobile.Droid/UI/MainApplication.cs +++ b/src/ST.Client.Mobile.Droid/UI/MainApplication.cs @@ -1,6 +1,5 @@ -using Android.App; +using Android.App; using Android.Runtime; -using AndroidX.AppCompat.App; using System.Properties; using Xamarin.Essentials; using AndroidApplication = Android.App.Application; @@ -18,17 +17,6 @@ namespace System.Application.UI { } - /// - /// 是否为主进程 - /// - /// - public bool IsMainProcess() - { - // 注意:进程名可以自定义,默认是包名,如果自定义了主进程名,这里就有误,所以不要自定义主进程名! - var name = this.GetCurrentProcessName(); - return name == PackageName; - } - public override void OnCreate() { base.OnCreate(); @@ -38,13 +26,19 @@ namespace System.Application.UI XEFileProvider.TemporaryLocation = FileProviderLocation.Internal; XEPlatform.Init(this); // 初始化 Xamarin.Essentials.Platform.Init - Startup.IsMainProcess = IsMainProcess(); + bool GetIsMainProcess() + { + // 注意:进程名可以自定义,默认是包名,如果自定义了主进程名,这里就有误,所以不要自定义主进程名! + var name = this.GetCurrentProcessName(); + return name == PackageName; + } + IsMainProcess = GetIsMainProcess(); DILevel level = DILevel.Min; - if (Startup.IsMainProcess) level = DILevel.MainProcess; + if (IsMainProcess) level = DILevel.MainProcess; Startup.Init(level); - if (Startup.IsMainProcess) + if (IsMainProcess) { XEVersionTracking.Track(); } @@ -53,5 +47,10 @@ namespace System.Application.UI Log.Debug("Application", "OnCreate Complete."); #endif } + + /// + /// 当前是否是主进程 + /// + public static bool IsMainProcess { get; private set; } } -} \ No newline at end of file +} diff --git a/src/ST.Client.Mobile.iOS/UI/AppDelegate.cs b/src/ST.Client.Mobile.iOS/UI/AppDelegate.cs index ede20b2fb..fa25fa769 100644 --- a/src/ST.Client.Mobile.iOS/UI/AppDelegate.cs +++ b/src/ST.Client.Mobile.iOS/UI/AppDelegate.cs @@ -1,4 +1,4 @@ -using Foundation; +using Foundation; using UIKit; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; @@ -36,5 +36,10 @@ namespace System.Application.UI return base.FinishedLaunching(app, options); } + + /// + /// 当前是否是主进程 + /// + public static bool IsMainProcess { get; private set; } } -} \ No newline at end of file +} diff --git a/src/Startup2.cs b/src/Startup2.cs index 4d1b33508..16154c559 100644 --- a/src/Startup2.cs +++ b/src/Startup2.cs @@ -1,4 +1,4 @@ -#if !__MOBILE__ +#if !__MOBILE__ using Avalonia; using Avalonia.Controls; using Avalonia.Platform; @@ -26,6 +26,11 @@ using System.Properties; using System.Diagnostics; using System.IO; using static System.Application.AppClientAttribute; +#if __ANDROID__ +using Program = System.Application.UI.MainApplication; +#elif __IOS__ +using Program = System.Application.UI.AppDelegate; +#endif namespace System.Application { @@ -57,7 +62,6 @@ namespace System.Application DI.Init(s => ConfigureServices(s, level)); static void ConfigureServices(IServiceCollection services, DILevel level) { - IsMainProcess = level == DILevel.MainProcess; ConfigureRequiredServices(services); ConfigureDemandServices(services, level); } @@ -219,7 +223,7 @@ namespace System.Application void AddNotificationService() { #if !__MOBILE__ - if (!IsMainProcess) return; + if (!Program.IsMainProcess) return; #endif services.AddNotificationService(); } @@ -466,15 +470,10 @@ namespace System.Application } #endif - /// - /// 当前是否是主进程 - /// - internal static bool IsMainProcess { get; set; } - /// internal static async void ActiveUserPost(ActiveUserType type) { - if (!IsMainProcess) return; + if (!Program.IsMainProcess) return; try { #if !__MOBILE__ @@ -517,4 +516,4 @@ namespace System.Application } } } -} \ No newline at end of file +}