修复 WebView3 拖拽选中内容时闪退 & 账号切换头像不显示 & 主进程判断不正确 & AbandonedMutexException

This commit is contained in:
Aigio Liu
2021-04-28 16:29:23 +08:00
parent 104404603d
commit f44cdb576a
11 changed files with 176 additions and 162 deletions
@@ -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
}
}
}
@@ -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
/// </summary>
public sealed class ApplicationInstance
{
private readonly ApplicationInstanceMessage _appInstanceMessage;
private readonly ApplicationInstanceMessage? _appInstanceMessage;
/// <summary>
/// 获取一个值,该值指示此实例是否是第一个要启动的实例。
@@ -28,23 +18,39 @@ namespace System.Application.UI
/// <summary>
/// 在接收新启动的实例的命令行时发生。
/// </summary>
public event EventHandler<MessageEventArgs> CommandLineArgsReceived;
public event EventHandler<MessageEventArgs>? 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;
}
/// <summary>
@@ -62,10 +68,9 @@ namespace System.Application.UI
/// <param name="commandLineArgs">当前进程的命令行参数。</param>
public void SendCommandLineArgs(string[] commandLineArgs)
{
this._appInstanceMessage.OnMessageReceived(commandLineArgs);
this._appInstanceMessage?.OnMessageReceived(commandLineArgs);
}
/// <summary>
/// 存储所有进程共有的消息以及已发送和接收的消息。
/// </summary>
@@ -74,7 +79,7 @@ namespace System.Application.UI
/// <summary>
/// 收到消息时发生。
/// </summary>
public event Action<string[]> MessageReceived;
public event Action<string[]>? MessageReceived;
/// <summary>
/// <see cref="MessageReceived"/> 引发一个事件。
@@ -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
{
/// <summary>
/// 命令行工具(Command Line Tools/CLT)
/// </summary>
internal static class CommandLineTools
partial class Program
{
public static int Main(string[] args,
Action<DILevel> initStartup,
Action initUIApp,
Action initCef)
/// <summary>
/// 命令行工具(Command Line Tools/CLT)
/// </summary>
static class CommandLineTools
{
if (args.Length == 0) args = new[] { "-h" };
public static int Main(string[] args,
Action<DILevel> 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<string>("-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<string>("-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<bool>("-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<bool>("-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<int>("-id", "指定一个Steam游戏Id"));
unlock_achievement.AddOption(new Option<bool>("-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<int>("-id", "指定一个Steam游戏Id"));
unlock_achievement.AddOption(new Option<bool>("-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;
}
}
}
}
}
@@ -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
/// <summary>
/// 当前是否是主进程
/// </summary>
[Obsolete("use Startup.IsMainProcess", true)]
internal static bool IsMainProcess
{
get => Startup.IsMainProcess;
private set => Startup.IsMainProcess = value;
}
#endif
/// <summary>
/// 当前是否是命令行工具进程
/// </summary>
internal static bool IsCLTProcess { get; set; }
}
}
}
+22 -13
View File
@@ -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;
}
/// <summary>
/// 是否最小化
/// </summary>
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;
}
/// <summary>
/// 是否最小化启动
/// </summary>
public static bool IsMinimize { get; /*private*/ set; }
/// <summary>
/// 当前是否是命令行工具进程
/// </summary>
public static bool IsCLTProcess { get; private set; }
/// <summary>
/// 当前是否是主进程
/// </summary>
public static bool IsMainProcess { get; private set; }
}
}
}
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
@@ -13,4 +13,4 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<RuntimeIdentifier>win7-x86</RuntimeIdentifier>
<PublishReadyToRun Condition=" '$(OS)' == 'Windows_NT' ">true</PublishReadyToRun>
</PropertyGroup>
</Project>
</Project>
@@ -7,6 +7,7 @@
<!--(SignAssembly)对此程序集进行签名会导致编译失败(CompileAvaloniaXamlTask)-->
<RootNamespace>System.Application.UI</RootNamespace>
<AssemblyName>Steam++</AssemblyName>
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
<!--<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
@@ -40,7 +41,8 @@
<PropertyGroup Condition=" $(DefineConstants.Contains(`PUBLISH`)) ">
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>
<PublishTrimmed>True</PublishTrimmed>
<!--目前裁剪存在问题,禁用-->
<PublishTrimmed>false</PublishTrimmed>
<TrimMode>link</TrimMode>
<TrimmerRemoveSymbols>true</TrimmerRemoveSymbols>
<!--剪裁框架库功能 https://docs.microsoft.com/zh-cn/dotnet/core/deploying/trimming-options#trimming-framework-library-features -->
@@ -55,6 +57,11 @@
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
<!--<ItemGroup>
<TrimmerRootAssembly Include="CefNet" />
<TrimmerRootAssembly Include="CefNet.Avalonia" />
</ItemGroup>-->
<ItemGroup>
<Compile Include="..\Startup2.cs" />
<Compile Include="..\Common.CoreLib\Properties\AssemblyInfo.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);
}
/// <summary>
/// 当前是否是主进程
/// </summary>
public static bool IsMainProcess { get; private set; }
}
}
}
@@ -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
{
}
/// <summary>
/// 是否为主进程
/// </summary>
/// <returns></returns>
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
}
/// <summary>
/// 当前是否是主进程
/// </summary>
public static bool IsMainProcess { get; private set; }
}
}
}
+7 -2
View File
@@ -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);
}
/// <summary>
/// 当前是否是主进程
/// </summary>
public static bool IsMainProcess { get; private set; }
}
}
}
+9 -10
View File
@@ -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
/// <summary>
/// 当前是否是主进程
/// </summary>
internal static bool IsMainProcess { get; set; }
/// <inheritdoc cref="IActiveUserClient.Post(ActiveUserRecordDTO, Guid?)"/>
internal static async void ActiveUserPost(ActiveUserType type)
{
if (!IsMainProcess) return;
if (!Program.IsMainProcess) return;
try
{
#if !__MOBILE__
@@ -517,4 +516,4 @@ namespace System.Application
}
}
}
}
}