diff --git a/.gitmodules b/.gitmodules
index bd0331340..11e3339e2 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -25,3 +25,6 @@
[submodule "H.NotifyIcon"]
path = H.NotifyIcon
url = https://github.com/CollapseLauncher/H.NotifyIcon
+[submodule "Hi3Helper.Win32"]
+ path = Hi3Helper.Win32
+ url = https://github.com/CollapseLauncher/Hi3Helper.Win32
diff --git a/.idea/.idea.CollapseLauncher/.idea/vcs.xml b/.idea/.idea.CollapseLauncher/.idea/vcs.xml
index b5af8fbf9..ca3b0a334 100644
--- a/.idea/.idea.CollapseLauncher/.idea/vcs.xml
+++ b/.idea/.idea.CollapseLauncher/.idea/vcs.xml
@@ -10,6 +10,7 @@
+
diff --git a/CollapseLauncher.slnx b/CollapseLauncher.slnx
index fd78fee4e..616f6af95 100644
--- a/CollapseLauncher.slnx
+++ b/CollapseLauncher.slnx
@@ -62,6 +62,10 @@
+
+
+
+
diff --git a/CollapseLauncher/App.xaml.cs b/CollapseLauncher/App.xaml.cs
index 98fe54b4b..27fce7abd 100644
--- a/CollapseLauncher/App.xaml.cs
+++ b/CollapseLauncher/App.xaml.cs
@@ -3,6 +3,8 @@
using Hi3Helper;
using Hi3Helper.SentryHelper;
using Hi3Helper.Shared.Region;
+using Hi3Helper.Win32.Native;
+using Hi3Helper.Win32.Native.Enums;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
@@ -12,7 +14,6 @@
using System.Linq;
using Windows.UI;
using static CollapseLauncher.InnerLauncherConfig;
-using static Hi3Helper.InvokeProp;
using static Hi3Helper.Logger;
namespace CollapseLauncher
@@ -37,6 +38,7 @@ public App()
DebugSettings.XamlResourceReferenceFailed += static (sender, args) =>
{
LogWriteLine($"[XAML_RES_REFERENCE] Sender: {sender}\r\n{args!.Message}", LogType.Error, true);
+ SentryHelper.ExceptionHandler(new Exception($"{args.Message}"), SentryHelper.ExceptionType.UnhandledXaml);
#if !DEBUG
MainEntryPoint.SpawnFatalErrorConsole(new Exception(args!.Message));
#endif
@@ -45,6 +47,7 @@ public App()
DebugSettings.BindingFailed += static (sender, args) =>
{
LogWriteLine($"[XAML_BINDING] Sender: {sender}\r\n{args!.Message}", LogType.Error, true);
+ SentryHelper.ExceptionHandler(new Exception($"{args.Message}"), SentryHelper.ExceptionType.UnhandledXaml);
#if !DEBUG
MainEntryPoint.SpawnFatalErrorConsole(new Exception(args!.Message));
#endif
@@ -64,7 +67,7 @@ public App()
}
RequestedTheme = IsAppThemeLight ? ApplicationTheme.Light : ApplicationTheme.Dark;
- SetPreferredAppMode(ShouldAppsUseDarkMode() ? PreferredAppMode.AllowDark : PreferredAppMode.Default);
+ PInvoke.SetPreferredAppMode(PInvoke.ShouldAppsUseDarkMode() ? PreferredAppMode.AllowDark : PreferredAppMode.Default);
this.InitializeComponent();
}
diff --git a/CollapseLauncher/Classes/CoCreateInstance.cs b/CollapseLauncher/Classes/CoCreateInstance.cs
deleted file mode 100644
index a182bccfa..000000000
--- a/CollapseLauncher/Classes/CoCreateInstance.cs
+++ /dev/null
@@ -1,176 +0,0 @@
-// ReSharper disable All
-using System;
-using System.Diagnostics;
-using System.Globalization;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.Marshalling;
-
-#pragma warning disable IL2050
-namespace CollapseLauncher
-{
- internal enum CLSCTX : uint
- {
- /// The code that creates and manages objects of this class is a DLL that runs in the same process as the caller of the function specifying the class context.
- CLSCTX_INPROC_SERVER = 0x00000001,
- /// The code that manages objects of this class is an in-process handler. This is a DLL that runs in the client process and implements client-side structures of this class when instances of the class are accessed remotely.
- CLSCTX_INPROC_HANDLER = 0x00000002,
- /// The EXE code that creates and manages objects of this class runs on same machine but is loaded in a separate process space.
- CLSCTX_LOCAL_SERVER = 0x00000004,
- /// Obsolete.
- CLSCTX_INPROC_SERVER16 = 0x00000008,
- /// A remote context. The LocalServer32 or LocalService code that creates and manages objects of this class is run on a different computer.
- CLSCTX_REMOTE_SERVER = 0x00000010,
- /// Obsolete.
- CLSCTX_INPROC_HANDLER16 = 0x00000020,
- /// Reserved.
- CLSCTX_RESERVED1 = 0x00000040,
- /// Reserved.
- CLSCTX_RESERVED2 = 0x00000080,
- /// Reserved.
- CLSCTX_RESERVED3 = 0x00000100,
- /// Reserved.
- CLSCTX_RESERVED4 = 0x00000200,
- /// Disables the downloading of code from the directory service or the Internet. This flag cannot be set at the same time as CLSCTX_ENABLE_CODE_DOWNLOAD.
- CLSCTX_NO_CODE_DOWNLOAD = 0x00000400,
- /// Reserved.
- CLSCTX_RESERVED5 = 0x00000800,
- /// Specify if you want the activation to fail if it uses custom marshalling.
- CLSCTX_NO_CUSTOM_MARSHAL = 0x00001000,
- /// Enables the downloading of code from the directory service or the Internet. This flag cannot be set at the same time as CLSCTX_NO_CODE_DOWNLOAD.
- CLSCTX_ENABLE_CODE_DOWNLOAD = 0x00002000,
- ///
- /// The CLSCTX_NO_FAILURE_LOG can be used to override the logging of failures in CoCreateInstanceEx. If the ActivationFailureLoggingLevel is created, the following values can determine the status of event logging:
- /// This doc was truncated.
- /// Read more on docs.microsoft.com.
- ///
- CLSCTX_NO_FAILURE_LOG = 0x00004000,
- ///
- /// Disables activate-as-activator (AAA) activations for this activation only. This flag overrides the setting of the EOAC_DISABLE_AAA flag from the EOLE_AUTHENTICATION_CAPABILITIES enumeration. This flag cannot be set at the same time as CLSCTX_ENABLE_AAA. Any activation where a server process would be launched under the caller's identity is known as an activate-as-activator (AAA) activation. Disabling AAA activations allows an application that runs under a privileged account (such as LocalSystem) to help prevent its identity from being used to launch untrusted components. Library applications that use activation calls should always set this flag during those calls. This helps prevent the library application from being used in an escalation-of-privilege security attack. This is the only way to disable AAA activations in a library application because the EOAC_DISABLE_AAA flag from the EOLE_AUTHENTICATION_CAPABILITIES enumeration is applied only to the server process and not to the library application. Windows 2000: This flag is not supported.
- /// Read more on docs.microsoft.com.
- ///
- CLSCTX_DISABLE_AAA = 0x00008000,
- ///
- /// Enables activate-as-activator (AAA) activations for this activation only. This flag overrides the setting of the EOAC_DISABLE_AAA flag from the EOLE_AUTHENTICATION_CAPABILITIES enumeration. This flag cannot be set at the same time as CLSCTX_DISABLE_AAA. Any activation where a server process would be launched under the caller's identity is known as an activate-as-activator (AAA) activation. Enabling this flag allows an application to transfer its identity to an activated component. Windows 2000: This flag is not supported.
- /// Read more on docs.microsoft.com.
- ///
- CLSCTX_ENABLE_AAA = 0x00010000,
- /// Begin this activation from the default context of the current apartment.
- CLSCTX_FROM_DEFAULT_CONTEXT = 0x00020000,
- ///
- CLSCTX_ACTIVATE_X86_SERVER = 0x00040000,
- /// Activate or connect to a 32-bit version of the server; fail if one is not registered.
- CLSCTX_ACTIVATE_32_BIT_SERVER = 0x00040000,
- /// Activate or connect to a 64 bit version of the server; fail if one is not registered.
- CLSCTX_ACTIVATE_64_BIT_SERVER = 0x00080000,
- ///
- /// When this flag is specified, COM uses the impersonation token of the thread, if one is present, for the activation request made by the thread. When this flag is not specified or if the thread does not have an impersonation token, COM uses the process token of the thread's process for the activation request made by the thread.
- /// Windows Vista or later: This flag is supported.
- /// Read more on docs.microsoft.com.
- ///
- CLSCTX_ENABLE_CLOAKING = 0x00100000,
- ///
- /// Indicates activation is for an app container.
- ///
Note This flag is reserved for internal use and is not intended to be used directly from your code.
- /// Read more on docs.microsoft.com.
- ///
- CLSCTX_APPCONTAINER = 0x00400000,
- ///
- /// Specify this flag for Interactive User activation behavior for As-Activator servers. A strongly named Medium IL Windows Store app can use this flag to launch an "As Activator" COM server without a strong name. Also, you can use this flag to bind to a running instance of the COM server that's launched by a desktop application. The client must be Medium IL, it must be strongly named, which means that it has a SysAppID in the client token, it can't be in session 0, and it must have the same user as the session ID's user in the client token. If the server is out-of-process and "As Activator", it launches the server with the token of the client token's session user. This token won't be strongly named. If the server is out-of-process and RunAs "Interactive User", this flag has no effect. If the server is out-of-process and is any other RunAs type, the activation fails. This flag has no effect for in-process servers. Off-machine activations fail when they use this flag.
- /// Read more on docs.microsoft.com.
- ///
- CLSCTX_ACTIVATE_AAA_AS_IU = 0x00800000,
- ///
- CLSCTX_RESERVED6 = 0x01000000,
- ///
- CLSCTX_ACTIVATE_ARM32_SERVER = 0x02000000,
- CLSCTX_ALLOW_LOWER_TRUST_REGISTRATION = 0x04000000,
- ///
- /// Used for loading Proxy/Stub DLLs.
- ///
Note This flag is reserved for internal use and is not intended to be used directly from your code.
- /// Read more on docs.microsoft.com.
- ///
- CLSCTX_PS_DLL = 0x80000000,
- CLSCTX_ALL = 0x00000017,
- CLSCTX_SERVER = 0x00000015,
- }
-
- internal readonly partial struct HRESULT
- : IEquatable
- {
- internal readonly int Value;
- internal HRESULT(int value) => this.Value = value;
- public static implicit operator int(HRESULT value) => value.Value;
- public static implicit operator uint(HRESULT value) => (uint)value.Value;
- public static explicit operator HRESULT(int value) => new HRESULT(value);
- public static explicit operator HRESULT(uint value) => new HRESULT((int)value);
- public static bool operator ==(HRESULT left, HRESULT right) => left.Value == right.Value;
- public static bool operator !=(HRESULT left, HRESULT right) => !(left == right);
- public bool Equals(HRESULT other) => this.Value == other.Value;
- public override bool Equals(object obj) => obj is HRESULT other && this.Equals(other);
- public override int GetHashCode() => this.Value.GetHashCode();
- public override string ToString() => string.Format(CultureInfo.InvariantCulture, "0x{0:X8}", this.Value);
-
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- internal bool Succeeded => this.Value >= 0;
-
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
- internal bool Failed => this.Value < 0;
-
- ///
- ///
- /// A pointer to the IErrorInfo interface that provides more information about the
- /// error. You can specify to use the current IErrorInfo interface, or
- /// new IntPtr(-1) to ignore the current IErrorInfo interface and construct the exception
- /// just from the error code.
- ///
- /// , if it does not reflect an error.
- ///
- internal HRESULT ThrowOnFailure(IntPtr errorInfo = default)
- {
- Marshal.ThrowExceptionForHR(this.Value, errorInfo);
- return this;
- }
-
- internal string ToString(string format, IFormatProvider formatProvider) => ((uint)this.Value).ToString(format, formatProvider);
- }
-
- internal static partial class PInvoke
- {
-#nullable enable
- internal static unsafe HRESULT CoCreateInstance(Guid rclsid, nint pUnkOuter, CLSCTX dwClsContext, out T? ppv)
- {
- Guid refTGuid = typeof(T).GUID;
- HRESULT hr = CoCreateInstance(in rclsid, pUnkOuter, dwClsContext, in refTGuid, out void* o);
- ppv = ComInterfaceMarshaller.ConvertToManaged(o);
- return hr;
- }
-
- [DllImport("OLE32.dll", EntryPoint = "CoCreateInstance", ExactSpelling = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- public static unsafe extern HRESULT CoCreateInstance(in Guid rclsid, IntPtr pUnkOuter, CLSCTX dwClsContext, in Guid riid, out void* ppObj);
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static unsafe TInterfaceTo? CastComInterfaceAs(this TInterfaceFrom interfaceFrom, in Guid interfaceToGuid)
- where TInterfaceFrom : class
- where TInterfaceTo : class
- {
- void* interfaceFromPtr = ComInterfaceMarshaller.ConvertToUnmanaged(interfaceFrom);
-
- Marshal.QueryInterface((nint)interfaceFromPtr, in interfaceToGuid, out nint ppv);
- void* interfaceToPtr = (void*)ppv;
-
- TInterfaceTo? interfaceTo = ComInterfaceMarshaller.ConvertToManaged(interfaceToPtr);
- return interfaceTo;
- }
-
- internal static unsafe void Free(T? obj)
- where T : class
- {
- void* objPtr = ComInterfaceMarshaller.ConvertToUnmanaged(obj);
- ComInterfaceMarshaller.Free(objPtr);
- }
-#nullable restore
- }
-}
-#pragma warning restore IL2050
diff --git a/CollapseLauncher/Classes/FileDialogCOM/FileDialogHelper.cs b/CollapseLauncher/Classes/FileDialog/FileDialogHelper.cs
similarity index 95%
rename from CollapseLauncher/Classes/FileDialogCOM/FileDialogHelper.cs
rename to CollapseLauncher/Classes/FileDialog/FileDialogHelper.cs
index 3d4ec0a79..9a1f7652c 100644
--- a/CollapseLauncher/Classes/FileDialogCOM/FileDialogHelper.cs
+++ b/CollapseLauncher/Classes/FileDialog/FileDialogHelper.cs
@@ -1,19 +1,18 @@
using CollapseLauncher.Dialogs;
using CollapseLauncher.Extension;
-using CollapseLauncher.FileDialogCOM;
using CollapseLauncher.Helper;
using Hi3Helper;
using Hi3Helper.Data;
using Hi3Helper.Shared.Region;
+using Hi3Helper.Win32.FileDialogCOM;
using Microsoft.UI.Text;
using Microsoft.UI.Xaml.Controls;
using System;
using System.IO;
-using System.Linq;
using System.Threading.Tasks;
#nullable enable
-namespace CollapseLauncher.Classes.FileDialogCOM
+namespace CollapseLauncher.FileDialogCOM
{
internal static class FileDialogHelper
{
@@ -95,7 +94,7 @@ await SpawnInvalidDialog(
return dirPath;
- async Task SpawnInvalidDialog(string title, string message, string selectedPath, bool isUseLegacyFormatting = false)
+ async Task SpawnInvalidDialog(string dialogTitle, string message, string selectedPath, bool isUseLegacyFormatting = false)
{
TextBlock textBlock = new TextBlock()
{
@@ -113,7 +112,7 @@ async Task SpawnInvalidDialog(string title, string message, string selectedPath,
}
await SimpleDialogs.SpawnDialog(
- isUseLegacyFormatting ? title : string.Format(Locale.Lang._Dialogs.InvalidGameDirNewTitleFormat, title),
+ isUseLegacyFormatting ? dialogTitle : string.Format(Locale.Lang._Dialogs.InvalidGameDirNewTitleFormat, dialogTitle),
textBlock,
(WindowUtility.CurrentWindow as MainWindow)?.Content,
Locale.Lang._Misc.Okay,
diff --git a/CollapseLauncher/Classes/FileDialogCOM/Enums.cs b/CollapseLauncher/Classes/FileDialogCOM/Enums.cs
deleted file mode 100644
index 854c4d628..000000000
--- a/CollapseLauncher/Classes/FileDialogCOM/Enums.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System;
-
-namespace CollapseLauncher.FileDialogCOM
-{
- [Flags]
- internal enum FOS : uint
- {
- FOS_OVERWRITEPROMPT = 0x00000002,
- FOS_STRICTFILETYPES = 0x00000004,
- FOS_NOCHANGEDIR = 0x00000008,
- FOS_PICKFOLDERS = 0x00000020,
- FOS_FORCEFILESYSTEM = 0x00000040, // Ensure that items returned are filesystem items.
- FOS_ALLNONSTORAGEITEMS = 0x00000080, // Allow choosing items that have no storage.
- FOS_NOVALIDATE = 0x00000100,
- FOS_ALLOWMULTISELECT = 0x00000200,
- FOS_PATHMUSTEXIST = 0x00000800,
- FOS_FILEMUSTEXIST = 0x00001000,
- FOS_CREATEPROMPT = 0x00002000,
- FOS_SHAREAWARE = 0x00004000,
- FOS_NOREADONLYRETURN = 0x00008000,
- FOS_NOTESTFILECREATE = 0x00010000,
- FOS_HIDEMRUPLACES = 0x00020000,
- FOS_HIDEPINNEDPLACES = 0x00040000,
- FOS_NODEREFERENCELINKS = 0x00100000,
- FOS_DONTADDTORECENT = 0x02000000,
- FOS_FORCESHOWHIDDEN = 0x10000000,
- FOS_DEFAULTNOMINIMODE = 0x20000000
- }
-
- internal enum SIATTRIBFLAGS
- {
- SIATTRIBFLAGS_AND = 0x00000001, // if multiple items and the attributes together.
- SIATTRIBFLAGS_OR = 0x00000002, // if multiple items or the attributes together.
- SIATTRIBFLAGS_APPCOMPAT = 0x00000003, // Call GetAttributes directly on the ShellFolder for multiple attributes
- }
-
- internal enum SIGDN : uint
- {
- SIGDN_NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL
- SIGDN_PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING
- SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING
- SIGDN_PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING
- SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR
- SIGDN_FILESYSPATH = 0x80058000, // SHGDN_FORPARSING
- SIGDN_URL = 0x80068000, // SHGDN_FORPARSING
- SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR
- SIGDN_PARENTRELATIVE = 0x80080001 // SHGDN_INFOLDER
- }
-}
diff --git a/CollapseLauncher/Classes/FileDialogCOM/FileDialogNative.cs b/CollapseLauncher/Classes/FileDialogCOM/FileDialogNative.cs
deleted file mode 100644
index ac8fafaee..000000000
--- a/CollapseLauncher/Classes/FileDialogCOM/FileDialogNative.cs
+++ /dev/null
@@ -1,222 +0,0 @@
-using Hi3Helper;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.InteropServices;
-using System.Threading.Tasks;
-using Hi3Helper.SentryHelper;
-
-namespace CollapseLauncher.FileDialogCOM
-{
- /*
- * Reference:
- * https://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/WinForms/Managed/System/WinForms/FileDialog_Vista_Interop@cs/1305376/FileDialog_Vista_Interop@cs
- *
- * UPDATE: 2023-11-01
- * This code has been modified to support ILTrimming and Native AOT
- * by using Source-generated COM Wrappers on .NET 8.
- *
- * Please refer to this link for more information:
- * https://learn.microsoft.com/en-us/dotnet/standard/native-interop/comwrappers-source-generation
- */
- [SuppressMessage("ReSharper", "UnusedTypeParameter")]
- public static class FileDialogNative
- {
- private static IntPtr parentHandler = IntPtr.Zero;
- public static void InitHandlerPointer(IntPtr handle) => parentHandler = handle;
-
- public static async ValueTask GetFilePicker(Dictionary FileTypeFilter = null, string title = null) =>
- (string)await GetPickerOpenTask(string.Empty, FileTypeFilter, title);
-
- public static async ValueTask GetMultiFilePicker(Dictionary FileTypeFilter = null, string title = null) =>
- (string[])await GetPickerOpenTask(Array.Empty(), FileTypeFilter, title, true);
-
- public static async ValueTask GetFolderPicker(string title = null) =>
- (string)await GetPickerOpenTask(string.Empty, null, title, false, true);
-
- public static async ValueTask GetMultiFolderPicker(string title = null) =>
- (string[])await GetPickerOpenTask(Array.Empty(), null, title, true, true);
-
- public static async ValueTask GetFileSavePicker(Dictionary FileTypeFilter = null, string title = null) =>
- await GetPickerSaveTask(string.Empty, FileTypeFilter, title);
-
- private static ValueTask