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 GetPickerOpenTask(object defaultValue, Dictionary FileTypeFilter = null, - string title = null, bool isMultiple = false, bool isFolder = false) - { - PInvoke.CoCreateInstance( - new Guid(CLSIDGuid.FileOpenDialog), - IntPtr.Zero, - CLSCTX.CLSCTX_INPROC_SERVER, - out IFileOpenDialog dialog).ThrowOnFailure(); - - IntPtr titlePtr = IntPtr.Zero; - - try - { - if (title != null) dialog!.SetTitle(titlePtr = UnicodeStringToCOMPtr(title)); - SetFileTypeFilter(dialog, FileTypeFilter); - - FOS mode = isMultiple ? FOS.FOS_NOREADONLYRETURN | FOS.FOS_DONTADDTORECENT | FOS.FOS_ALLOWMULTISELECT : - FOS.FOS_NOREADONLYRETURN | FOS.FOS_DONTADDTORECENT; - - if (isFolder) mode |= FOS.FOS_PICKFOLDERS; - - dialog!.SetOptions(mode); - if (dialog.Show(parentHandler) < 0) return new ValueTask(defaultValue); - - if (isMultiple) - { - IShellItemArray resShell; - dialog.GetResults(out resShell); - return new ValueTask(GetIShellItemArray(resShell)); - } - else - { - IShellItem resShell; - dialog.GetResult(out resShell); - resShell!.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out IntPtr resultPtr); - return new ValueTask(COMPtrToUnicodeString(resultPtr)); - } - } - catch (COMException ex) - { - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); - Logger.LogWriteLine($"COM Exception: {ex}", LogType.Error, true); - return new ValueTask(defaultValue); - } - finally - { - if (titlePtr != IntPtr.Zero) Marshal.FreeCoTaskMem(titlePtr); - // Free the COM instance - PInvoke.Free(dialog); - } - } - - private static ValueTask GetPickerSaveTask(string defaultValue, Dictionary FileTypeFilter = null, string title = null) - { - PInvoke.CoCreateInstance( - new Guid(CLSIDGuid.FileSaveDialog), - IntPtr.Zero, - CLSCTX.CLSCTX_INPROC_SERVER, - out IFileSaveDialog dialog).ThrowOnFailure(); - - IntPtr titlePtr = IntPtr.Zero; - - try - { - if (title != null) dialog!.SetTitle(titlePtr = UnicodeStringToCOMPtr(title)); - SetFileTypeFilter(dialog, FileTypeFilter); - - FOS mode = FOS.FOS_NOREADONLYRETURN | FOS.FOS_DONTADDTORECENT; - - dialog!.SetOptions(mode); - if (dialog.Show(parentHandler) < 0) return new ValueTask(defaultValue); - - IShellItem resShell; - dialog.GetResult(out resShell); - resShell!.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out IntPtr resultPtr); - return new ValueTask(COMPtrToUnicodeString(resultPtr)); - } - catch (COMException ex) - { - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); - Logger.LogWriteLine($"COM Exception: {ex}", LogType.Error, true); - return new ValueTask(defaultValue); - } - finally - { - if (titlePtr != IntPtr.Zero) Marshal.FreeCoTaskMem(titlePtr); - // Free the COM instance - PInvoke.Free(dialog); - } - } - - private static void SetFileTypeFilter(IFileOpenDialog dialog, Dictionary FileTypeFilter) - { - if (FileTypeFilter != null) - { - int len = FileTypeFilter.Count; - int i = 0; - COMDLG_FILTERSPEC[] array = new COMDLG_FILTERSPEC[len]; - foreach (KeyValuePair entry in FileTypeFilter) - array[i++] = new COMDLG_FILTERSPEC { pszName = entry.Key, pszSpec = entry.Value }; - - IntPtr structPtr = ArrayToHGlobalPtr(array); - dialog!.SetFileTypes((uint)len, structPtr); - Marshal.FreeHGlobal(structPtr); - } - } - - private static void SetFileTypeFilter(IFileSaveDialog dialog, Dictionary FileTypeFilter) - { - if (FileTypeFilter != null) - { - int len = FileTypeFilter.Count; - int i = 0; - COMDLG_FILTERSPEC[] array = new COMDLG_FILTERSPEC[len]; - foreach (KeyValuePair entry in FileTypeFilter) - array[i++] = new COMDLG_FILTERSPEC { pszName = entry.Key, pszSpec = entry.Value }; - - IntPtr structPtr = ArrayToHGlobalPtr(array); - dialog!.SetFileTypes((uint)len, structPtr); - Marshal.FreeHGlobal(structPtr); - } - } - - private static IntPtr ArrayToHGlobalPtr(T[] array) - { - int sizeOf = Marshal.SizeOf(); - - IntPtr structPtr = Marshal.AllocHGlobal(sizeOf * array!.Length); - long partPtrLong = structPtr.ToInt64(); - for (int i = 0; i < array.Length; i++) - { - IntPtr partPtr = new IntPtr(partPtrLong); - Marshal.StructureToPtr(array[i]!, partPtr, false); - partPtrLong += sizeOf; - } - - return structPtr; - } - - private static IntPtr UnicodeStringToCOMPtr(string str) => Marshal.StringToCoTaskMemUni(str); - - private static string COMPtrToUnicodeString(IntPtr ptr) - { - try - { - string result = Marshal.PtrToStringUni(ptr); - return result; - } - catch (Exception e) - { - SentryHelper.ExceptionHandler(e, SentryHelper.ExceptionType.UnhandledOther); - Logger.LogWriteLine($"Error while marshalling COM Pointer {ptr} to string!\r\n{e}"); - throw; - } - finally - { - if (ptr != IntPtr.Zero) Marshal.FreeCoTaskMem(ptr); - } - } - - private static string[] GetIShellItemArray(IShellItemArray itemArray) - { - IShellItem item; - uint fileCount; - - itemArray!.GetCount(out fileCount); - string[] results = new string[fileCount]; - - for (uint i = 0; i < fileCount; i++) - { - itemArray.GetItemAt(i, out item); - if (item == null) throw new COMException($"FileDialogNative::GetIShellItemArray returning null!\r\n"); - item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out IntPtr _resPtr); - results[0] = COMPtrToUnicodeString(_resPtr); - } - - return results; - } - } -} diff --git a/CollapseLauncher/Classes/FileDialogCOM/Guid.cs b/CollapseLauncher/Classes/FileDialogCOM/Guid.cs deleted file mode 100644 index 7b985ae64..000000000 --- a/CollapseLauncher/Classes/FileDialogCOM/Guid.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace CollapseLauncher.FileDialogCOM -{ - internal class IIDGuid - { - internal const string IModalWindow = "B4DB1657-70D7-485E-8E3E-6FCB5A5C1802"; - internal const string IFileDialog = "42F85136-DB7E-439C-85F1-E4075D135FC8"; - internal const string IFileOpenDialog = "D57C7288-D4AD-4768-BE02-9D969532D960"; - internal const string IFileSaveDialog = "84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB"; - internal const string IFileDialogEvents = "973510DB-7D7F-452B-8975-74A85828D354"; - internal const string IShellItem = "43826D1E-E718-42EE-BC55-A1E261C37BFE"; - internal const string IShellItemArray = "B63EA76D-1F85-456F-A19C-48159EFA858B"; - } - - internal class CLSIDGuid - { - internal const string FileOpenDialog = "DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7"; - internal const string FileSaveDialog = "C0B4E2F3-BA21-4773-8DBA-335EC946EB8B"; - } -} diff --git a/CollapseLauncher/Classes/FileDialogCOM/Interfaces.cs b/CollapseLauncher/Classes/FileDialogCOM/Interfaces.cs deleted file mode 100644 index c0e43be6e..000000000 --- a/CollapseLauncher/Classes/FileDialogCOM/Interfaces.cs +++ /dev/null @@ -1,174 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -namespace CollapseLauncher.FileDialogCOM -{ - [Guid(IIDGuid.IShellItemArray)] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [GeneratedComInterface] - internal partial interface IShellItemArray - { - // Not supported: IBindCtx - void BindToHandler(IntPtr pbc, ref Guid rbhid, ref Guid riid, out IntPtr ppvOut); - - void GetPropertyStore(int Flags, ref Guid riid, out IntPtr ppv); - - void GetPropertyDescriptionList(ref PROPERTYKEY keyType, ref Guid riid, out IntPtr ppv); - - void GetAttributes(SIATTRIBFLAGS dwAttribFlags, uint sfgaoMask, out uint psfgaoAttribs); - - void GetCount(out uint pdwNumItems); - - void GetItemAt(uint dwIndex, out IShellItem ppsi); - - void EnumItems(out IntPtr ppenumShellItems); - } - - [Guid(IIDGuid.IFileOpenDialog)] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [GeneratedComInterface] - internal partial interface IFileOpenDialog - { - [PreserveSig] - int Show(IntPtr parent); - - void SetFileTypes(uint cFileTypes, IntPtr rgFilterSpec); - - void SetFileTypeIndex(uint iFileType); - - void GetFileTypeIndex(out uint piFileType); - - void Advise(IFileDialogEvents pfde, out uint pdwCookie); - - void Unadvise(uint dwCookie); - - void SetOptions(FOS fos); - - void GetOptions(out FOS pfos); - - void SetDefaultFolder(IShellItem psi); - - void SetFolder(IShellItem psi); - - void GetFolder(out IShellItem ppsi); - - void GetCurrentSelection(out IShellItem ppsi); - - void SetFileName(IntPtr pszName); - - void GetFileName(out IntPtr pszName); - - void SetTitle(IntPtr pszTitle); - - void SetOkButtonLabel(IntPtr pszText); - - void SetFileNameLabel(IntPtr pszLabel); - - void GetResult(out IShellItem ppsi); - - // Argument: IShellItem psi, FileDialogCustomPlace (no longer available) fdcp - void AddPlace(IShellItem psi, IntPtr fdcp); - - void SetDefaultExtension(IntPtr pszDefaultExtension); - - void Close(int hr); - - void SetClientGuid(ref Guid guid); - - void ClearClientData(); - - void SetFilter(IntPtr pFilter); - - void GetResults(out IShellItemArray ppenum); - - void GetSelectedItems(out IShellItemArray ppsai); - } - - [Guid(IIDGuid.IFileSaveDialog)] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [GeneratedComInterface(Options = ComInterfaceOptions.ComObjectWrapper)] - internal partial interface IFileSaveDialog - { - [PreserveSig] - int Show(IntPtr parent); - - void SetFileTypes(uint cFileTypes, IntPtr rgFilterSpec); - - void SetFileTypeIndex(uint iFileType); - - void GetFileTypeIndex(out uint piFileType); - - void Advise(IFileDialogEvents pfde, out uint pdwCookie); - - void Unadvise(uint dwCookie); - - void SetOptions(FOS fos); - - void GetOptions(out FOS pfos); - - void SetDefaultFolder(IShellItem psi); - - void SetFolder(IShellItem psi); - - void GetFolder(out IShellItem ppsi); - - void GetCurrentSelection(out IShellItem ppsi); - - void SetFileName(IntPtr pszName); - - void GetFileName(out IntPtr pszName); - - void SetTitle(IntPtr pszTitle); - - void SetOkButtonLabel(IntPtr pszText); - - void SetFileNameLabel(IntPtr pszLabel); - - void GetResult(out IShellItem ppsi); - - // Argument: IShellItem psi, FileDialogCustomPlace (no longer available) fdcp - void AddPlace(IShellItem psi, IntPtr fdcp); - - void SetDefaultExtension(IntPtr pszDefaultExtension); - - void Close([MarshalAs(UnmanagedType.Error)] int hr); - - void SetClientGuid(ref Guid guid); - - void ClearClientData(); - - void SetFilter(IntPtr pFilter); - - void SetSaveAsItem(IShellItem psi); - - void SetProperties(IntPtr pStore); - - void SetCollectedProperties(IntPtr pList, int fAppendDefault); - - void GetProperties(out IntPtr ppStore); - - void ApplyProperties(IShellItem psi, IntPtr pStore, ref IntPtr hwnd, IntPtr pSink); - } - - [Guid(IIDGuid.IFileDialogEvents)] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [GeneratedComInterface] - internal partial interface IFileDialogEvents; // This dialog is no longer being used - - [Guid(IIDGuid.IShellItem)] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [GeneratedComInterface] - internal partial interface IShellItem - { - void BindToHandler(IntPtr pbc, ref Guid bhid, ref Guid riid, out IntPtr ppv); - - void GetParent(out IShellItem ppsi); - - void GetDisplayName(SIGDN sigdnName, out IntPtr ppszName); - - void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs); - - void Compare(IShellItem psi, uint hint, out int piOrder); - } -} diff --git a/CollapseLauncher/Classes/FileDialogCOM/Structs.cs b/CollapseLauncher/Classes/FileDialogCOM/Structs.cs deleted file mode 100644 index ee859a292..000000000 --- a/CollapseLauncher/Classes/FileDialogCOM/Structs.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -// ReSharper disable PartialTypeWithSinglePart - -namespace CollapseLauncher.FileDialogCOM -{ - [StructLayout(LayoutKind.Sequential, Pack = 4)] - internal partial struct PROPERTYKEY - { - internal Guid fmtid; - internal uint pid; - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] - - internal partial struct COMDLG_FILTERSPEC - { - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszName; - [MarshalAs(UnmanagedType.LPWStr)] - internal string pszSpec; - } -} diff --git a/CollapseLauncher/Classes/FileMigrationProcess/FileMigrationProcess.cs b/CollapseLauncher/Classes/FileMigrationProcess/FileMigrationProcess.cs index a51d7d209..7726b6a21 100644 --- a/CollapseLauncher/Classes/FileMigrationProcess/FileMigrationProcess.cs +++ b/CollapseLauncher/Classes/FileMigrationProcess/FileMigrationProcess.cs @@ -1,4 +1,4 @@ -using CollapseLauncher.Classes.FileDialogCOM; +using CollapseLauncher.FileDialogCOM; using Hi3Helper; using Hi3Helper.Shared.Region; using Microsoft.UI.Xaml; diff --git a/CollapseLauncher/Classes/FileMigrationProcess/Statics.cs b/CollapseLauncher/Classes/FileMigrationProcess/Statics.cs index 8e6d4237b..a3a305699 100644 --- a/CollapseLauncher/Classes/FileMigrationProcess/Statics.cs +++ b/CollapseLauncher/Classes/FileMigrationProcess/Statics.cs @@ -1,6 +1,6 @@ -using CollapseLauncher.Classes.FileDialogCOM; -using CollapseLauncher.CustomControls; +using CollapseLauncher.CustomControls; using CollapseLauncher.Dialogs; +using CollapseLauncher.FileDialogCOM; using Hi3Helper.Data; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; diff --git a/CollapseLauncher/Classes/FileMigrationProcess/UIBuilder.cs b/CollapseLauncher/Classes/FileMigrationProcess/UIBuilder.cs index d64ff8bb7..1dd30a0e1 100644 --- a/CollapseLauncher/Classes/FileMigrationProcess/UIBuilder.cs +++ b/CollapseLauncher/Classes/FileMigrationProcess/UIBuilder.cs @@ -1,10 +1,10 @@ -using CollapseLauncher.Classes.FileDialogCOM; -using CollapseLauncher.CustomControls; +using CollapseLauncher.CustomControls; using CollapseLauncher.Dialogs; using CollapseLauncher.Extension; using CollapseLauncher.FileDialogCOM; using Hi3Helper; using Hi3Helper.Data; +using Hi3Helper.Win32.FileDialogCOM; using Microsoft.UI.Text; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/ImportExportBase.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/ImportExportBase.cs index daea49d27..9cb1b83cc 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/ImportExportBase.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/BaseClass/ImportExportBase.cs @@ -1,8 +1,8 @@ -using CollapseLauncher.FileDialogCOM; -using Hi3Helper; +using Hi3Helper; using Hi3Helper.EncTool; using Hi3Helper.UABT; using Hi3Helper.UABT.Binary; +using Hi3Helper.Win32.FileDialogCOM; using Microsoft.Win32; using System; using System.Buffers; @@ -399,7 +399,7 @@ private void EnsureFileSaveHasExtension(ref string path, string exte) { if (string.IsNullOrEmpty(path)) return; string ext = Path.GetExtension(path); - + if (string.IsNullOrEmpty(ext)) { path += exte; diff --git a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/ScreenManager.cs b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/ScreenManager.cs index 56239204b..c21b587a1 100644 --- a/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/ScreenManager.cs +++ b/CollapseLauncher/Classes/GameManagement/GameSettings/Genshin/RegistryClass/ScreenManager.cs @@ -1,8 +1,8 @@ using CollapseLauncher.GameSettings.Base; +using CollapseLauncher.Helper; using CollapseLauncher.Interfaces; using Hi3Helper; using Hi3Helper.EncTool; -using Hi3Helper.Screen; using Microsoft.Win32; using System; using System.Drawing; @@ -17,7 +17,7 @@ internal class ScreenManager : BaseScreenSettingData, IGameSettingsValue InvokeProp.IsProcessExist(_GameExecutableName, Path.Combine(_GameVersion?.GameDirPath ?? "", _GameExecutableName)); + get => PInvoke.IsProcessExist(_GameExecutableName, out _, out _, Path.Combine(_GameVersion?.GameDirPath ?? "", _GameExecutableName), ILoggerHelper.GetILogger()); } #nullable enable @@ -127,7 +128,7 @@ internal bool IsGameRunning Process process = processArr[i]; int processId = process.Id; - string? processPath = InvokeProp.GetProcessPathByProcessId(processId); + string? processPath = PInvoke.GetProcessPathByProcessId(processId, ILoggerHelper.GetILogger()); string expectedProcessPath = Path.Combine(_GameVersion?.GameDirPath ?? "", _GameExecutableName); if (string.IsNullOrEmpty(processPath) || !expectedProcessPath.Equals(processPath, StringComparison.OrdinalIgnoreCase) || process.MainWindowHandle == IntPtr.Zero) diff --git a/CollapseLauncher/Classes/Helper/TaskSchedulerHelper.cs b/CollapseLauncher/Classes/Helper/TaskSchedulerHelper.cs index 47a3f515e..436f534c2 100644 --- a/CollapseLauncher/Classes/Helper/TaskSchedulerHelper.cs +++ b/CollapseLauncher/Classes/Helper/TaskSchedulerHelper.cs @@ -1,13 +1,12 @@ -using CollapseLauncher.ShellLinkCOM; -using Hi3Helper; -using Hi3Helper.Data; +using Hi3Helper; +using Hi3Helper.SentryHelper; using Hi3Helper.Shared.Region; +using Hi3Helper.Win32.ShellLinkCOM; using System; using System.Diagnostics; using System.IO; using System.Text; using System.Threading.Tasks; -using Hi3Helper.SentryHelper; namespace CollapseLauncher.Helper { @@ -176,15 +175,13 @@ internal static void RecreateIconShortcuts() string currentExecDescription = currentExecVersionInfo.FileDescription ?? ""; // Create shell link instance and save the shortcut under Desktop and User's Start menu - using ShellLink shellLink = new ShellLink() - { - IconIndex = 0, - IconPath = currentExecPath, - DisplayMode = LinkDisplayMode.edmNormal, - WorkingDirectory = workingDirPath, - Target = currentExecPath, - Description = currentExecDescription - }; + using ShellLink shellLink = new ShellLink(); + shellLink.IconIndex = 0; + shellLink.IconPath = currentExecPath; + shellLink.DisplayMode = LinkDisplayMode.edmNormal; + shellLink.WorkingDirectory = workingDirPath ?? ""; + shellLink.Target = currentExecPath; + shellLink.Description = currentExecDescription; // Get paths string shortcutFilename = currentExecVersionInfo.ProductName + ".lnk"; @@ -193,7 +190,7 @@ internal static void RecreateIconShortcuts() string iconLocationStartMenu = Path.Combine( startMenuLocation, "Programs", - currentExecVersionInfo.CompanyName, + currentExecVersionInfo.CompanyName ?? "", shortcutFilename); string iconLocationDesktop = Path.Combine( desktopLocation, @@ -204,8 +201,8 @@ internal static void RecreateIconShortcuts() string iconLocationDesktopDir = Path.GetDirectoryName(iconLocationDesktop); // Try create directory - Directory.CreateDirectory(iconLocationStartMenuDir); - Directory.CreateDirectory(iconLocationDesktopDir); + Directory.CreateDirectory(iconLocationStartMenuDir!); + Directory.CreateDirectory(iconLocationDesktopDir!); // Save the icons shellLink.Save(iconLocationStartMenu); diff --git a/CollapseLauncher/Classes/Helper/Update/LauncherUpdateHelper.cs b/CollapseLauncher/Classes/Helper/Update/LauncherUpdateHelper.cs index 68ee0dc72..84a77d15d 100644 --- a/CollapseLauncher/Classes/Helper/Update/LauncherUpdateHelper.cs +++ b/CollapseLauncher/Classes/Helper/Update/LauncherUpdateHelper.cs @@ -74,7 +74,7 @@ internal static async Task IsUpdateAvailable(bool isForceCheckUpdate = fal IFileDownloader updateManagerHttpAdapter = new UpdateManagerHttpAdapter(); #if USEVELOPACK // Initialize update manager logger, locator and options - ILogger velopackLogger = ILoggerHelper.CreateCollapseILogger(); + ILogger velopackLogger = ILoggerHelper.GetILogger(); VelopackLocator updateManagerLocator = VelopackLocator.GetDefault(velopackLogger); UpdateOptions updateManagerOptions = new UpdateOptions { diff --git a/CollapseLauncher/Classes/Helper/WindowUtility.cs b/CollapseLauncher/Classes/Helper/WindowUtility.cs index 203c1c7ab..d1e00eb82 100644 --- a/CollapseLauncher/Classes/Helper/WindowUtility.cs +++ b/CollapseLauncher/Classes/Helper/WindowUtility.cs @@ -1,361 +1,365 @@ #nullable enable - using CollapseLauncher.Extension; - using CollapseLauncher.FileDialogCOM; - using H.NotifyIcon.Core; - using Hi3Helper; - using Hi3Helper.Screen; - using Hi3Helper.Shared.Region; - using Microsoft.Graphics.Display; - using Microsoft.UI; - using Microsoft.UI.Composition.SystemBackdrops; - using Microsoft.UI.Dispatching; - using Microsoft.UI.Input; - using Microsoft.UI.Windowing; - using Microsoft.UI.Xaml; - using Microsoft.UI.Xaml.Media; - using System; - using System.Runtime.InteropServices; - using Windows.Foundation; - using Windows.Graphics; - using Windows.UI; - using Hi3Helper.SentryHelper; - using WinRT.Interop; - using Size = System.Drawing.Size; - using WindowId = Microsoft.UI.WindowId; - - namespace CollapseLauncher.Helper +using CollapseLauncher.Extension; +using H.NotifyIcon.Core; +using Hi3Helper; +using Hi3Helper.SentryHelper; +using Hi3Helper.Shared.Region; +using Hi3Helper.Win32.FileDialogCOM; +using Hi3Helper.Win32.Native; +using Hi3Helper.Win32.Native.Enums; +using Hi3Helper.Win32.Native.Structs; +using Hi3Helper.Win32.Screen; +using Microsoft.Graphics.Display; +using Microsoft.UI; +using Microsoft.UI.Composition.SystemBackdrops; +using Microsoft.UI.Dispatching; +using Microsoft.UI.Input; +using Microsoft.UI.Windowing; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media; +using System; +using System.Runtime.InteropServices; +using Windows.Foundation; +using Windows.Graphics; +using Windows.UI; +using WinRT.Interop; +using Size = System.Drawing.Size; +using WindowId = Microsoft.UI.WindowId; + +namespace CollapseLauncher.Helper +{ + internal enum WindowBackdropKind { - internal enum WindowBackdropKind - { - Acrylic, - Mica, - MicaAlt, - None - } + Acrylic, + Mica, + MicaAlt, + None + } - internal static class WindowUtility - { - private static event EventHandler? DragAreaChangeEvent; + internal static class WindowUtility + { + private static event EventHandler? DragAreaChangeEvent; - private static nint OldMainWndProcPtr; - private static nint OldDesktopSiteBridgeWndProcPtr; + private static nint OldMainWndProcPtr; + private static nint OldDesktopSiteBridgeWndProcPtr; - private delegate IntPtr WndProcDelegate(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lParam); + private delegate IntPtr WndProcDelegate(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lParam); - internal static nint CurrentWindowPtr = nint.Zero; - internal static Window? CurrentWindow; - internal static AppWindow? CurrentAppWindow; - internal static WindowId? CurrentWindowId; - internal static OverlappedPresenter? CurrentOverlappedPresenter; + internal static nint CurrentWindowPtr = nint.Zero; + internal static Window? CurrentWindow; + internal static AppWindow? CurrentAppWindow; + internal static WindowId? CurrentWindowId; + internal static OverlappedPresenter? CurrentOverlappedPresenter; + internal static ScreenProp? CurrentScreenProp; - internal static DisplayArea? CurrentWindowDisplayArea + internal static DisplayArea? CurrentWindowDisplayArea + { + get { - get + if (!CurrentWindowId.HasValue) { - if (!CurrentWindowId.HasValue) - { - return null; - } - - return DisplayArea.GetFromWindowId(CurrentWindowId.Value, DisplayAreaFallback.Primary); + return null; } + + return DisplayArea.GetFromWindowId(CurrentWindowId.Value, DisplayAreaFallback.Primary); } + } - internal static DisplayInformation? CurrentWindowDisplayInformation + internal static DisplayInformation? CurrentWindowDisplayInformation + { + get { - get + try { - try + DispatcherQueue dispatcherQueue = DispatcherQueue.GetForCurrentThread(); + if (dispatcherQueue.HasThreadAccess) + { + return CurrentWindowId.HasValue + ? DisplayInformation.CreateForWindowId(CurrentWindowId.Value) + : null; + } + else { - DispatcherQueue dispatcherQueue = DispatcherQueue.GetForCurrentThread(); - if (dispatcherQueue.HasThreadAccess) + DisplayInformation? displayInfoInit = null; + dispatcherQueue.TryEnqueue(() => { - return CurrentWindowId.HasValue + displayInfoInit = CurrentWindowId.HasValue ? DisplayInformation.CreateForWindowId(CurrentWindowId.Value) : null; - } - else - { - DisplayInformation? displayInfoInit = null; - dispatcherQueue.TryEnqueue(() => - { - displayInfoInit = CurrentWindowId.HasValue - ? DisplayInformation.CreateForWindowId(CurrentWindowId.Value) - : null; - }); - return displayInfoInit; - } - } - catch (Exception ex) - { - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); - Logger.LogWriteLine($"An error has occured while getting display information\r\n{ex}", LogType.Error, true); + }); + return displayInfoInit; } - return null; } + catch (Exception ex) + { + SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); + Logger.LogWriteLine($"An error has occured while getting display information\r\n{ex}", LogType.Error, true); + } + return null; } + } - internal static DisplayAdvancedColorInfo? CurrentWindowDisplayColorInfo + internal static DisplayAdvancedColorInfo? CurrentWindowDisplayColorInfo + { + get { - get + DisplayInformation? displayInfo = CurrentWindowDisplayInformation; + if (displayInfo == null) { - DisplayInformation? displayInfo = CurrentWindowDisplayInformation; - if (displayInfo == null) - { - return null; - } - - return displayInfo.GetAdvancedColorInfo(); + return null; } + + return displayInfo.GetAdvancedColorInfo(); } + } - internal static bool CurrentWindowIsMaximizable + internal static bool CurrentWindowIsMaximizable + { + get => CurrentOverlappedPresenter != null && CurrentOverlappedPresenter.IsMaximizable; + set { - get => CurrentOverlappedPresenter != null && CurrentOverlappedPresenter.IsMaximizable; - set + if (CurrentOverlappedPresenter == null) { - if (CurrentOverlappedPresenter == null) - { - return; - } - - CurrentOverlappedPresenter.IsMaximizable = value; + return; } + + CurrentOverlappedPresenter.IsMaximizable = value; } + } - internal static bool CurrentWindowIsResizable + internal static bool CurrentWindowIsResizable + { + get => CurrentOverlappedPresenter != null && CurrentOverlappedPresenter.IsResizable; + set { - get => CurrentOverlappedPresenter != null && CurrentOverlappedPresenter.IsResizable; - set + if (CurrentOverlappedPresenter == null) { - if (CurrentOverlappedPresenter == null) - { - return; - } - - CurrentOverlappedPresenter.IsResizable = value; + return; } + + CurrentOverlappedPresenter.IsResizable = value; } + } - internal static nint CurrentWindowMonitorPtr + internal static nint CurrentWindowMonitorPtr + { + get { - get + DisplayArea? displayArea = CurrentWindowDisplayArea; + if (displayArea == null) { - DisplayArea? displayArea = CurrentWindowDisplayArea; - if (displayArea == null) - { - return nint.Zero; - } - - nint monitorPtr = Win32Interop.GetMonitorFromDisplayId(displayArea.DisplayId); - return monitorPtr; + return nint.Zero; } + + nint monitorPtr = Win32Interop.GetMonitorFromDisplayId(displayArea.DisplayId); + return monitorPtr; } + } - internal static uint CurrentWindowMonitorDpi + internal static uint CurrentWindowMonitorDpi + { + get { - get + const uint DefaultDpiValue = 96; + nint monitorPtr = CurrentWindowMonitorPtr; + if (monitorPtr == nint.Zero) { - const uint DefaultDpiValue = 96; - nint monitorPtr = CurrentWindowMonitorPtr; - if (monitorPtr == nint.Zero) - { - return DefaultDpiValue; - } - - if (InvokeProp.GetDpiForMonitor(monitorPtr, InvokeProp.Monitor_DPI_Type.MDT_Default, out uint dpi, - out uint _) == 0) - { - return dpi; - } - - Logger.LogWriteLine($"[WindowUtility::CurrentWindowMonitorDpi] Could not get DPI for the current monitor at 0x{monitorPtr:x8}"); return DefaultDpiValue; + } + if (PInvoke.GetDpiForMonitor(monitorPtr, Monitor_DPI_Type.MDT_Default, out uint dpi, + out uint _) == 0) + { + return dpi; } + + Logger.LogWriteLine($"[WindowUtility::CurrentWindowMonitorDpi] Could not get DPI for the current monitor at 0x{monitorPtr:x8}"); + return DefaultDpiValue; + } + } - internal static double CurrentWindowMonitorScaleFactor - // Deliberate loss of precision - // ReSharper disable once PossibleLossOfFraction - => (CurrentWindowMonitorDpi * 100 + (96 >> 1)) / 96 / 100.0; + internal static double CurrentWindowMonitorScaleFactor + // Deliberate loss of precision + // ReSharper disable once PossibleLossOfFraction + => (CurrentWindowMonitorDpi * 100 + (96 >> 1)) / 96 / 100.0; - internal static Rect CurrentWindowPosition + internal static Rect CurrentWindowPosition + { + get => CurrentWindow?.Bounds ?? default; + set { - get => CurrentWindow?.Bounds ?? default; - set + if (CurrentWindowPtr == nint.Zero || CurrentAppWindow == null) { - if (CurrentWindowPtr == nint.Zero || CurrentAppWindow == null) - { - return; - } + return; + } - if (InnerLauncherConfig.m_isWindows11) - { - // We have no title bar - var titleBarHeight = InvokeProp.GetSystemMetrics(InvokeProp.SystemMetric.SM_CYSIZEFRAME) + - InvokeProp.GetSystemMetrics(InvokeProp.SystemMetric.SM_CYCAPTION) + - InvokeProp.GetSystemMetrics(InvokeProp.SystemMetric.SM_CXPADDEDBORDER); - value.Height -= titleBarHeight; + if (InnerLauncherConfig.m_isWindows11) + { + // We have no title bar + var titleBarHeight = PInvoke.GetSystemMetrics(SystemMetric.SM_CYSIZEFRAME) + + PInvoke.GetSystemMetrics(SystemMetric.SM_CYCAPTION) + + PInvoke.GetSystemMetrics(SystemMetric.SM_CXPADDEDBORDER); + value.Height -= titleBarHeight; - CurrentAppWindow.ResizeClient(new SizeInt32 - { - Width = (int) value.Width, - Height = (int) value.Height - }); - CurrentAppWindow.Move(new PointInt32 - { - X = (int) value.X, - Y = (int) value.Y - }); - } - else + CurrentAppWindow.ResizeClient(new SizeInt32 { - CurrentAppWindow.MoveAndResize(new RectInt32() - { - Width = (int) value.Width, - Height = (int) value.Height, - X = (int) value.X, - Y = (int) value.Y - }); - } + Width = (int)value.Width, + Height = (int)value.Height + }); + CurrentAppWindow.Move(new PointInt32 + { + X = (int)value.X, + Y = (int)value.Y + }); + } + else + { + CurrentAppWindow.MoveAndResize(new RectInt32() + { + Width = (int)value.Width, + Height = (int)value.Height, + X = (int)value.X, + Y = (int)value.Y + }); } } + } - internal static string? CurrentWindowTitle + internal static string? CurrentWindowTitle + { + get => CurrentAppWindow?.Title; + set { - get => CurrentAppWindow?.Title; - set + if (CurrentAppWindow == null) { - if (CurrentAppWindow == null) - { - return; - } - - CurrentAppWindow.Title = value; + return; } + + CurrentAppWindow.Title = value; } + } - internal static bool CurrentWindowTitlebarExtendContent + internal static bool CurrentWindowTitlebarExtendContent + { + get => CurrentWindow?.ExtendsContentIntoTitleBar ?? false; + set { - get => CurrentWindow?.ExtendsContentIntoTitleBar ?? false; - set + if (CurrentWindow == null) { - if (CurrentWindow == null) - { - return; - } - - CurrentWindow.ExtendsContentIntoTitleBar = value; + return; } + + CurrentWindow.ExtendsContentIntoTitleBar = value; } + } - internal static TitleBarHeightOption CurrentWindowTitlebarHeightOption + internal static TitleBarHeightOption CurrentWindowTitlebarHeightOption + { + get => CurrentAppWindow?.TitleBar.PreferredHeightOption ?? TitleBarHeightOption.Standard; + set { - get => CurrentAppWindow?.TitleBar.PreferredHeightOption ?? TitleBarHeightOption.Standard; - set + if (CurrentAppWindow == null) { - if (CurrentAppWindow == null) - { - return; - } - - CurrentAppWindow.TitleBar.PreferredHeightOption = value; + return; } + + CurrentAppWindow.TitleBar.PreferredHeightOption = value; } + } - internal static IconShowOptions CurrentWindowTitlebarIconShowOption + internal static IconShowOptions CurrentWindowTitlebarIconShowOption + { + get => CurrentAppWindow?.TitleBar.IconShowOptions ?? IconShowOptions.ShowIconAndSystemMenu; + set { - get => CurrentAppWindow?.TitleBar.IconShowOptions ?? IconShowOptions.ShowIconAndSystemMenu; - set + if (CurrentAppWindow == null) { - if (CurrentAppWindow == null) - { - return; - } - - CurrentAppWindow.TitleBar.IconShowOptions = value; + return; } + + CurrentAppWindow.TitleBar.IconShowOptions = value; } + } - internal static void RegisterWindow(this Window window) - { - // Uninstall existing drag area change - UninstallDragAreaChangeMonitor(); + internal static void RegisterWindow(this Window window) + { + // Uninstall existing drag area change + UninstallDragAreaChangeMonitor(); - CurrentWindow = window; - CurrentWindowPtr = WindowNative.GetWindowHandle(window); - CurrentWindowId = Win32Interop.GetWindowIdFromWindow(CurrentWindowPtr); + CurrentWindow = window; + CurrentWindowPtr = WindowNative.GetWindowHandle(window); + CurrentWindowId = Win32Interop.GetWindowIdFromWindow(CurrentWindowPtr); - if (!CurrentWindowId.HasValue) - { - throw new NullReferenceException($"Window ID cannot be retrieved from pointer: 0x{CurrentWindowPtr:x8}"); - } + if (!CurrentWindowId.HasValue) + { + throw new NullReferenceException($"Window ID cannot be retrieved from pointer: 0x{CurrentWindowPtr:x8}"); + } - CurrentAppWindow = AppWindow.GetFromWindowId(CurrentWindowId.Value); - CurrentOverlappedPresenter = CurrentAppWindow.Presenter as OverlappedPresenter; + CurrentAppWindow = AppWindow.GetFromWindowId(CurrentWindowId.Value); + CurrentOverlappedPresenter = CurrentAppWindow.Presenter as OverlappedPresenter; - // Install WndProc callback - OldMainWndProcPtr = InstallWndProcCallback(CurrentWindowPtr, MainWndProc); + // Install WndProc callback + OldMainWndProcPtr = InstallWndProcCallback(CurrentWindowPtr, MainWndProc); - // Install Drag Area Change monitor - InstallDragAreaChangeMonitor(); + // Install Drag Area Change monitor + InstallDragAreaChangeMonitor(); - // Apply fix for mouse event - ApplyWindowTitlebarContextFix(); + // Apply fix for mouse event + ApplyWindowTitlebarContextFix(); - // Apply fix for Window border on Windows 10 - ApplyWindowBorderFix(); + // Apply fix for Window border on Windows 10 + ApplyWindowBorderFix(); - // Initialize FileDialogHandler - FileDialogNative.InitHandlerPointer(CurrentWindowPtr); - } + // Initialize FileDialogHandler + FileDialogNative.InitHandlerPointer(CurrentWindowPtr); + } - #region Drag Area Handler + #region Drag Area Handler - private static void InstallDragAreaChangeMonitor() - { - DragAreaChangeEvent += WindowDragAreaChangeEventHandler; - } + private static void InstallDragAreaChangeMonitor() + { + DragAreaChangeEvent += WindowDragAreaChangeEventHandler; + } - private static void UninstallDragAreaChangeMonitor() - { - DragAreaChangeEvent -= WindowDragAreaChangeEventHandler; - } + private static void UninstallDragAreaChangeMonitor() + { + DragAreaChangeEvent -= WindowDragAreaChangeEventHandler; + } - private static void WindowDragAreaChangeEventHandler(object? sender, RectInt32[] dragArea) + private static void WindowDragAreaChangeEventHandler(object? sender, RectInt32[] dragArea) + { + if (sender is AppWindow appWindow) { - if (sender is AppWindow appWindow) - { - appWindow.TitleBar.SetDragRectangles(dragArea); - } + appWindow.TitleBar.SetDragRectangles(dragArea); } + } - #endregion + #endregion - #region WndProc Handler + #region WndProc Handler - private static IntPtr InstallWndProcCallback(IntPtr hwnd, WndProcDelegate wndProc) - { - // Install WndProc hook - const int GWLP_WNDPROC = -4; - WndProcDelegate mNewWndProcDelegate = wndProc; - IntPtr pWndProc = Marshal.GetFunctionPointerForDelegate(mNewWndProcDelegate); - return InvokeProp.SetWindowLongPtr(hwnd, GWLP_WNDPROC, pWndProc); - } + private static IntPtr InstallWndProcCallback(IntPtr hwnd, WndProcDelegate wndProc) + { + // Install WndProc hook + const int GWLP_WNDPROC = -4; + WndProcDelegate mNewWndProcDelegate = wndProc; + IntPtr pWndProc = Marshal.GetFunctionPointerForDelegate(mNewWndProcDelegate); + return PInvoke.SetWindowLongPtr(hwnd, GWLP_WNDPROC, pWndProc); + } - private static IntPtr MainWndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lParam) + private static IntPtr MainWndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lParam) + { + const uint WM_SYSCOMMAND = 0x0112; + const uint WM_SHOWWINDOW = 0x0018; + const uint WM_NCHITTEST = 0x0084; + const uint WM_NCCALCSIZE = 0x0083; + const uint WM_SETTINGCHANGE = 0x001A; + const uint WM_ACTIVATE = 0x0006; + + switch (msg) { - const uint WM_SYSCOMMAND = 0x0112; - const uint WM_SHOWWINDOW = 0x0018; - const uint WM_NCHITTEST = 0x0084; - const uint WM_NCCALCSIZE = 0x0083; - const uint WM_SETTINGCHANGE = 0x001A; - const uint WM_ACTIVATE = 0x0006; - - switch (msg) - { - case WM_ACTIVATE: + case WM_ACTIVATE: { if (wParam == 1 && lParam == 0) MainPage.CurrentBackgroundHandler?.WindowFocused(); @@ -365,56 +369,56 @@ private static IntPtr MainWndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr break; } - case WM_SYSCOMMAND: + case WM_SYSCOMMAND: { const uint SC_MAXIMIZE = 0xF030; const uint SC_MINIMIZE = 0xF020; - const uint SC_RESTORE = 0xF120; + const uint SC_RESTORE = 0xF120; switch (wParam) { case SC_MAXIMIZE: - { - // TODO: Apply to force disable the "double-click to maximize" feature. - // The feature should expected to be disabled while m_presenter.IsResizable and IsMaximizable - // set to false. But the feature is still not respecting the changes in WindowsAppSDK 1.4. - // - // Issues have been described here: - // https://github.com/microsoft/microsoft-ui-xaml/issues/8666 - // https://github.com/microsoft/microsoft-ui-xaml/issues/8783 - - // Ignore WM_SYSCOMMAND SC_MAXIMIZE message - // Thank you Microsoft :) - return 0; - } + { + // TODO: Apply to force disable the "double-click to maximize" feature. + // The feature should expected to be disabled while m_presenter.IsResizable and IsMaximizable + // set to false. But the feature is still not respecting the changes in WindowsAppSDK 1.4. + // + // Issues have been described here: + // https://github.com/microsoft/microsoft-ui-xaml/issues/8666 + // https://github.com/microsoft/microsoft-ui-xaml/issues/8783 + + // Ignore WM_SYSCOMMAND SC_MAXIMIZE message + // Thank you Microsoft :) + return 0; + } case SC_MINIMIZE: - { - MainPage.CurrentBackgroundHandler?.WindowUnfocused(); - if (LauncherConfig.GetAppConfigValue("MinimizeToTray").ToBool()) { - // Carousel is handled inside WM_SHOWWINDOW message for minimize to tray - if (CurrentWindow is MainWindow mainWindow && mainWindow._TrayIcon != null) + MainPage.CurrentBackgroundHandler?.WindowUnfocused(); + if (LauncherConfig.GetAppConfigValue("MinimizeToTray").ToBool()) { - mainWindow._TrayIcon.ToggleAllVisibility(); + // Carousel is handled inside WM_SHOWWINDOW message for minimize to tray + if (CurrentWindow is MainWindow mainWindow && mainWindow._TrayIcon != null) + { + mainWindow._TrayIcon.ToggleAllVisibility(); + } + else TrayNullHandler("WindowUtility.MainWndProc"); + + return 0; } - else TrayNullHandler("WindowUtility.MainWndProc"); - return 0; + InnerLauncherConfig.m_homePage?.CarouselStopScroll(); + break; } - - InnerLauncherConfig.m_homePage?.CarouselStopScroll(); - break; - } case SC_RESTORE: - { - MainPage.CurrentBackgroundHandler?.WindowFocused(); - InnerLauncherConfig.m_homePage?.CarouselRestartScroll(); - break; - } + { + MainPage.CurrentBackgroundHandler?.WindowFocused(); + InnerLauncherConfig.m_homePage?.CarouselRestartScroll(); + break; + } } break; } - case WM_SHOWWINDOW: + case WM_SHOWWINDOW: { if (wParam == 0) { @@ -427,28 +431,28 @@ private static IntPtr MainWndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr } break; } - case WM_NCHITTEST: + case WM_NCHITTEST: { - const int HTCLIENT = 1; - const int HTCAPTION = 2; + const int HTCLIENT = 1; + const int HTCAPTION = 2; const int HTMINBUTTON = 8; - const int HTRIGHT = 11; - const int HTTOP = 12; - const int HTTOPRIGHT = 14; + const int HTRIGHT = 11; + const int HTTOP = 12; + const int HTTOPRIGHT = 14; - var result = InvokeProp.CallWindowProc(OldMainWndProcPtr, hwnd, msg, wParam, lParam); + var result = PInvoke.CallWindowProc(OldMainWndProcPtr, hwnd, msg, wParam, lParam); return result switch - { - // Fix "Ghost Minimize Button" issue - HTMINBUTTON => HTCLIENT, - // Fix "Caption Resize" issue - HTRIGHT => HTCAPTION, - HTTOP => HTCAPTION, - HTTOPRIGHT => HTCAPTION, - _ => result - }; + { + // Fix "Ghost Minimize Button" issue + HTMINBUTTON => HTCLIENT, + // Fix "Caption Resize" issue + HTRIGHT => HTCAPTION, + HTTOP => HTCAPTION, + HTTOPRIGHT => HTCAPTION, + _ => result + }; } - case WM_NCCALCSIZE: + case WM_NCCALCSIZE: { if (!InnerLauncherConfig.m_isWindows11 && wParam != 0) { @@ -457,262 +461,260 @@ private static IntPtr MainWndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr break; } - case WM_SETTINGCHANGE: + case WM_SETTINGCHANGE: { var setting = Marshal.PtrToStringAnsi(lParam); if (setting == "ImmersiveColorSet") { - InvokeProp.SetPreferredAppMode(InvokeProp.ShouldAppsUseDarkMode() - ? InvokeProp.PreferredAppMode.AllowDark - : InvokeProp.PreferredAppMode.Default); + PInvoke.SetPreferredAppMode(PInvoke.ShouldAppsUseDarkMode() + ? PreferredAppMode.AllowDark + : PreferredAppMode.Default); } break; } - } - - return InvokeProp.CallWindowProc(OldMainWndProcPtr, hwnd, msg, wParam, lParam); } - #endregion + return PInvoke.CallWindowProc(OldMainWndProcPtr, hwnd, msg, wParam, lParam); + } - #region Titlebar Methods + #endregion - private static void ApplyWindowTitlebarContextFix() - { - if (!CurrentWindowId.HasValue) - { - return; - } + #region Titlebar Methods - InputNonClientPointerSource incps = InputNonClientPointerSource.GetForWindowId(CurrentWindowId.Value); - incps.SetRegionRects(NonClientRegionKind.Close, null); - incps.SetRegionRects(NonClientRegionKind.Minimize, null); - EnableWindowNonClientArea(); + private static void ApplyWindowTitlebarContextFix() + { + if (!CurrentWindowId.HasValue) + { + return; } - internal static void ApplyWindowTitlebarLegacyColor() + InputNonClientPointerSource incps = InputNonClientPointerSource.GetForWindowId(CurrentWindowId.Value); + incps.SetRegionRects(NonClientRegionKind.Close, null); + incps.SetRegionRects(NonClientRegionKind.Minimize, null); + EnableWindowNonClientArea(); + } + + internal static void ApplyWindowTitlebarLegacyColor() + { + UIElementExtensions.SetApplicationResource("WindowCaptionForeground", + InnerLauncherConfig.IsAppThemeLight + ? new Color { A = 255, B = 0, G = 0, R = 0 } + : new Color { A = 255, B = 255, G = 255, R = 255 }); + UIElementExtensions.SetApplicationResource("WindowCaptionBackground", + new SolidColorBrush(new Color { A = 0, B = 0, G = 0, R = 0 })); + UIElementExtensions.SetApplicationResource("WindowCaptionBackgroundDisabled", + new SolidColorBrush(new Color { A = 0, B = 0, G = 0, R = 0 })); + } + + internal static void SetWindowBackdrop(WindowBackdropKind kind) + { + if (CurrentWindow == null) { - UIElementExtensions.SetApplicationResource("WindowCaptionForeground", - InnerLauncherConfig.IsAppThemeLight - ? new Color { A = 255, B = 0, G = 0, R = 0 } - : new Color { A = 255, B = 255, G = 255, R = 255 }); - UIElementExtensions.SetApplicationResource("WindowCaptionBackground", - new SolidColorBrush(new Color { A = 0, B = 0, G = 0, R = 0 })); - UIElementExtensions.SetApplicationResource("WindowCaptionBackgroundDisabled", - new SolidColorBrush(new Color { A = 0, B = 0, G = 0, R = 0 })); + return; } - internal static void SetWindowBackdrop(WindowBackdropKind kind) + CurrentWindow.SystemBackdrop = kind switch { - if (CurrentWindow == null) - { - return; - } + WindowBackdropKind.Acrylic => new DesktopAcrylicBackdrop(), + WindowBackdropKind.Mica => !InnerLauncherConfig.m_isWindows11 + ? new DesktopAcrylicBackdrop() + : new MicaBackdrop(), + WindowBackdropKind.MicaAlt => !InnerLauncherConfig.m_isWindows11 + ? new DesktopAcrylicBackdrop() + : new MicaBackdrop { Kind = MicaKind.BaseAlt }, + _ => null + }; + } - CurrentWindow.SystemBackdrop = kind switch - { - WindowBackdropKind.Acrylic => new DesktopAcrylicBackdrop(), - WindowBackdropKind.Mica => !InnerLauncherConfig.m_isWindows11 - ? new DesktopAcrylicBackdrop() - : new MicaBackdrop(), - WindowBackdropKind.MicaAlt => !InnerLauncherConfig.m_isWindows11 - ? new DesktopAcrylicBackdrop() - : new MicaBackdrop { Kind = MicaKind.BaseAlt }, - _ => null - }; + internal static void SetWindowTitlebarDefaultDragArea() + { + if (CurrentWindow == null) + { + return; } - internal static void SetWindowTitlebarDefaultDragArea() - { - if (CurrentWindow == null) - { - return; - } + double scaleFactor = CurrentWindowMonitorScaleFactor; + RectInt32[] dragRects = + [new(0, 0, (int)(CurrentWindow.Bounds.Width * scaleFactor), (int)(48 * scaleFactor))]; - double scaleFactor = CurrentWindowMonitorScaleFactor; - RectInt32[] dragRects = - [new(0, 0, (int)(CurrentWindow.Bounds.Width * scaleFactor), (int)(48 * scaleFactor))]; + DragAreaChangeEvent?.Invoke(CurrentAppWindow, dragRects); + } - DragAreaChangeEvent?.Invoke(CurrentAppWindow, dragRects); - } + internal static void SetWindowTitlebarDragArea(RectInt32[] dragAreas) + { + DragAreaChangeEvent?.Invoke(CurrentAppWindow, dragAreas); + } - internal static void SetWindowTitlebarDragArea(RectInt32[] dragAreas) + internal static void SetWindowTitlebarIcon(nint smallIconPtr, nint largeIconPtr) + { + if (smallIconPtr == nint.Zero || largeIconPtr == nint.Zero) { - DragAreaChangeEvent?.Invoke(CurrentAppWindow, dragAreas); + return; } - internal static void SetWindowTitlebarIcon(nint smallIconPtr, nint largeIconPtr) - { - if (smallIconPtr == nint.Zero || largeIconPtr == nint.Zero) - { - return; - } - - InvokeProp.SetWindowIcon(CurrentWindowPtr, smallIconPtr, largeIconPtr); - } + PInvoke.SetWindowIcon(CurrentWindowPtr, smallIconPtr, largeIconPtr); + } - #endregion + #endregion - #region Window state methods + #region Window state methods - private static void ApplyWindowBorderFix() + private static void ApplyWindowBorderFix() + { + // Hide window border but keep drop shadow + if (!InnerLauncherConfig.m_isWindows11) { - // Hide window border but keep drop shadow - if (!InnerLauncherConfig.m_isWindows11) + var margin = new MARGINS { - var margin = new InvokeProp.MARGINS - { - cyBottomHeight = 1 - }; - InvokeProp.DwmExtendFrameIntoClientArea(CurrentWindowPtr, ref margin); - - var flags = InvokeProp.SetWindowPosFlags.SWP_NOSIZE - | InvokeProp.SetWindowPosFlags.SWP_NOMOVE - | InvokeProp.SetWindowPosFlags.SWP_NOZORDER - | InvokeProp.SetWindowPosFlags.SWP_FRAMECHANGED; - InvokeProp.SetWindowPos(CurrentWindowPtr, 0, 0, 0, 0, 0, flags); - } + cyBottomHeight = 1 + }; + PInvoke.DwmExtendFrameIntoClientArea(CurrentWindowPtr, ref margin); + + var flags = SetWindowPosFlags.SWP_NOSIZE + | SetWindowPosFlags.SWP_NOMOVE + | SetWindowPosFlags.SWP_NOZORDER + | SetWindowPosFlags.SWP_FRAMECHANGED; + PInvoke.SetWindowPos(CurrentWindowPtr, 0, 0, 0, 0, 0, flags); + } - var desktopSiteBridgeHwnd = InvokeProp.FindWindowEx(CurrentWindowPtr, 0, "Microsoft.UI.Content.DesktopChildSiteBridge", ""); - OldDesktopSiteBridgeWndProcPtr = InstallWndProcCallback(desktopSiteBridgeHwnd, DesktopSiteBridgeWndProc); + var desktopSiteBridgeHwnd = PInvoke.FindWindowEx(CurrentWindowPtr, 0, "Microsoft.UI.Content.DesktopChildSiteBridge", ""); + OldDesktopSiteBridgeWndProcPtr = InstallWndProcCallback(desktopSiteBridgeHwnd, DesktopSiteBridgeWndProc); } - private static IntPtr DesktopSiteBridgeWndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lParam) - { - const uint WM_WINDOWPOSCHANGING = 0x0046; + private static IntPtr DesktopSiteBridgeWndProc(IntPtr hwnd, uint msg, UIntPtr wParam, IntPtr lParam) + { + const uint WM_WINDOWPOSCHANGING = 0x0046; - switch (msg) - { - case WM_WINDOWPOSCHANGING: + switch (msg) + { + case WM_WINDOWPOSCHANGING: { // Fix the weird 1px offset - var windowPos = Marshal.PtrToStructure(lParam); + var windowPos = Marshal.PtrToStructure(lParam); if (windowPos.x == 0 && windowPos.y == 1 && windowPos.cx == (int)(WindowSize.WindowSize.CurrentWindowSize.WindowBounds.Width * CurrentWindowMonitorScaleFactor) && windowPos.cy == (int)(WindowSize.WindowSize.CurrentWindowSize.WindowBounds.Height * CurrentWindowMonitorScaleFactor) - 1) { - windowPos.y = 0; + windowPos.y = 0; windowPos.cy += 1; Marshal.StructureToPtr(windowPos, lParam, false); } break; } - } - - return InvokeProp.CallWindowProc(OldDesktopSiteBridgeWndProcPtr, hwnd, msg, wParam, lParam); } - internal static void SetWindowSize(int width, int height) - { - if (CurrentWindowPtr == nint.Zero) - { - return; - } + return PInvoke.CallWindowProc(OldDesktopSiteBridgeWndProcPtr, hwnd, msg, wParam, lParam); + } - // Get the scale factor and calculate the size and offset - double scaleFactor = CurrentWindowMonitorScaleFactor; - int lastWindowWidth = (int)(width * scaleFactor); - int lastWindowHeight = (int)(height * scaleFactor); + internal static void SetWindowSize(int width, int height) + { + if (CurrentScreenProp == null || CurrentWindowPtr == nint.Zero) + return; - Size desktopSize = ScreenProp.GetScreenSize(); - int xOff = desktopSize.Width / 2 - lastWindowWidth / 2; - int yOff = desktopSize.Height / 2 - lastWindowHeight / 2; + // Get the scale factor and calculate the size and offset + double scaleFactor = CurrentWindowMonitorScaleFactor; + int lastWindowWidth = (int)(width * scaleFactor); + int lastWindowHeight = (int)(height * scaleFactor); - // Use CurrentWindowPosition to change the size and position - CurrentWindowPosition = new Rect - { Height = lastWindowHeight, Width = lastWindowWidth, X = xOff, Y = yOff }; - } + Size desktopSize = CurrentScreenProp.GetScreenSize(); + int xOff = desktopSize.Width / 2 - lastWindowWidth / 2; + int yOff = desktopSize.Height / 2 - lastWindowHeight / 2; - internal static void WindowMinimize() - { - if (CurrentWindowPtr == nint.Zero) - { - return; - } + // Use CurrentWindowPosition to change the size and position + CurrentWindowPosition = new Rect + { Height = lastWindowHeight, Width = lastWindowWidth, X = xOff, Y = yOff }; + } - const uint WM_SYSCOMMAND = 0x0112; - const uint SC_MINIMIZE = 0xF020; - InvokeProp.SendMessage(CurrentWindowPtr, WM_SYSCOMMAND, SC_MINIMIZE, 0); + internal static void WindowMinimize() + { + if (CurrentWindowPtr == nint.Zero) + { + return; } - internal static void WindowRestore() - { - if (CurrentWindowPtr == nint.Zero) - { - return; - } + const uint WM_SYSCOMMAND = 0x0112; + const uint SC_MINIMIZE = 0xF020; + PInvoke.SendMessage(CurrentWindowPtr, WM_SYSCOMMAND, SC_MINIMIZE, 0); + } - const uint WM_SYSCOMMAND = 0x0112; - const uint SC_RESTORE = 0xF120; - InvokeProp.SendMessage(CurrentWindowPtr, WM_SYSCOMMAND, SC_RESTORE, 0); + internal static void WindowRestore() + { + if (CurrentWindowPtr == nint.Zero) + { + return; } - internal static void EnableWindowNonClientArea() + const uint WM_SYSCOMMAND = 0x0112; + const uint SC_RESTORE = 0xF120; + PInvoke.SendMessage(CurrentWindowPtr, WM_SYSCOMMAND, SC_RESTORE, 0); + } + + internal static void EnableWindowNonClientArea() + { + if (!CurrentWindowId.HasValue || CurrentAppWindow == null) { - if (!CurrentWindowId.HasValue || CurrentAppWindow == null) - { - return; - } + return; + } - double scaleFactor = CurrentWindowMonitorScaleFactor; - var incps = InputNonClientPointerSource.GetForWindowId(CurrentWindowId.Value); - var safeArea = new RectInt32[] - { + double scaleFactor = CurrentWindowMonitorScaleFactor; + var incps = InputNonClientPointerSource.GetForWindowId(CurrentWindowId.Value); + var safeArea = new RectInt32[] + { new(CurrentAppWindow.Size.Width - (int)((144 + 12) * scaleFactor), 0, (int)((144 + 12) * scaleFactor), (int)(48 * scaleFactor)) - }; - incps.SetRegionRects(NonClientRegionKind.Passthrough, safeArea); - } + }; + incps.SetRegionRects(NonClientRegionKind.Passthrough, safeArea); + } - internal static void DisableWindowNonClientArea() + internal static void DisableWindowNonClientArea() + { + if (!CurrentWindowId.HasValue || CurrentAppWindow == null) { - if (!CurrentWindowId.HasValue || CurrentAppWindow == null) - { - return; - } - - double scaleFactor = CurrentWindowMonitorScaleFactor; - var incps = InputNonClientPointerSource.GetForWindowId(CurrentWindowId.Value); - var safeArea = new RectInt32[] { new(0, 0, CurrentAppWindow.Size.Width, (int)(48 * scaleFactor)) }; - incps.SetRegionRects(NonClientRegionKind.Passthrough, safeArea); + return; } - internal static bool IsCurrentWindowInFocus() - { - IntPtr currentForegroundWindow = InvokeProp.GetForegroundWindow(); - return CurrentWindowPtr == currentForegroundWindow; - } + double scaleFactor = CurrentWindowMonitorScaleFactor; + var incps = InputNonClientPointerSource.GetForWindowId(CurrentWindowId.Value); + var safeArea = new RectInt32[] { new(0, 0, CurrentAppWindow.Size.Width, (int)(48 * scaleFactor)) }; + incps.SetRegionRects(NonClientRegionKind.Passthrough, safeArea); + } - #endregion + internal static bool IsCurrentWindowInFocus() + { + IntPtr currentForegroundWindow = PInvoke.GetForegroundWindow(); + return CurrentWindowPtr == currentForegroundWindow; + } - #region Tray Icon Invoker - /// - /// - /// - public static void ToggleToTray_MainWindow() - { - if (CurrentWindow is not MainWindow window) return; + #endregion - if (window._TrayIcon != null) window._TrayIcon.ToggleMainVisibility(); - else TrayNullHandler(nameof(Tray_ShowNotification)); - } + #region Tray Icon Invoker + /// + /// + /// + public static void ToggleToTray_MainWindow() + { + if (CurrentWindow is not MainWindow window) return; - /// - /// - /// - public static void ToggleToTray_AllWindow() - { - if (CurrentWindow is not MainWindow window) return; + if (window._TrayIcon != null) window._TrayIcon.ToggleMainVisibility(); + else TrayNullHandler(nameof(Tray_ShowNotification)); + } - if (window._TrayIcon != null) window._TrayIcon.ToggleAllVisibility(); - else TrayNullHandler(nameof(Tray_ShowNotification)); - } + /// + /// + /// + public static void ToggleToTray_AllWindow() + { + if (CurrentWindow is not MainWindow window) return; + + if (window._TrayIcon != null) window._TrayIcon.ToggleAllVisibility(); + else TrayNullHandler(nameof(Tray_ShowNotification)); + } - /// - /// - /// + /// + /// + /// /// The title to display on the balloon tip. /// The text to display on the balloon tip. /// A symbol that indicates the severity. @@ -745,28 +747,28 @@ public static void ToggleToTray_AllWindow() /// // Taken from H.NotifyIcon.TrayIcon.ShowNotification docs // https://github.com/HavenDV/H.NotifyIcon/blob/89356c52bedae45b1fd451531e8ac8cfe8b13086/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Notifications.cs#L14 - public static void Tray_ShowNotification(string title, - string message, - NotificationIcon icon = NotificationIcon.None, - IntPtr? customIconHandle = null, - bool largeIcon = false, - bool sound = true, - bool respectQuietTime = true, - bool realtime = false) - { - if (CurrentWindow is not MainWindow window) return; - - if (window._TrayIcon != null) - window._TrayIcon.ShowNotification(title, message, icon, customIconHandle, largeIcon, sound, - respectQuietTime, realtime); - else TrayNullHandler(nameof(Tray_ShowNotification)); - } + public static void Tray_ShowNotification(string title, + string message, + NotificationIcon icon = NotificationIcon.None, + IntPtr? customIconHandle = null, + bool largeIcon = false, + bool sound = true, + bool respectQuietTime = true, + bool realtime = false) + { + if (CurrentWindow is not MainWindow window) return; - private static void TrayNullHandler(string caller) - { - Logger.LogWriteLine($"TrayIcon is null/not initialized!\r\n\tCalled by: {caller}"); - } + if (window._TrayIcon != null) + window._TrayIcon.ShowNotification(title, message, icon, customIconHandle, largeIcon, sound, + respectQuietTime, realtime); + else TrayNullHandler(nameof(Tray_ShowNotification)); + } - #endregion + private static void TrayNullHandler(string caller) + { + Logger.LogWriteLine($"TrayIcon is null/not initialized!\r\n\tCalled by: {caller}"); } + + #endregion } +} diff --git a/CollapseLauncher/Classes/InstallManagement/BaseClass/InstallManagerBase.cs b/CollapseLauncher/Classes/InstallManagement/BaseClass/InstallManagerBase.cs index f5374517a..f42b547c7 100644 --- a/CollapseLauncher/Classes/InstallManagement/BaseClass/InstallManagerBase.cs +++ b/CollapseLauncher/Classes/InstallManagement/BaseClass/InstallManagerBase.cs @@ -15,7 +15,9 @@ using CollapseLauncher.CustomControls; using CollapseLauncher.Dialogs; +using CollapseLauncher.DiscordPresence; using CollapseLauncher.Extension; +using CollapseLauncher.FileDialogCOM; using CollapseLauncher.Helper; using CollapseLauncher.Helper.Metadata; using CollapseLauncher.Interfaces; @@ -25,6 +27,7 @@ using Hi3Helper.EncTool.Parser.AssetIndex; using Hi3Helper.Http; using Hi3Helper.Http.Legacy; +using Hi3Helper.SentryHelper; using Hi3Helper.Shared.ClassStruct; using Hi3Helper.Shared.Region; using Hi3Helper.Sophon; @@ -61,9 +64,6 @@ using SophonLogger = Hi3Helper.Sophon.Helper.Logger; using SophonManifest = Hi3Helper.Sophon.SophonManifest; -using CollapseLauncher.Classes.FileDialogCOM; -using CollapseLauncher.DiscordPresence; -using Hi3Helper.SentryHelper; // ReSharper disable ForCanBeConvertedToForeach // ReSharper disable SwitchStatementHandlesSomeKnownEnumValuesWithDefault @@ -1565,7 +1565,7 @@ protected virtual async Task StartPackageInstallationInner(List entriesIndex, L } // Assign local sizes to progress - _progress.ProgressPerFileSizeCurrent = _progressPerFileSizeCurrent; + _progress!.ProgressPerFileSizeCurrent = _progressPerFileSizeCurrent; _progress.ProgressPerFileSizeTotal = _progressPerFileSizeTotal; _progress.ProgressAllSizeCurrent = _progressAllSizeCurrent; _progress.ProgressAllSizeTotal = _progressAllSizeTotal; @@ -2254,9 +2254,9 @@ public virtual async ValueTask ApplyHdiffListPatch() { List hdiffEntry = TryGetHDiffList(); - _progress.ProgressAllSizeTotal = hdiffEntry.Sum(x => x.fileSize); + _progress!.ProgressAllSizeTotal = hdiffEntry.Sum(x => x.fileSize); _progress.ProgressAllSizeCurrent = 0; - _status.IsIncludePerFileIndicator = false; + _status!.IsIncludePerFileIndicator = false; RestartStopwatch(); _progressAllCountTotal = 1; @@ -2363,7 +2363,7 @@ public virtual async ValueTask ApplyHdiffListPatch() private async void EventListener_PatchEvent(object sender, PatchEvent e) { - lock (_progress) + lock (_progress!) { _progress.ProgressAllSizeCurrent += e.Read; } @@ -2777,7 +2777,7 @@ private async ValueTask CheckExistingSteamInstallation() if (migrationOptionReturn == 0) { _gameVersionManager.UpdateGamePath(pathOnSteam, false); - await StartSteamMigration(pathOnSteam); + await StartSteamMigration(); _gameVersionManager.UpdateGameVersionToLatest(false); return 0; } @@ -2791,7 +2791,7 @@ private async ValueTask CheckExistingSteamInstallation() } #nullable enable - private async Task StartSteamMigration(string gamePath) + private async Task StartSteamMigration() { // Get game repair instance and if it's null, then return; string? latestGameVersionString = _gameVersionManager.GetGameVersionAPI()?.VersionString; @@ -2842,7 +2842,7 @@ private async Task StartSteamMigration(string gamePath) TextBlock percentageStatus = mainGrid.AddElementToGridRowColumn( new TextBlock() { FontWeight = FontWeights.Bold, Text = "0.00%" } .WithHorizontalAlignment(HorizontalAlignment.Right), - 3, 1, 0, 0); + 3, 1); ProgressBar progressBar = mainGrid.AddElementToGridRowColumn( new ProgressBar { IsIndeterminate = true }, 4, 0, 0, 2) @@ -2871,7 +2871,7 @@ private async Task StartSteamMigration(string gamePath) #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed await gameRepairInstance.StartCheckRoutine(); statusActivity.Text = Lang._InstallMigrateSteam.Step4Title; - await gameRepairInstance.StartRepairRoutine(false); + await gameRepairInstance.StartRepairRoutine(); contentDialog.Hide(); } catch (Exception ex) @@ -3126,13 +3126,11 @@ private bool TryGetExistingBHI3LPath(ref string OutputPath) FileInfo execPath = new FileInfo(Path.Combine(config.game_info.install_path, _gameVersionManager.GamePreset.GameExecutableName!)); OutputPath = config.game_info.install_path; + // If all of those not passed, then return false return execPath is { Exists: true, Length: > 1 >> 16 }; - // If all of those not passed, then return false - #nullable disable } -#nullable enable private async Task AskGameFolderDialog(Func? checkExistingGameDelegate = null) { // Set initial folder variable as empty @@ -3610,7 +3608,7 @@ private async ValueTask RunPackageDownloadRoutine(Http httpClie int packageCount) { // Set the activity status - _status.IsIncludePerFileIndicator = packageCount > 1; + _status!.IsIncludePerFileIndicator = packageCount > 1; _status.ActivityStatus = $"{Lang._Misc.Downloading}: {string.Format(Lang._Misc.PerFromTo, _progressAllCountCurrent, _progressAllCountTotal)}"; @@ -3872,7 +3870,7 @@ private async Task GetPackagesRemoteSize(List packageList, C await Parallel.ForEachAsync(packageList, new ParallelOptions { CancellationToken = token - }, async (package, innerToken) => + }, async (package, _) => { if (package.Segments != null) { @@ -3894,7 +3892,7 @@ public void UpdateCompletenessStatus(CompletenessStatus status) { case CompletenessStatus.Running: IsRunning = true; - _status.IsRunning = true; + _status!.IsRunning = true; _status.IsCompleted = false; _status.IsCanceled = false; #if !DISABLEDISCORD @@ -3903,19 +3901,19 @@ public void UpdateCompletenessStatus(CompletenessStatus status) break; case CompletenessStatus.Completed: IsRunning = false; - _status.IsRunning = false; + _status!.IsRunning = false; _status.IsCompleted = true; _status.IsCanceled = false; #if !DISABLEDISCORD InnerLauncherConfig.AppDiscordPresence?.SetActivity(ActivityType.Idle); #endif // HACK: Fix the progress not achieving 100% while completed - _progress.ProgressAllPercentage = 100f; + _progress!.ProgressAllPercentage = 100f; _progress.ProgressPerFilePercentage = 100f; break; case CompletenessStatus.Cancelled: IsRunning = false; - _status.IsRunning = false; + _status!.IsRunning = false; _status.IsCompleted = false; _status.IsCanceled = true; #if !DISABLEDISCORD @@ -3924,7 +3922,7 @@ public void UpdateCompletenessStatus(CompletenessStatus status) break; case CompletenessStatus.Idle: IsRunning = false; - _status.IsRunning = false; + _status!.IsRunning = false; _status.IsCompleted = false; _status.IsCanceled = false; #if !DISABLEDISCORD @@ -3951,7 +3949,7 @@ protected async Task TryGetSegmentedPackageRemoteSize(GameInstallPackage asset, { CancellationToken = token }, - async (i, innerToken) => + async (i, _) => { long segmentSize = await FallbackCDNUtil.GetContentLength(asset.Segments[i].URL, token); totalSize += segmentSize; @@ -3986,7 +3984,7 @@ protected void UpdateProgressBase() protected async void DeltaPatchCheckProgress(object sender, PatchEvent e) { - _progress.ProgressAllPercentage = e.ProgressPercentage; + _progress!.ProgressAllPercentage = e.ProgressPercentage; _progress.ProgressAllTimeLeft = e.TimeLeft; _progress.ProgressAllSpeed = e.Speed; @@ -3996,7 +3994,7 @@ protected async void DeltaPatchCheckProgress(object sender, PatchEvent e) if (await CheckIfNeedRefreshStopwatch()) { - _status.IsProgressAllIndetermined = false; + _status!.IsProgressAllIndetermined = false; UpdateProgressBase(); UpdateStatus(); } @@ -4030,7 +4028,7 @@ protected void DeltaPatchCheckLogEvent(object sender, LoggerEvent e) protected async void DeltaPatchCheckProgress(object sender, TotalPerfileProgress e) { - _progress.ProgressAllPercentage = + _progress!.ProgressAllPercentage = e.ProgressAllPercentage == 0 ? e.ProgressPerFilePercentage : e.ProgressAllPercentage; _progress.ProgressAllTimeLeft = e.ProgressAllTimeLeft; @@ -4041,7 +4039,7 @@ protected async void DeltaPatchCheckProgress(object sender, TotalPerfileProgress if (await CheckIfNeedRefreshStopwatch()) { - _status.IsProgressAllIndetermined = false; + _status!.IsProgressAllIndetermined = false; UpdateProgressBase(); UpdateStatus(); } @@ -4060,7 +4058,7 @@ private async void ZipProgressAdapter(object sender, ExtractProgressProp e) _progressPerFileSizeTotal = (long)e.TotalSize; // Assign local sizes to progress - _progress.ProgressPerFileSizeCurrent = _progressPerFileSizeCurrent; + _progress!.ProgressPerFileSizeCurrent = _progressPerFileSizeCurrent; _progress.ProgressPerFileSizeTotal = _progressPerFileSizeTotal; _progress.ProgressAllSizeCurrent = _progressAllSizeCurrent; _progress.ProgressAllSizeTotal = _progressAllSizeTotal; @@ -4097,7 +4095,7 @@ private long GetLastSize(long input) private async void HttpClientDownloadProgressAdapter(int read, DownloadProgress downloadProgress) { // Set the progress bar not indetermined - _status.IsProgressPerFileIndetermined = false; + _status!.IsProgressPerFileIndetermined = false; _status.IsProgressAllIndetermined = false; // Increment the total current size if status is not merging @@ -4108,7 +4106,7 @@ private async void HttpClientDownloadProgressAdapter(int read, DownloadProgress if (_refreshStopwatch!.ElapsedMilliseconds > _refreshInterval) { // Assign local sizes to progress - _progress.ProgressPerFileSizeCurrent = _progressPerFileSizeCurrent; + _progress!.ProgressPerFileSizeCurrent = _progressPerFileSizeCurrent; _progress.ProgressPerFileSizeTotal = _progressPerFileSizeTotal; _progress.ProgressAllSizeCurrent = _progressAllSizeCurrent; _progress.ProgressAllSizeTotal = _progressAllSizeTotal; @@ -4154,7 +4152,7 @@ private async void HttpClientDownloadProgressAdapter(int read, DownloadProgress private async void HttpClientDownloadProgressAdapter(object sender, DownloadEvent e) { // Set the progress bar not indetermined - _status.IsProgressPerFileIndetermined = false; + _status!.IsProgressPerFileIndetermined = false; _status.IsProgressAllIndetermined = false; if (e.State != DownloadState.Merging) @@ -4170,7 +4168,7 @@ private async void HttpClientDownloadProgressAdapter(object sender, DownloadEven if (e.State != DownloadState.Merging) { // Assign local sizes to progress - _progress.ProgressPerFileSizeCurrent = _progressPerFileSizeCurrent; + _progress!.ProgressPerFileSizeCurrent = _progressPerFileSizeCurrent; _progress.ProgressPerFileSizeTotal = _progressPerFileSizeTotal; _progress.ProgressAllSizeCurrent = _progressAllSizeCurrent; _progress.ProgressAllSizeTotal = _progressAllSizeTotal; @@ -4197,7 +4195,7 @@ private async void HttpClientDownloadProgressAdapter(object sender, DownloadEven // If status is merging, then use progress for speed and timelapse from Http client // and set the rest from the base class - _progress.ProgressAllTimeLeft = e.TimeLeft; + _progress!.ProgressAllTimeLeft = e.TimeLeft; double speedWithReset = _progressAllIOReadCurrent / _downloadSpeedRefreshStopwatch.Elapsed.TotalSeconds; _progress.ProgressAllSpeed = speedWithReset; diff --git a/CollapseLauncher/Classes/Properties/InnerLauncherConfig.cs b/CollapseLauncher/Classes/Properties/InnerLauncherConfig.cs index c14017ec3..8eeebea23 100644 --- a/CollapseLauncher/Classes/Properties/InnerLauncherConfig.cs +++ b/CollapseLauncher/Classes/Properties/InnerLauncherConfig.cs @@ -4,6 +4,7 @@ using CollapseLauncher.Pages; using Hi3Helper; using Hi3Helper.Shared.ClassStruct; +using Hi3Helper.Win32.Native; using Microsoft.UI.Text; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; @@ -14,8 +15,8 @@ using System.Linq; using Windows.Foundation; using Windows.UI; -using static Hi3Helper.InvokeProp; using static Hi3Helper.Shared.Region.LauncherConfig; +// ReSharper disable ConditionIsAlwaysTrueOrFalse #nullable enable namespace CollapseLauncher @@ -42,21 +43,21 @@ public enum AppMode GenerateVelopackMetadata } - public static AppMode m_appMode; - public static Arguments m_arguments = new(); - public static bool m_isWindows11; - public static IntPtr m_oldWndProc; - public static Delegate? m_newWndProcDelegate; - public static HandlerRoutine? m_consoleCtrlHandler; - public static MainPage? m_mainPage; - public static HomePage? m_homePage; - public static bool m_windowSupportCustomTitle = false; - public static Size m_actualMainFrameSize; - public static string? m_appCurrentFrameName; - public static NotificationPush? NotificationData; - public static bool IsCustomBG = false; - public static bool IsSkippingUpdateCheck = false; - public static AppThemeMode CurrentAppTheme; + public static AppMode m_appMode; + public static Arguments m_arguments = new(); + public static bool m_isWindows11; + public static IntPtr m_oldWndProc; + public static Delegate? m_newWndProcDelegate; + public static ConsoleControlHandler? m_consoleCtrlHandler; + public static MainPage? m_mainPage; + public static HomePage? m_homePage; + public static bool m_windowSupportCustomTitle = false; + public static Size m_actualMainFrameSize; + public static string? m_appCurrentFrameName; + public static NotificationPush? NotificationData; + public static bool IsCustomBG = false; + public static bool IsSkippingUpdateCheck = false; + public static AppThemeMode CurrentAppTheme; #if !DISABLEDISCORD #pragma warning disable CA2211 public static DiscordPresenceManager? AppDiscordPresence; @@ -67,7 +68,7 @@ public enum AppMode { AppThemeMode.Dark => false, AppThemeMode.Light => true, - _ => !ShouldAppsUseDarkMode() + _ => !PInvoke.ShouldAppsUseDarkMode() }; public static string? GetComboBoxGameRegionValue(object obj) @@ -81,7 +82,7 @@ public static int GetIndexOfRegionStringOrDefault(string? category) { int? index = LauncherMetadataHelper.GetPreviousGameRegion(category); - return index == -1 || index == null ? 0 : index ?? 0; + return index == -1 || index == null ? 0 : (int)index; } public static List BuildGameTitleListUI() diff --git a/CollapseLauncher/Classes/RegistryMonitor/RegistryMonitor.cs b/CollapseLauncher/Classes/RegistryMonitor/RegistryMonitor.cs index f7d21c284..888cbf6b1 100644 --- a/CollapseLauncher/Classes/RegistryMonitor/RegistryMonitor.cs +++ b/CollapseLauncher/Classes/RegistryMonitor/RegistryMonitor.cs @@ -10,50 +10,20 @@ */ using Hi3Helper; +using Hi3Helper.SentryHelper; +using Hi3Helper.Win32.Native; +using Hi3Helper.Win32.Native.Enums; using Microsoft.Win32; using System; using System.ComponentModel; using System.IO; -using System.Runtime.InteropServices; using System.Threading; -using Hi3Helper.SentryHelper; using static Hi3Helper.Logger; namespace RegistryUtils { public class RegistryMonitor : IDisposable { - #region P/Invoke - - [DllImport("advapi32.dll", EntryPoint = "RegOpenKeyExW", CharSet = CharSet.Unicode, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern int RegOpenKeyEx(IntPtr hKey, string subKey, uint options, int samDesired, - out IntPtr phkResult); - - [DllImport("advapi32.dll", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern int RegNotifyChangeKeyValue(IntPtr hKey, bool bWatchSubtree, - RegChangeNotifyFilter dwNotifyFilter, IntPtr hEvent, - bool fAsynchronous); - - [DllImport("advapi32.dll", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern int RegCloseKey(IntPtr hKey); - - private const int KEY_QUERY_VALUE = 0x0001; - private const int KEY_NOTIFY = 0x0010; - private const int STANDARD_RIGHTS_READ = 0x00020000; - - private static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(unchecked((int)0x80000000)); - private static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(unchecked((int)0x80000001)); - private static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002)); - private static readonly IntPtr HKEY_USERS = new IntPtr(unchecked((int)0x80000003)); - private static readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(unchecked((int)0x80000004)); - private static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(unchecked((int)0x80000005)); - private static readonly IntPtr HKEY_DYN_DATA = new IntPtr(unchecked((int)0x80000006)); - - #endregion - #region Event handling /// @@ -76,8 +46,7 @@ private static extern int RegNotifyChangeKeyValue(IntPtr hKey, bool bWatchSubtre protected virtual void OnRegChanged() { EventHandler handler = RegChanged; - if (handler != null) - handler(this, null); + handler?.Invoke(this, null!); } /// @@ -110,11 +79,11 @@ protected virtual void OnError(Exception e) #region Private member variables - private IntPtr _registryHive; + private HKEYCLASS _registryHive; private string _registrySubName; private object _threadLock = new object(); private Thread _thread; - private bool _disposed = false; + private bool _disposed; private ManualResetEvent _eventTerminate = new ManualResetEvent(false); private RegChangeNotifyFilter _regFilter = RegChangeNotifyFilter.Key | RegChangeNotifyFilter.Attribute | @@ -173,7 +142,7 @@ public void Dispose() { LogWriteLine($"Error at stopping RegistryWatcher!\r\n{ex}", LogType.Error, true); SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); - new Exception($"Error in RegistryMonitor Dispose routine!\r\n{ex}"); + throw new Exception($"Error in RegistryMonitor Dispose routine!\r\n{ex}"); } _disposed = true; #if DEBUG @@ -206,27 +175,27 @@ private void InitRegistryKey(RegistryHive hive, string name) switch (hive) { case RegistryHive.ClassesRoot: - _registryHive = HKEY_CLASSES_ROOT; + _registryHive = HKEYCLASS.HKEY_CLASSES_ROOT; break; case RegistryHive.CurrentConfig: - _registryHive = HKEY_CURRENT_CONFIG; + _registryHive = HKEYCLASS.HKEY_CURRENT_CONFIG; break; case RegistryHive.CurrentUser: - _registryHive = HKEY_CURRENT_USER; + _registryHive = HKEYCLASS.HKEY_CURRENT_USER; break; case RegistryHive.LocalMachine: - _registryHive = HKEY_LOCAL_MACHINE; + _registryHive = HKEYCLASS.HKEY_LOCAL_MACHINE; break; case RegistryHive.PerformanceData: - _registryHive = HKEY_PERFORMANCE_DATA; + _registryHive = HKEYCLASS.HKEY_PERFORMANCE_DATA; break; case RegistryHive.Users: - _registryHive = HKEY_USERS; + _registryHive = HKEYCLASS.HKEY_USERS; break; default: @@ -243,30 +212,30 @@ private void InitRegistryKey(string name) { case "HKEY_CLASSES_ROOT": case "HKCR": - _registryHive = HKEY_CLASSES_ROOT; + _registryHive = HKEYCLASS.HKEY_CLASSES_ROOT; break; case "HKEY_CURRENT_USER": case "HKCU": - _registryHive = HKEY_CURRENT_USER; + _registryHive = HKEYCLASS.HKEY_CURRENT_USER; break; case "HKEY_LOCAL_MACHINE": case "HKLM": - _registryHive = HKEY_LOCAL_MACHINE; + _registryHive = HKEYCLASS.HKEY_LOCAL_MACHINE; break; case "HKEY_USERS": - _registryHive = HKEY_USERS; + _registryHive = HKEYCLASS.HKEY_USERS; break; case "HKEY_CURRENT_CONFIG": - _registryHive = HKEY_CURRENT_CONFIG; + _registryHive = HKEYCLASS.HKEY_CURRENT_CONFIG; break; default: - _registryHive = IntPtr.Zero; - throw new ArgumentException("The registry hive '" + nameParts[0] + "' is not supported", "value"); + _registryHive = HKEYCLASS.None; + throw new ArgumentException("The registry hive '" + nameParts[0] + "' is not supported", nameof(name)); } _registrySubName = string.Join("\\", nameParts, 1, nameParts.Length - 1); @@ -296,7 +265,7 @@ public void Start() if (!IsMonitoring) { _eventTerminate.Reset(); - _thread = new Thread(new ThreadStart(MonitorThread)); + _thread = new Thread(MonitorThread); _thread.IsBackground = true; _thread.Start(); } @@ -337,7 +306,8 @@ private void MonitorThread() private void ThreadLoop() { IntPtr registryKey; - int result = RegOpenKeyEx(_registryHive, _registrySubName, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_NOTIFY, + int result = PInvoke.RegOpenKeyEx(_registryHive, _registrySubName, 0, + (uint)ACCESS_MASK.STANDARD_RIGHTS_READ | (uint)RegKeyAccess.KEY_QUERY_VALUE | (uint)RegKeyAccess.KEY_NOTIFY, out registryKey); if (result != 0) throw new Win32Exception(result); @@ -351,7 +321,7 @@ private void ThreadLoop() { if (_disposed) break; #pragma warning disable CS0618 // Type or member is obsolete - result = RegNotifyChangeKeyValue(registryKey, true, _regFilter, _eventNotify.Handle, true); + result = PInvoke.RegNotifyChangeKeyValue(registryKey, true, _regFilter, _eventNotify.Handle, true); #pragma warning restore CS0618 // Type or member is obsolete if (result != 0) throw new Win32Exception(result); @@ -368,35 +338,15 @@ private void ThreadLoop() } } } - catch { throw; } finally { if (registryKey != IntPtr.Zero) { - RegCloseKey(registryKey); + PInvoke.RegCloseKey(registryKey); } - for (int i = 0; i < waitHandles?.Length; i++) waitHandles?[i]?.Dispose(); + for (int i = 0; i < waitHandles?.Length; i++) waitHandles[i]?.Dispose(); } } } - - /// - /// Filter for notifications reported by . - /// - [Flags] - public enum RegChangeNotifyFilter - { - /// Notify the caller if a subkey is added or deleted. - Key = 1, - /// Notify the caller of changes to the attributes of the key, - /// such as the security descriptor information. - Attribute = 2, - /// Notify the caller of changes to a value of the key. This can - /// include adding or deleting a value, or changing an existing value. - Value = 4, - /// Notify the caller of changes to the security descriptor - /// of the key. - Security = 8, - } } diff --git a/CollapseLauncher/Classes/RepairManagement/StarRail/Check.cs b/CollapseLauncher/Classes/RepairManagement/StarRail/Check.cs index f9bc2062c..b46fc2161 100644 --- a/CollapseLauncher/Classes/RepairManagement/StarRail/Check.cs +++ b/CollapseLauncher/Classes/RepairManagement/StarRail/Check.cs @@ -2,6 +2,7 @@ using Hi3Helper.Data; using Hi3Helper.SentryHelper; using Hi3Helper.Shared.ClassStruct; +using Hi3Helper.Win32.Native; using System; using System.Collections.Generic; using System.IO; @@ -33,8 +34,8 @@ internal static string ReplaceStreamingToPersistentPath(string inputPath, string _ => string.Empty }, execName); - int indexOfStart = inputPath.IndexOf(parentStreamingRelativePath); - int indexOfEnd = indexOfStart + parentStreamingRelativePath.Length; + int indexOfStart = inputPath.IndexOf(parentStreamingRelativePath, StringComparison.Ordinal); + int indexOfEnd = indexOfStart + parentStreamingRelativePath.Length; if (indexOfStart == -1) return inputPath; @@ -69,11 +70,14 @@ private async Task Check(List assetIndex, CancellationToke List brokenAssetIndex = new List(); // Set Indetermined status as false - _status.IsProgressAllIndetermined = false; - _status.IsProgressPerFileIndetermined = false; + if (_status != null) + { + _status.IsProgressAllIndetermined = false; + _status.IsProgressPerFileIndetermined = false; - // Show the asset entry panel - _status.IsAssetEntryPanelShow = true; + // Show the asset entry panel + _status.IsAssetEntryPanelShow = true; + } // Await the task for parallel processing try @@ -118,7 +122,11 @@ private async Task Check(List assetIndex, CancellationToke private async ValueTask CheckGenericAssetType(FilePropertiesRemote asset, List targetAssetIndex, CancellationToken token) { // Update activity status - _status.ActivityStatus = string.Format(Lang._GameRepairPage.Status6, StarRailRepairExtension.GetFileRelativePath(asset.N, _gamePath)); + if (_status != null) + { + _status.ActivityStatus = string.Format(Lang._GameRepairPage.Status6, + StarRailRepairExtension.GetFileRelativePath(asset.N, _gamePath)); + } // Increment current total count _progressAllCountCurrent++; @@ -200,7 +208,11 @@ private async ValueTask CheckGenericAssetType(FilePropertiesRemote asset, List targetAssetIndex, CancellationToken token) { // Update activity status - _status.ActivityStatus = string.Format(Lang._GameRepairPage.Status6, StarRailRepairExtension.GetFileRelativePath(asset.N, _gamePath)); + if (_status != null) + { + _status.ActivityStatus = string.Format(Lang._GameRepairPage.Status6, + StarRailRepairExtension.GetFileRelativePath(asset.N, _gamePath)); + } // Increment current total count _progressAllCountCurrent++; @@ -312,7 +324,7 @@ private async ValueTask CheckAssetType(FilePropertiesRemote asset, List - /// Flags determining how the links with missing - /// targets are resolved. - /// - [Flags] - public enum EShellLinkResolveFlags : uint - { - /// - /// Allow any match during resolution. Has no effect - /// on ME/2000 or above, use the other flags instead. - /// - SLR_ANY_MATCH = 0x2, - - /// - /// Call the Microsoft Windows Installer. - /// - SLR_INVOKE_MSI = 0x80, - - /// - /// Disable distributed link tracking. By default, - /// distributed link tracking tracks removable media - /// across multiple devices based on the volume name. - /// It also uses the UNC path to track remote file - /// systems whose drive letter has changed. Setting - /// SLR_NOLINKINFO disables both types of tracking. - /// - SLR_NOLINKINFO = 0x40, - - /// - /// Do not display a dialog box if the link cannot be resolved. - /// When SLR_NO_UI is set, a time-out value that specifies the - /// maximum amount of time to be spent resolving the link can - /// be specified in milliseconds. The function returns if the - /// link cannot be resolved within the time-out duration. - /// If the timeout is not set, the time-out duration will be - /// set to the default value of 3,000 milliseconds (3 seconds). - /// - SLR_NO_UI = 0x1, - - /// - /// Not documented in SDK. Assume same as SLR_NO_UI but - /// intended for applications without a hWnd. - /// - SLR_NO_UI_WITH_MSG_PUMP = 0x101, - - /// - /// Do not update the link information. - /// - SLR_NOUPDATE = 0x8, - - /// - /// Do not execute the search heuristics. - /// - SLR_NOSEARCH = 0x10, - - /// - /// Do not use distributed link tracking. - /// - SLR_NOTRACK = 0x20, - - /// - /// If the link object has changed, update its path and list - /// of identifiers. If SLR_UPDATE is set, you do not need to - /// call IPersistFile::IsDirty to determine whether or not - /// the link object has changed. - /// - SLR_UPDATE = 0x4 - } -} diff --git a/CollapseLauncher/Classes/ShellLinkCOM/Filetime.cs b/CollapseLauncher/Classes/ShellLinkCOM/Filetime.cs deleted file mode 100644 index 8d3a28d58..000000000 --- a/CollapseLauncher/Classes/ShellLinkCOM/Filetime.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Runtime.InteropServices; - -namespace CollapseLauncher.ShellLinkCOM -{ - [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0)] - public partial struct Filetime - { - public uint dwLowDateTime; - public uint dwHighDateTime; - } -} diff --git a/CollapseLauncher/Classes/ShellLinkCOM/IPersist.cs b/CollapseLauncher/Classes/ShellLinkCOM/IPersist.cs deleted file mode 100644 index f101830ce..000000000 --- a/CollapseLauncher/Classes/ShellLinkCOM/IPersist.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -namespace CollapseLauncher.ShellLinkCOM -{ - [Guid(CLSIDGuid.Id_IPersistIGuid)] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [GeneratedComInterface] - internal partial interface IPersist - { - [PreserveSig] - //[helpstring("Returns the class identifier for the component object")] - void GetClassID(out Guid pClassID); - } -} diff --git a/CollapseLauncher/Classes/ShellLinkCOM/IPersistFile.cs b/CollapseLauncher/Classes/ShellLinkCOM/IPersistFile.cs deleted file mode 100644 index fba52e832..000000000 --- a/CollapseLauncher/Classes/ShellLinkCOM/IPersistFile.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -namespace CollapseLauncher.ShellLinkCOM -{ - [Guid(CLSIDGuid.Id_IPersistFileIGuid)] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16)] - internal partial interface IPersistFile - { - // can't get this to go if I extend IPersist, so put it here: - [PreserveSig] - void GetClassID(out Guid pClassID); - - //[helpstring("Checks for changes since last file write")] - void IsDirty(); - - //[helpstring("Opens the specified file and initializes the object from its contents")] - void Load( - [MarshalAs(UnmanagedType.LPWStr)] string pszFileName, - uint dwMode); - - //[helpstring("Saves the object into the specified file")] - void Save( - [MarshalAs(UnmanagedType.LPWStr)] string pszFileName, - [MarshalAs(UnmanagedType.Bool)] bool fRemember); - - //[helpstring("Notifies the object that save is completed")] - void SaveCompleted( - [MarshalAs(UnmanagedType.LPWStr)] string pszFileName); - - //[helpstring("Gets the current name of the file associated with the object")] - void GetCurFile( - [MarshalAs(UnmanagedType.LPWStr)] out string ppszFileName); - } -} diff --git a/CollapseLauncher/Classes/ShellLinkCOM/IPropertyStore.cs b/CollapseLauncher/Classes/ShellLinkCOM/IPropertyStore.cs deleted file mode 100644 index b51f6304c..000000000 --- a/CollapseLauncher/Classes/ShellLinkCOM/IPropertyStore.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -namespace CollapseLauncher.ShellLinkCOM -{ - [Guid(CLSIDGuid.Id_IPropertyStoreIGuid)] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [GeneratedComInterface] - internal partial interface IPropertyStore - { - [PreserveSig] - int GetCount(out uint cProps); - [PreserveSig] - int GetAt(in uint iProp, out PropertyKey pkey); - [PreserveSig] - int GetValue(ref PropertyKey key, out PropVariant pv); - [PreserveSig] - int SetValue(ref PropertyKey key, ref PropVariant pv); - [PreserveSig] - int Commit(); - } -} diff --git a/CollapseLauncher/Classes/ShellLinkCOM/IShellLinkW.cs b/CollapseLauncher/Classes/ShellLinkCOM/IShellLinkW.cs deleted file mode 100644 index 9d5a37586..000000000 --- a/CollapseLauncher/Classes/ShellLinkCOM/IShellLinkW.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; - -namespace CollapseLauncher.ShellLinkCOM -{ - [Guid(CLSIDGuid.Id_ShellLinkIGuid)] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16)] - internal partial interface IShellLinkW - { - //[helpstring("Retrieves the path and filename of a shell link object")] - unsafe void GetPath( - char* pszFile, - int cchMaxPath, - nint pfd, - uint fFlags); - - //[helpstring("Retrieves the list of shell link item identifiers")] - void GetIDList(out IntPtr ppidl); - - //[helpstring("Sets the list of shell link item identifiers")] - void SetIDList(IntPtr pidl); - - //[helpstring("Retrieves the shell link description string")] - unsafe void GetDescription( - char* pszFile, - int cchMaxName); - - //[helpstring("Sets the shell link description string")] - void SetDescription( - [MarshalAs(UnmanagedType.LPWStr)] string pszName); - - //[helpstring("Retrieves the name of the shell link working directory")] - unsafe void GetWorkingDirectory( - char* pszDir, - int cchMaxPath); - - //[helpstring("Sets the name of the shell link working directory")] - void SetWorkingDirectory( - [MarshalAs(UnmanagedType.LPWStr)] string pszDir); - - //[helpstring("Retrieves the shell link command-line arguments")] - unsafe void GetArguments( - char* pszArgs, - int cchMaxPath); - - //[helpstring("Sets the shell link command-line arguments")] - void SetArguments( - [MarshalAs(UnmanagedType.LPWStr)] string pszArgs); - - //[propget, helpstring("Retrieves or sets the shell link hot key")] - void GetHotkey(out short pwHotkey); - //[propput, helpstring("Retrieves or sets the shell link hot key")] - void SetHotkey(short pwHotkey); - - //[propget, helpstring("Retrieves or sets the shell link show command")] - void GetShowCmd(out uint piShowCmd); - //[propput, helpstring("Retrieves or sets the shell link show command")] - void SetShowCmd(uint piShowCmd); - - //[helpstring("Retrieves the location (path and index) of the shell link icon")] - unsafe void GetIconLocation( - char* pszIconPath, - int cchIconPath, - out int piIcon); - - //[helpstring("Sets the location (path and index) of the shell link icon")] - void SetIconLocation( - [MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, - int iIcon); - - //[helpstring("Sets the shell link relative path")] - void SetRelativePath( - [MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, - uint dwReserved); - - //[helpstring("Resolves a shell link. The system searches for the shell link object and updates the shell link path and its list of identifiers (if necessary)")] - void Resolve( - IntPtr hWnd, - uint fFlags); - - //[helpstring("Sets the shell link path and filename")] - void SetPath( - [MarshalAs(UnmanagedType.LPWStr)] string pszFile); - } -} diff --git a/CollapseLauncher/Classes/ShellLinkCOM/PropVariant.cs b/CollapseLauncher/Classes/ShellLinkCOM/PropVariant.cs deleted file mode 100644 index 5f70b3e1e..000000000 --- a/CollapseLauncher/Classes/ShellLinkCOM/PropVariant.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace CollapseLauncher.ShellLinkCOM -{ - [StructLayout(LayoutKind.Sequential)] - internal struct PropVariant - { - public short variantType; - public short Reserved1, Reserved2, Reserved3; - public IntPtr pointerValue; - - public static PropVariant FromString(string str) - { - var pv = new PropVariant() - { - variantType = 31, // VT_LPWSTR - pointerValue = Marshal.StringToCoTaskMemUni(str), - }; - - return pv; - } - - public static PropVariant FromGuid(Guid guid) - { - byte[] bytes = guid.ToByteArray(); - var pv = new PropVariant() - { - variantType = 72, // VT_CLSID - pointerValue = Marshal.AllocCoTaskMem(bytes.Length), - }; - Marshal.Copy(bytes, 0, pv.pointerValue, bytes.Length); - - return pv; - } - - /// - /// Called to properly clean up the memory referenced by a PropVariant instance. - /// - [DllImport("ole32.dll")] - private extern static int PropVariantClear(ref PropVariant pvar); - - /// - /// Called to clear the PropVariant's referenced and local memory. - /// - /// - /// You must call Clear to avoid memory leaks. - /// - public void Clear() - { - PropVariantClear(ref this); - } - } -} diff --git a/CollapseLauncher/Classes/ShellLinkCOM/PropertyKey.cs b/CollapseLauncher/Classes/ShellLinkCOM/PropertyKey.cs deleted file mode 100644 index 40ce516b8..000000000 --- a/CollapseLauncher/Classes/ShellLinkCOM/PropertyKey.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace CollapseLauncher.ShellLinkCOM -{ - [StructLayout(LayoutKind.Sequential)] - public struct PropertyKey - { - public Guid fmtid; - public UIntPtr pid; - - public static PropertyKey PKEY_AppUserModel_ID - { - get - { - return new PropertyKey() - { - fmtid = Guid.ParseExact("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", "B"), - pid = new UIntPtr(5), - }; - } - } - - public static PropertyKey PKEY_AppUserModel_ToastActivatorCLSID - { - get - { - return new PropertyKey() - { - fmtid = Guid.ParseExact("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", "B"), - pid = new UIntPtr(26), - }; - } - } - } -} diff --git a/CollapseLauncher/Classes/ShellLinkCOM/ShellLink.cs b/CollapseLauncher/Classes/ShellLinkCOM/ShellLink.cs deleted file mode 100644 index 605bb8282..000000000 --- a/CollapseLauncher/Classes/ShellLinkCOM/ShellLink.cs +++ /dev/null @@ -1,566 +0,0 @@ -using Hi3Helper; -using System; -using System.Buffers; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; - -#nullable enable -#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type -namespace CollapseLauncher.ShellLinkCOM -{ - unsafe delegate void ToDelegateInvoke(char* buffer, int length); - unsafe delegate void ToDelegateWithW32FindDataInvoke(char* buffer, nint findDataPtr, int length); - - public class ShellLink : IDisposable - { - // Use Unicode (W) under NT, otherwise use ANSI - IShellLinkW? linkW; - IPersistFile? persistFileW; - IPersist? persistW; - IPropertyStore? propertyStoreW; - string shortcutFile = ""; - - /// - /// Creates an instance of the Shell Link object. - /// - public ShellLink() - { - PInvoke.CoCreateInstance( - CLSIDGuid.ClsId_ShellLink, - IntPtr.Zero, - CLSCTX.CLSCTX_INPROC_SERVER, - out IShellLinkW? shellLink - ).ThrowOnFailure(); - - linkW = shellLink; - persistFileW = shellLink?.CastComInterfaceAs(in CLSIDGuid.IGuid_IPersistFile); - persistW = shellLink?.CastComInterfaceAs(in CLSIDGuid.IGuid_IPersist); - propertyStoreW = shellLink?.CastComInterfaceAs(in CLSIDGuid.IGuid_IPropertyStore); - } - - /// - /// Creates an instance of a Shell Link object - /// from the specified link file - /// - /// The Shortcut file to open - public ShellLink(string linkFile) : this() => Open(linkFile); - - /// - /// Call dispose just in case it hasn't happened yet - /// - ~ShellLink() => Dispose(); - - /// - /// Dispose the object, releasing the COM ShellLink object - /// - public void Dispose() => PInvoke.Free(linkW); - - public string ShortCutFile - { - get => shortcutFile; - set => shortcutFile = value; - } - - /// - /// This pointer must be destroyed with DistroyIcon when you are done with it. - /// - /// Whether to return the small or large icon - public IntPtr GetIcon(bool large) - { - // Get icon index and path: - string iconFile = IconPath; - int iconIndex = IconIndex; - - // If there are no details set for the icon, then we must use - // the shell to get the icon for the target: - if (iconFile.Length == 0) - { - // Use the FileIcon object to get the icon: - SHGetFileInfoConstants flags = - SHGetFileInfoConstants.SHGFI_ICON | - SHGetFileInfoConstants.SHGFI_ATTRIBUTES; - - flags = flags | (large ? SHGetFileInfoConstants.SHGFI_LARGEICON : SHGetFileInfoConstants.SHGFI_SMALLICON); - - FileIcon fileIcon = new FileIcon(Target, flags); - return fileIcon.ShellIcon; - } - else - { - // Use ExtractIconEx to get the icon: - IntPtr[] hIconEx = new IntPtr[1] { IntPtr.Zero }; - uint iconCount = 0; - if (large) - { - iconCount = InvokeProp.ExtractIconEx( - iconFile, - iconIndex, - hIconEx, - null, - 1); - } - else - { - iconCount = InvokeProp.ExtractIconEx( - iconFile, - iconIndex, - null, - hIconEx, - 1); - } - - return hIconEx[0]; - } - } - - private string? _iconPath; - /// - /// Gets the path to the file containing the icon for this shortcut. - /// - public unsafe string IconPath - { - get => _iconPath ??= GetStringFromIMethod(260, (ptr, len) => linkW?.GetIconLocation(ptr, len, out _)); - set => linkW?.SetIconLocation(_iconPath = value, IconIndex); - } - - private int? _iconIndex; - /// - /// Gets the index of this icon within the icon path's resources - /// - public unsafe int IconIndex - { - get - { - if (_iconIndex == null) - { - int iconIndex = 0; - _ = GetStringFromIMethod(260, (ptr, len) => linkW?.GetIconLocation(ptr, len, out iconIndex)); - _iconIndex = iconIndex; - } - return _iconIndex ?? 0; - } - set => linkW?.SetIconLocation(IconPath, value); - } - - private string? _target; - /// - /// Gets/sets the fully qualified path to the link's target - /// - public unsafe string Target - { - get => _target ??= GetStringAndW32FindDataFromIMethod(260, out _, (ptr, fd, len) => linkW?.GetPath(ptr, len, fd, (uint)EShellLinkGP.SLGP_UNCPRIORITY)); - set => linkW?.SetPath(_target = value); - } - - private string? _workingDirectory; - /// - /// Gets/sets the Working Directory for the Link - /// - public unsafe string WorkingDirectory - { - get => _workingDirectory ??= GetStringFromIMethod(260, (ptr, len) => linkW?.GetWorkingDirectory(ptr, len)); - set => linkW?.SetWorkingDirectory(_workingDirectory = value); - } - - private string? _description; - /// - /// Gets/sets the description of the link - /// - public unsafe string Description - { - get => _description ??= GetStringFromIMethod(1024, (ptr, len) => linkW?.GetDescription(ptr, len)); - set => linkW?.SetDescription(_description = value); - } - - private string? _arguments; - /// - /// Gets/sets any command line arguments associated with the link - /// - public unsafe string Arguments - { - get => _arguments ??= GetStringFromIMethod(260, (ptr, len) => linkW?.GetArguments(ptr, len)); - set => linkW?.SetArguments(_arguments = value); - } - - /// - /// Gets/sets the initial display mode when the shortcut is - /// run - /// - public LinkDisplayMode DisplayMode - { - get - { - uint cmd = 0; - linkW?.GetShowCmd(out cmd); - return (LinkDisplayMode)cmd; - } - set => linkW?.SetShowCmd((uint)value); - } - - /// - /// Gets/sets the HotKey to start the shortcut (if any) - /// - public short HotKey - { - get - { - short key = 0; - linkW?.GetHotkey(out key); - return key; - } - set => linkW?.SetHotkey(value); - } - - private unsafe Win32FindDataW* GetWin32FindDataFromBuffer(byte[] buffer) - { - fixed (void* refPtr = &buffer[0]) - { - return (Win32FindDataW*)refPtr; - } - } - - private unsafe string GetStringAndW32FindDataFromIMethod(int length, out byte[] win32FindDataBuffer, ToDelegateWithW32FindDataInvoke toInvokeDelegate) - { - int sizeOfFindData = Marshal.SizeOf(); - - win32FindDataBuffer = new byte[sizeOfFindData]; - char[] buffer = ArrayPool.Shared.Rent(length); - try - { - fixed (char* bufferPtr = &buffer[0]) - fixed (void* findDataPtr = &win32FindDataBuffer[0]) - { - nint findDataSafe = (nint)findDataPtr; - toInvokeDelegate(bufferPtr, findDataSafe, length); - - return GetStringFromNullTerminatedPtr(bufferPtr); - } - } - finally - { - ArrayPool.Shared.Return(buffer); - } - } - - private unsafe string GetStringFromIMethod(int length, ToDelegateInvoke toInvokeDelegate) - { - char[] buffer = ArrayPool.Shared.Rent(length); - try - { - fixed (char* bufferPtr = &buffer[0]) - { - toInvokeDelegate(bufferPtr, length); - return GetStringFromNullTerminatedPtr(bufferPtr); - } - } - finally - { - ArrayPool.Shared.Return(buffer); - } - } - - private static unsafe string GetStringFromNullTerminatedPtr(char* bufferPtr) - { - ReadOnlySpan returnString = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr); - string outString = returnString.ToString(); - return outString; - } - - private unsafe string GetFileNameFromDataPtr(Win32FindDataW* win32FindData) - { - byte* fdPtr = (byte*)win32FindData; - void* offset = fdPtr + 44; // Fixed pos of cFileName field - char* offsetField = (char*)offset; - - ReadOnlySpan spanNullTerminated = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(offsetField); - return spanNullTerminated.ToString(); - } - - private unsafe string GetAlternativeFileNameFromDataPtr(Win32FindDataW* win32FindData) - { - byte* fdPtr = (byte*)win32FindData; - void* offset = fdPtr + 44 + 520; // Fixed pos of cFileName + sizeof(cFileName) field - char* offsetField = (char*)offset; - - ReadOnlySpan spanNullTerminated = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(offsetField); - return spanNullTerminated.ToString(); - } - - /// - /// Sets the appUserModelId - /// - public void SetAppUserModelId(string appId) - { - var pkey = PropertyKey.PKEY_AppUserModel_ID; - var str = PropVariant.FromString(appId); - propertyStoreW?.SetValue(ref pkey, ref str); - } - - /// - /// Sets the ToastActivatorCLSID - /// - public void SetToastActivatorCLSID(string clsid) - { - var guid = Guid.Parse(clsid); - SetToastActivatorCLSID(guid); - } - - /// - /// Sets the ToastActivatorCLSID - /// - public void SetToastActivatorCLSID(Guid clsid) - { - PropertyKey pkey = PropertyKey.PKEY_AppUserModel_ToastActivatorCLSID; - PropVariant varGuid = PropVariant.FromGuid(clsid); - try - { - int errCode = propertyStoreW?.SetValue(ref pkey, ref varGuid) ?? unchecked((int)0x80004003); - Marshal.ThrowExceptionForHR(errCode); - - errCode = propertyStoreW?.Commit() ?? unchecked((int)0x80004003); - Marshal.ThrowExceptionForHR(errCode); - } - finally - { - varGuid.Clear(); - } - } - - /// - /// Saves the shortcut to ShortCutFile. - /// - public void Save() - { - Save(shortcutFile); - } - - /// - /// Saves the shortcut to the specified file - /// - /// The shortcut file (.lnk) - public void Save(string linkFile) => persistFileW?.Save(linkFile, true); - - /// - /// Loads a shortcut from the specified file - /// - /// The shortcut file (.lnk) to load - public void Open(string linkFile) => Open(linkFile, IntPtr.Zero, EShellLinkResolveFlags.SLR_ANY_MATCH | EShellLinkResolveFlags.SLR_NO_UI, 1); - - /// - /// Loads a shortcut from the specified file, and allows flags controlling - /// the UI behaviour if the shortcut's target isn't found to be set. - /// - /// The shortcut file (.lnk) to load - /// The window handle of the application's UI, if any - /// Flags controlling resolution behaviour - public void Open(string linkFile, IntPtr hWnd, EShellLinkResolveFlags resolveFlags) => Open(linkFile, hWnd, resolveFlags, 1); - - /// - /// Loads a shortcut from the specified file, and allows flags controlling - /// the UI behaviour if the shortcut's target isn't found to be set. If - /// no SLR_NO_UI is specified, you can also specify a timeout. - /// - /// The shortcut file (.lnk) to load - /// The window handle of the application's UI, if any - /// Flags controlling resolution behaviour - /// Timeout if SLR_NO_UI is specified, in ms. - public void Open(string linkFile, IntPtr hWnd, EShellLinkResolveFlags resolveFlags, ushort timeOut) - { - uint flags; - - if ((resolveFlags & EShellLinkResolveFlags.SLR_NO_UI) - == EShellLinkResolveFlags.SLR_NO_UI) - { - flags = (uint)((int)resolveFlags | (timeOut << 16)); - } - else - { - flags = (uint)resolveFlags; - } - - persistFileW?.Load(linkFile, 0); - this.shortcutFile = linkFile; - } - } - - /// - /// Enables extraction of icons for any file type from - /// the Shell. - /// - [ExcludeFromCodeCoverage] - [SupportedOSPlatform("windows")] - public class FileIcon - { - const int MAX_PATH = 260; - - [StructLayout(LayoutKind.Sequential)] - struct SHFILEINFO - { - public IntPtr hIcon; - public int iIcon; - public int dwAttributes; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] - public string szDisplayName; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] - public string szTypeName; - } - - [DllImport("shell32")] - static extern IntPtr SHGetFileInfo( - string pszPath, - int dwFileAttributes, - ref SHFILEINFO psfi, - uint cbFileInfo, - uint uFlags); - - [DllImport("user32.dll")] - static extern int DestroyIcon(IntPtr hIcon); - - const int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x100; - const int FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x2000; - const int FORMAT_MESSAGE_FROM_HMODULE = 0x800; - const int FORMAT_MESSAGE_FROM_STRING = 0x400; - const int FORMAT_MESSAGE_FROM_SYSTEM = 0x1000; - const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x200; - const int FORMAT_MESSAGE_MAX_WIDTH_MASK = 0xFF; - - [DllImport("kernel32")] - static extern int FormatMessage( - int dwFlags, - IntPtr lpSource, - int dwMessageId, - int dwLanguageId, - string lpBuffer, - uint nSize, - IntPtr argumentsLong); - - [DllImport("kernel32")] - static extern int GetLastError(); - - string? fileName; - string? displayName; - string? typeName; - SHGetFileInfoConstants flags; - IntPtr fileIcon; - - /// - /// Gets/sets the flags used to extract the icon - /// - public SHGetFileInfoConstants Flags - { - get => flags; - set => flags = value; - } - - /// - /// Gets/sets the filename to get the icon for - /// - public string? FileName - { - get => fileName; - set => fileName = value; - } - - /// - /// Gets the icon for the chosen file - /// - public IntPtr ShellIcon => fileIcon; - - /// - /// Gets the display name for the selected file - /// if the SHGFI_DISPLAYNAME flag was set. - /// - public string? DisplayName => displayName; - - /// - /// Gets the type name for the selected file - /// if the SHGFI_TYPENAME flag was set. - /// - public string? TypeName => typeName; - - /// - /// Gets the information for the specified - /// file name and flags. - /// - private void GetInfo() - { - fileIcon = IntPtr.Zero; - typeName = ""; - displayName = ""; - - SHFILEINFO shfi = new SHFILEINFO(); - uint shfiSize = (uint)Marshal.SizeOf(); - - IntPtr ret = SHGetFileInfo( - fileName ?? string.Empty, 0, ref shfi, shfiSize, (uint)(flags)); - if (ret != IntPtr.Zero) - { - if (shfi.hIcon != IntPtr.Zero) - { - fileIcon = shfi.hIcon; // need to dispose this - } - typeName = shfi.szTypeName; - displayName = shfi.szDisplayName; - } - else - { - int err = GetLastError(); - Console.WriteLine("Error {0}", err); - string txtS = new string('\0', 256); - int len = FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - IntPtr.Zero, err, 0, txtS, 256, IntPtr.Zero); - Console.WriteLine("Len {0} text {1}", len, txtS); - - // throw exception - } - } - - /// - /// Constructs a new, default instance of the FileIcon - /// class. Specify the filename and call GetInfo() - /// to retrieve an icon. - /// - public FileIcon() - { - flags = SHGetFileInfoConstants.SHGFI_ICON | - SHGetFileInfoConstants.SHGFI_DISPLAYNAME | - SHGetFileInfoConstants.SHGFI_TYPENAME | - SHGetFileInfoConstants.SHGFI_ATTRIBUTES | - SHGetFileInfoConstants.SHGFI_EXETYPE; - } - - /// - /// Constructs a new instance of the FileIcon class - /// and retrieves the icon, display name and type name - /// for the specified file. - /// - /// The filename to get the icon, - /// display name and type name for - public FileIcon(string fileName) - : this() - { - this.fileName = fileName; - GetInfo(); - } - - /// - /// Constructs a new instance of the FileIcon class - /// and retrieves the information specified in the - /// flags. - /// - /// The filename to get information - /// for - /// The flags to use when extracting the - /// icon and other shell information. - public FileIcon(string fileName, SHGetFileInfoConstants flags) - { - this.fileName = fileName; - this.flags = flags; - GetInfo(); - } - } -} diff --git a/CollapseLauncher/Classes/ShellLinkCOM/Win32FindDataW.cs b/CollapseLauncher/Classes/ShellLinkCOM/Win32FindDataW.cs deleted file mode 100644 index bde8bb902..000000000 --- a/CollapseLauncher/Classes/ShellLinkCOM/Win32FindDataW.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Runtime.InteropServices; - -namespace CollapseLauncher.ShellLinkCOM -{ - [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0)] - public partial struct Win32FindDataW - { - public uint dwFileAttributes; // 4 - public Filetime ftCreationTime; // 12 - public Filetime ftLastAccessTime; // 20 - public Filetime ftLastWriteTime; // 28 - public uint nFileSizeHigh; // 32 - public uint nFileSizeLow; // 36 - public uint dwReserved0; // 40 - public uint dwReserved1; // 44 - - [MarshalAs(UnmanagedType.ByValArray, - // SizeConst = 260 - SizeConst = 520 - )] - public char[] cFileName; - - [MarshalAs(UnmanagedType.ByValArray, - // SizeConst = 14 - SizeConst = 28 - )] - public char[] cAlternateFileName; - - public uint dwFileType; - public uint dwCreatorType; - public uint wFinderFlags; - } -} diff --git a/CollapseLauncher/CollapseLauncher.csproj b/CollapseLauncher/CollapseLauncher.csproj index 480e29fa6..c4d312afe 100644 --- a/CollapseLauncher/CollapseLauncher.csproj +++ b/CollapseLauncher/CollapseLauncher.csproj @@ -1,4 +1,4 @@ - + WinExe @@ -194,6 +194,7 @@ + diff --git a/CollapseLauncher/Program.cs b/CollapseLauncher/Program.cs index 009c4b0a9..e917f038f 100644 --- a/CollapseLauncher/Program.cs +++ b/CollapseLauncher/Program.cs @@ -1,11 +1,12 @@ using CollapseLauncher.Helper; using CollapseLauncher.Helper.Update; -using CollapseLauncher.ShellLinkCOM; using Hi3Helper; using Hi3Helper.SentryHelper; using Hi3Helper.Data; using Hi3Helper.Http.Legacy; using Hi3Helper.Shared.ClassStruct; +using Hi3Helper.Win32.Native; +using Hi3Helper.Win32.ShellLinkCOM; using InnoSetupHelper; using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; @@ -35,17 +36,20 @@ namespace CollapseLauncher; +public static partial class MainEntryPointExtension +{ + [LibraryImport("Microsoft.ui.xaml.dll", EntryPoint = "XamlCheckProcessRequirements")] + public static partial void XamlCheckProcessRequirements(); +} + public static class MainEntryPoint { #nullable enable public static int InstanceCount; public static App? CurrentAppInstance; - public static string[]? LastArgs = null; + public static string[]? LastArgs; #nullable restore - [DllImport("Microsoft.ui.xaml.dll")] - private static extern void XamlCheckProcessRequirements(); - [STAThread] public static void Main(params string[] args) { @@ -59,18 +63,19 @@ public static void Main(params string[] args) AppCurrentArgument = args; // Extract icons from the executable file - var mainModulePath = Process.GetCurrentProcess().MainModule?.FileName; - var iconCount = InvokeProp.ExtractIconEx(mainModulePath, -1, null, null, 0); + string mainModulePath = Process.GetCurrentProcess().MainModule?.FileName ?? ""; + var iconCount = PInvoke.ExtractIconEx(mainModulePath, -1, null, null, 0); if (iconCount > 0) { var largeIcons = new IntPtr[1]; var smallIcons = new IntPtr[1]; - InvokeProp.ExtractIconEx(mainModulePath, 0, largeIcons, smallIcons, 1); + PInvoke.ExtractIconEx(mainModulePath, 0, largeIcons, smallIcons, 1); AppIconLarge = largeIcons[0]; AppIconSmall = smallIcons[0]; } - InitAppPreset(); + WindowUtility.CurrentScreenProp = new Hi3Helper.Win32.Screen.ScreenProp(); + InitAppPreset(WindowUtility.CurrentScreenProp); var logPath = AppGameLogsFolder; _log = IsConsoleEnabled ? new LoggerConsole(logPath, Encoding.UTF8) @@ -173,12 +178,12 @@ public static void Main(params string[] args) AppDomain.CurrentDomain.ProcessExit += OnProcessExit!; - InstanceCount = InvokeProp.EnumerateInstances(); + InstanceCount = PInvoke.EnumerateInstances(ILoggerHelper.GetILogger()); AppActivation.Enable(); if (!AppActivation.DecideRedirection()) { - XamlCheckProcessRequirements(); + MainEntryPointExtension.XamlCheckProcessRequirements(); ComWrappersSupport.InitializeComWrappers(); StartMainApplication(); @@ -313,7 +318,7 @@ private static void StartUpdaterHook() .WithRestarted(TryCleanupFallbackUpdate) .WithAfterUpdateFastCallback(TryCleanupFallbackUpdate) .WithFirstRun(TryCleanupFallbackUpdate) - .Run(ILoggerHelper.CreateCollapseILogger()); + .Run(ILoggerHelper.GetILogger()); #endif } @@ -371,7 +376,7 @@ public static void TryCleanupFallbackUpdate(SemanticVersion newVersion) // Try to remove legacy shortcuts string currentWindowsPathDrive = Path.GetPathRoot(Environment.SystemDirectory); - if (currentWindowsPathDrive != null) + if (!string.IsNullOrEmpty(currentWindowsPathDrive)) { string squirrelLegacyStartMenuGlobal = Path.Combine(currentWindowsPathDrive, @"ProgramData\Microsoft\Windows\Start Menu\Programs\Collapse\Collapse Launcher"); string squirrelLegacyStartMenuGlobalParent = Path.GetDirectoryName(squirrelLegacyStartMenuGlobal); @@ -382,7 +387,7 @@ public static void TryCleanupFallbackUpdate(SemanticVersion newVersion) } // Try to delete all possible shortcuts on any users (since the shortcut used will be the global one) - string currentUsersDirPath = Path.Combine(currentWindowsPathDrive, "Users"); + string currentUsersDirPath = Path.Combine(currentWindowsPathDrive!, "Users"); foreach (string userDirInfoPath in Directory .EnumerateDirectories(currentUsersDirPath, "*", SearchOption.TopDirectoryOnly) .Where(ConverterTool.IsUserHasPermission)) diff --git a/CollapseLauncher/XAMLs/MainApp/MainWindow.xaml.cs b/CollapseLauncher/XAMLs/MainApp/MainWindow.xaml.cs index bb96941f2..4165e0d58 100644 --- a/CollapseLauncher/XAMLs/MainApp/MainWindow.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/MainWindow.xaml.cs @@ -8,7 +8,9 @@ using CollapseLauncher.Pages.OOBE; using CommunityToolkit.WinUI.Animations; using Hi3Helper; +using Hi3Helper.SentryHelper; using Hi3Helper.Shared.Region; +using Hi3Helper.Win32.Native; using Microsoft.UI.Composition; using Microsoft.UI.Input; using Microsoft.UI.Windowing; @@ -16,12 +18,9 @@ using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media.Animation; using System; -using System.Threading; using System.Threading.Tasks; using Windows.UI; -using Hi3Helper.SentryHelper; using static CollapseLauncher.InnerLauncherConfig; -using static Hi3Helper.InvokeProp; using static Hi3Helper.Logger; using static Hi3Helper.Shared.Region.LauncherConfig; // ReSharper disable RedundantExtendsListEntry @@ -176,10 +175,10 @@ public void InitializeWindowSettings() } // Hide system menu - var controlsHwnd = FindWindowEx(WindowUtility.CurrentWindowPtr, 0, "ReunionWindowingCaptionControls", "ReunionCaptionControlsWindow"); + var controlsHwnd = PInvoke.FindWindowEx(WindowUtility.CurrentWindowPtr, 0, "ReunionWindowingCaptionControls", "ReunionCaptionControlsWindow"); if (controlsHwnd != IntPtr.Zero) { - DestroyWindow(controlsHwnd); + PInvoke.DestroyWindow(controlsHwnd); } } else @@ -201,7 +200,7 @@ public void InitializeWindowSettings() LauncherUpdateInvoker.UpdateEvent += LauncherUpdateInvoker_UpdateEvent; m_consoleCtrlHandler += ConsoleCtrlHandler; - SetConsoleCtrlHandler(m_consoleCtrlHandler, true); + PInvoke.SetConsoleCtrlHandler(m_consoleCtrlHandler, true); } private bool ConsoleCtrlHandler(uint dwCtrlType) diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/CachesPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/CachesPage.xaml.cs index 629353142..c805c5b36 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/CachesPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/CachesPage.xaml.cs @@ -5,6 +5,7 @@ using CollapseLauncher.Statics; using Hi3Helper; using Hi3Helper.Shared.ClassStruct; + using Hi3Helper.Win32.Native; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls.Primitives; @@ -57,7 +58,7 @@ public async void RunCheckRoutine(object sender, bool isFast, bool isMainButton) try { - InvokeProp.PreventSleep(); + PInvoke.PreventSleep(ILoggerHelper.GetILogger()); AddEvent(); bool IsNeedUpdate = await CurrentGameProperty._GameCache.StartCheckRoutine(isFast); @@ -96,7 +97,7 @@ public async void RunCheckRoutine(object sender, bool isFast, bool isMainButton) finally { RemoveEvent(); - InvokeProp.RestoreSleep(); + PInvoke.RestoreSleep(); } } @@ -107,7 +108,7 @@ public async void StartCachesUpdate(object sender, RoutedEventArgs e) try { - InvokeProp.PreventSleep(); + PInvoke.PreventSleep(ILoggerHelper.GetILogger()); AddEvent(); int assetCount = CurrentGameProperty._GameCache.AssetEntry.Count; @@ -145,7 +146,7 @@ public async void StartCachesUpdate(object sender, RoutedEventArgs e) } finally { - InvokeProp.RestoreSleep(); + PInvoke.RestoreSleep(); RemoveEvent(); } } diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/InstallationConvert.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/InstallationConvert.xaml.cs index 76cca66a3..afc69b6cc 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/InstallationConvert.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/InstallationConvert.xaml.cs @@ -1,6 +1,5 @@ using CollapseLauncher.CustomControls; using CollapseLauncher.Extension; -using CollapseLauncher.FileDialogCOM; using CollapseLauncher.Helper; using CollapseLauncher.Helper.Metadata; using CollapseLauncher.Statics; @@ -8,6 +7,7 @@ using Hi3Helper.Data; using Hi3Helper.Http; using Hi3Helper.Http.Legacy; +using Hi3Helper.Win32.FileDialogCOM; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media; @@ -25,6 +25,7 @@ using static Hi3Helper.Locale; using static Hi3Helper.Logger; using static Hi3Helper.Shared.Region.LauncherConfig; +// ReSharper disable RedundantExtendsListEntry namespace CollapseLauncher.Dialogs { @@ -32,7 +33,7 @@ public partial class InstallationConvert : Page { string SourceDataIntegrityURL; string GameVersion; - bool IsAlreadyConverted = false; + bool IsAlreadyConverted; PresetConfig SourceProfile; PresetConfig TargetProfile; GameConversionManagement Converter; @@ -137,8 +138,7 @@ public async void StartConversionProcess() private void DoSetProfileDataLocation() { SourceProfile.ActualGameDataLocation = NormalizePath(SourceIniFile["launcher"]["game_install_path"].ToString()); - TargetProfile.ActualGameDataLocation = Path.Combine(Path.GetDirectoryName(SourceProfile.ActualGameDataLocation), $"{TargetProfile.GameDirectoryName}_ConvertedTo-{TargetProfile.ProfileName}"); - string TargetINIPath = Path.Combine(AppGameFolder, TargetProfile.ProfileName, "config.ini"); + TargetProfile.ActualGameDataLocation = Path.Combine(Path.GetDirectoryName(SourceProfile.ActualGameDataLocation) ?? "", $"{TargetProfile.GameDirectoryName}_ConvertedTo-{TargetProfile.ProfileName}"); DispatcherQueue?.TryEnqueue(() => { @@ -189,7 +189,7 @@ private async Task FetchDataIntegrityURL(PresetConfig Profile) internal bool IsSourceGameExist(PresetConfig Profile) { - string INIPath = Path.Combine(AppGameFolder, Profile.ProfileName, "config.ini"); + string INIPath = Path.Combine(AppGameFolder, Profile.ProfileName ?? "", "config.ini"); string GamePath; string ExecPath; if (!File.Exists(INIPath)) @@ -229,7 +229,7 @@ internal bool IsSourceGameExist(PresetConfig Profile) GameVersion? remoteVersion = CurrentGameProperty._GameVersion.GetGameVersionAPI(); if (!localVersion.IsMatch(remoteVersion)) return false; - ExecPath = Path.Combine(GamePath, Profile.GameExecutableName); + ExecPath = Path.Combine(GamePath, Profile.GameExecutableName ?? ""); if (!File.Exists(ExecPath)) return false; } @@ -243,45 +243,60 @@ internal bool IsSourceGameExist(PresetConfig Profile) internal async Task<(PresetConfig, PresetConfig)> AskConvertionDestination() { - (ContentDialogResult Result, ComboBox SourceGame, ComboBox TargetGame) = await Dialog_SelectGameConvertRecipe(Content); - PresetConfig SourceRet = null; - PresetConfig TargetRet = null; + (ContentDialogResult result, ComboBox sourceGame, ComboBox targetGame) = await Dialog_SelectGameConvertRecipe(Content); + PresetConfig sourceRet = null; + PresetConfig targetRet = null; - if (SourceGame.SelectedItem == null || TargetGame.SelectedItem == null) + if (sourceGame.SelectedItem == null || targetGame.SelectedItem == null) throw new OperationCanceledException(); - string sourceGameRegionString = InnerLauncherConfig.GetComboBoxGameRegionValue(SourceGame.SelectedItem); - string targetGameRegionString = InnerLauncherConfig.GetComboBoxGameRegionValue(TargetGame.SelectedItem); + string sourceGameRegionString = InnerLauncherConfig.GetComboBoxGameRegionValue(sourceGame.SelectedItem); + string targetGameRegionString = InnerLauncherConfig.GetComboBoxGameRegionValue(targetGame.SelectedItem); - switch (Result) + switch (result) { case ContentDialogResult.Secondary: - SourceRet = LauncherMetadataHelper.LauncherMetadataConfig[LauncherMetadataHelper.CurrentMetadataConfigGameName]. - Values.Where(x => x.ZoneName == sourceGameRegionString).First(); - TargetRet = LauncherMetadataHelper.LauncherMetadataConfig[LauncherMetadataHelper.CurrentMetadataConfigGameName]. - Values.Where(x => x.ZoneName == targetGameRegionString).First(); + if (LauncherMetadataHelper.CurrentMetadataConfigGameName != null) + { + sourceRet = LauncherMetadataHelper + .LauncherMetadataConfig![LauncherMetadataHelper.CurrentMetadataConfigGameName].Values + .Where(x => x.ZoneName == sourceGameRegionString)!.First(); + targetRet = LauncherMetadataHelper + .LauncherMetadataConfig![LauncherMetadataHelper.CurrentMetadataConfigGameName].Values + .Where(x => x.ZoneName == targetGameRegionString)!.First(); + } + break; case ContentDialogResult.Primary: throw new OperationCanceledException(); + case ContentDialogResult.None: + break; + default: + throw new ArgumentOutOfRangeException(); } - return (SourceRet, TargetRet); + return (sourceRet, targetRet); } - public static List GetConvertibleNameList(string ZoneName) + public static List GetConvertibleNameList(string zoneName) { - List _out = new List(); - List GameTargetProfileName = LauncherMetadataHelper.LauncherMetadataConfig[LauncherMetadataHelper.CurrentMetadataConfigGameName].Values - .Where(x => x.ZoneName == ZoneName) - .Select(x => x.ConvertibleTo) - .First(); - - foreach (string Entry in GameTargetProfileName) - _out.Add(LauncherMetadataHelper.LauncherMetadataConfig[LauncherMetadataHelper.CurrentMetadataConfigGameName].Values - .Where(x => x.ZoneName == Entry) - .Select(x => x.ZoneName) - .First()); - - return _out; + List outList = new List(); + if (LauncherMetadataHelper.CurrentMetadataConfigGameName == null) + { + return outList; + } + + List gameTargetProfileName = LauncherMetadataHelper.LauncherMetadataConfig![LauncherMetadataHelper.CurrentMetadataConfigGameName].Values + .Where(x => x.ZoneName == zoneName) + .Select(x => x.ConvertibleTo) + .First()!; + + foreach (string entry in gameTargetProfileName) + outList.Add(LauncherMetadataHelper.LauncherMetadataConfig[LauncherMetadataHelper.CurrentMetadataConfigGameName].Values + .Where(x => x.ZoneName == entry) + .Select(x => x.ZoneName) + .First()); + + return outList; } private async Task DoDownloadRecipe() @@ -338,17 +353,6 @@ private void Step2ProgressEvents(object sender, DownloadEvent e) }); } - private void Step2ProgressEvents(int read, DownloadProgress downloadProgress) - { - double speed = downloadProgress.BytesDownloaded / CurrentStopwatch.Elapsed.TotalSeconds; - double percentage = GetPercentageNumber(downloadProgress.BytesDownloaded, downloadProgress.BytesTotal); - DispatcherQueue?.TryEnqueue(() => - { - Step2ProgressStatus.Text = $"{percentage}% - {string.Format(Lang._Misc.SpeedPerSec, SummarizeSizeSimple(speed))}"; - Step2ProgressRing.Value = percentage; - }); - } - private async Task DoPrepareIngredients() { DispatcherQueue?.TryEnqueue(() => @@ -507,7 +511,6 @@ private async void CancelConversion(object sender, RoutedEventArgs e) if (await Dialog.QueueAndSpawnDialog() == ContentDialogResult.Primary) { tokenSource.Cancel(); - return; } } @@ -532,11 +535,11 @@ private void RevertConversion() foreach (string filePath in Directory.EnumerateFiles(IngrPath, "*", SearchOption.AllDirectories)) { ReadOnlySpan relativePath = filePath.AsSpan().Slice(DirLength); - destFilePath = Path.Combine(OrigPath, relativePath.ToString()); + destFilePath = Path.Combine(OrigPath ?? "", relativePath.ToString()); destFolderPath = Path.GetDirectoryName(destFilePath); if (!Directory.Exists(destFolderPath)) - Directory.CreateDirectory(destFolderPath); + Directory.CreateDirectory(destFolderPath ?? ""); try { diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs b/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs index 19d305636..3abb23e39 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/Dialogs/SimpleDialogs.cs @@ -1,15 +1,14 @@ using CollapseLauncher.CustomControls; using CollapseLauncher.Extension; -using CollapseLauncher.FileDialogCOM; using CollapseLauncher.Helper; using CollapseLauncher.Helper.Animation; -using CollapseLauncher.Helper.Image; using CollapseLauncher.Helper.Metadata; using CollapseLauncher.InstallManager.Base; using CollapseLauncher.Statics; using CommunityToolkit.WinUI; using Hi3Helper; using Hi3Helper.SentryHelper; +using Hi3Helper.Win32.Native; using Microsoft.UI.Input; using Microsoft.UI.Text; using Microsoft.UI.Xaml; @@ -1147,7 +1146,7 @@ public static async Task Dialog_ShowUnhandledExceptionMenu( private static async void CopyTextToClipboard(object sender, RoutedEventArgs e) { - InvokeProp.CopyStringToClipboard(ErrorSender.ExceptionContent); + PInvoke.CopyStringToClipboard(ErrorSender.ExceptionContent, ILoggerHelper.GetILogger()); if (sender is Button btn && btn.Content != null && btn.Content is Panel panel) { FontIcon fontIcon = panel.Children[0] as FontIcon; diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/FileCleanupPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/FileCleanupPage.xaml.cs index a0c44b0b9..27c1c2e3f 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/FileCleanupPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/FileCleanupPage.xaml.cs @@ -4,6 +4,7 @@ using CollapseLauncher.InstallManager.Base; using Hi3Helper; using Hi3Helper.Data; +using Hi3Helper.Win32.Native; using Microsoft.UI.Text; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; @@ -216,7 +217,7 @@ private async Task PerformRemoval(ICollection? deletionSource, lo } } - await Task.Run(() => InvokeProp.MoveFileToRecycleBin(toBeDeleted)); + await Task.Run(() => PInvoke.MoveFileToRecycleBin(toBeDeleted)); DispatcherQueue.TryEnqueue(() => { for (int i = FileInfoSource.Count - 1; i >= 0; i--) diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/GenshinGameSettingsPage.Ext.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/GenshinGameSettingsPage.Ext.cs index 9bf7096b5..560aacb6e 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/GenshinGameSettingsPage.Ext.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/GenshinGameSettingsPage.Ext.cs @@ -1,6 +1,6 @@ using CollapseLauncher.GameSettings.Genshin; using CollapseLauncher.GameSettings.Genshin.Enums; -using Hi3Helper.Screen; +using CollapseLauncher.Helper; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using System; @@ -127,7 +127,7 @@ public bool IsCustomResolutionEnabled GameResolutionFullscreenExclusive.IsEnabled = IsFullscreenEnabled; GameResolutionSelector.IsEnabled = true; - Size size = ScreenProp.GetScreenSize(); + Size size = WindowUtility.CurrentScreenProp.GetScreenSize(); GameResolutionSelector.SelectedItem = $"{size.Width}x{size.Height}"; } } @@ -212,7 +212,7 @@ public string ResolutionSelected string res = Settings.SettingsScreen.sizeResString; if (string.IsNullOrEmpty(res)) { - Size size = ScreenProp.GetScreenSize(); + Size size = WindowUtility.CurrentScreenProp.GetScreenSize(); return $"{size.Width}x{size.Height}"; } return res; diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/HonkaiGameSettingsPage.Ext.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/HonkaiGameSettingsPage.Ext.cs index f7e687d95..e6a4ffd68 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/HonkaiGameSettingsPage.Ext.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/HonkaiGameSettingsPage.Ext.cs @@ -2,7 +2,7 @@ using CollapseLauncher.GameSettings; using CollapseLauncher.GameSettings.Honkai; using CollapseLauncher.GameSettings.Honkai.Enums; -using Hi3Helper.Screen; +using CollapseLauncher.Helper; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using System.Collections.Generic; @@ -158,7 +158,7 @@ public bool IsCustomResolutionEnabled GameResolutionFullscreenExclusive.IsEnabled = IsFullscreenEnabled; GameResolutionSelector.IsEnabled = true; - Size size = ScreenProp.GetScreenSize(); + Size size = WindowUtility.CurrentScreenProp.GetScreenSize(); GameResolutionSelector.SelectedItem = $"{size.Width}x{size.Height}"; } } @@ -228,7 +228,7 @@ public string ResolutionSelected string res = Settings.SettingsScreen.sizeResString; if (string.IsNullOrEmpty(res)) { - Size size = ScreenProp.GetScreenSize(); + Size size = WindowUtility.CurrentScreenProp.GetScreenSize(); return $"{size.Width}x{size.Height}"; } return res; diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/StarRailGameSettingsPage.Ext.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/StarRailGameSettingsPage.Ext.cs index f0272189c..9888a2eb8 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/StarRailGameSettingsPage.Ext.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/StarRailGameSettingsPage.Ext.cs @@ -1,6 +1,6 @@ using CollapseLauncher.GameSettings.StarRail; +using CollapseLauncher.Helper; using Hi3Helper; -using Hi3Helper.Screen; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using System; @@ -91,7 +91,7 @@ public bool IsCustomResolutionEnabled GameResolutionFullscreenExclusive.IsEnabled = IsFullscreenEnabled; GameResolutionSelector.IsEnabled = true; - Size size = ScreenProp.GetScreenSize(); + Size size = WindowUtility.CurrentScreenProp.GetScreenSize(); GameResolutionSelector.SelectedItem = $"{size.Width}x{size.Height}"; } } @@ -178,7 +178,7 @@ public string ResolutionSelected string res = Settings.SettingsScreen.sizeResString; if (string.IsNullOrEmpty(res)) { - Size size = ScreenProp.GetScreenSize(); + Size size = WindowUtility.CurrentScreenProp.GetScreenSize(); return $"{size.Width}x{size.Height}"; } return res; diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/ZenlessGameSettingsPage.Ext.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/ZenlessGameSettingsPage.Ext.cs index 7864d7f2f..a3265cc3e 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/ZenlessGameSettingsPage.Ext.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/ZenlessGameSettingsPage.Ext.cs @@ -1,5 +1,5 @@ using CollapseLauncher.GameSettings.Zenless.Enums; -using Hi3Helper.Screen; +using CollapseLauncher.Helper; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using System.Collections.Generic; @@ -185,7 +185,7 @@ public bool IsCustomResolutionEnabled GameResolutionFullscreenExclusive.IsEnabled = IsFullscreenEnabled; GameResolutionSelector.IsEnabled = true; - Size size = ScreenProp.GetScreenSize(); + Size size = WindowUtility.CurrentScreenProp.GetScreenSize(); GameResolutionSelector.SelectedItem = $"{size.Width}x{size.Height}"; } } @@ -272,7 +272,7 @@ public string ResolutionSelected string res = Settings.SettingsScreen.sizeResString; if (string.IsNullOrEmpty(res)) { - Size size = ScreenProp.GetScreenSize(); + Size size = WindowUtility.CurrentScreenProp.GetScreenSize(); return $"{size.Width}x{size.Height}"; } return res; diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/ZenlessGameSettingsPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/ZenlessGameSettingsPage.xaml.cs index 554e958fd..1b8466d5d 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/ZenlessGameSettingsPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/GameSettingsPages/ZenlessGameSettingsPage.xaml.cs @@ -7,11 +7,9 @@ using CollapseLauncher.Statics; using Hi3Helper; using Hi3Helper.Data; - using Hi3Helper.Screen; using Hi3Helper.Shared.ClassStruct; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media; - using Microsoft.UI.Xaml.Navigation; using Microsoft.Win32; using RegistryUtils; using System; @@ -25,6 +23,7 @@ using static Hi3Helper.Logger; using static Hi3Helper.Shared.Region.LauncherConfig; using static CollapseLauncher.Statics.GamePropertyVault; +using CollapseLauncher.Helper; namespace CollapseLauncher.Pages { @@ -209,11 +208,11 @@ private void InitializeSettings(object sender, RoutedEventArgs e) private List GetResPairs_Fullscreen() { - var displayProp = ScreenProp.GetScreenSize(); + var displayProp = WindowUtility.CurrentScreenProp.GetScreenSize(); var nativeAspRatio = (double)displayProp.Width / displayProp.Height; var acH = acceptableHeight; - acH.RemoveAll(h => h > ScreenProp.GetMaxHeight()); + acH.RemoveAll(h => h > WindowUtility.CurrentScreenProp.GetMaxHeight()); List resPairs = new List(); @@ -228,13 +227,13 @@ private List GetResPairs_Fullscreen() private List GetResPairs_Windowed() { - var displayProp = ScreenProp.GetScreenSize(); + var displayProp = WindowUtility.CurrentScreenProp.GetScreenSize(); var nativeAspRatio = (double)displayProp.Width / displayProp.Height; var wideRatio = (double)16 / 9; var ulWideRatio = (double)21 / 9; var acH = acceptableHeight; - acH.RemoveAll(h => h > ScreenProp.GetMaxHeight()); + acH.RemoveAll(h => h > WindowUtility.CurrentScreenProp.GetMaxHeight()); List resPairs = new List(); diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml.cs index fe8b69b28..371298802 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/HomePage.xaml.cs @@ -5,7 +5,6 @@ using CollapseLauncher.Helper.LauncherApiLoader.Sophon; using CollapseLauncher.Dialogs; using CollapseLauncher.Extension; -using CollapseLauncher.FileDialogCOM; using CollapseLauncher.GamePlaytime; using CollapseLauncher.GameSettings.Genshin; using CollapseLauncher.Helper; @@ -22,9 +21,10 @@ using H.NotifyIcon; using Hi3Helper; using Hi3Helper.EncTool.WindowTool; -using Hi3Helper.Screen; using Hi3Helper.SentryHelper; using Hi3Helper.Shared.ClassStruct; +using Hi3Helper.Win32.FileDialogCOM; +using Hi3Helper.Win32.Native; using Microsoft.UI.Composition; using Microsoft.UI.Input; using Microsoft.UI.Text; @@ -51,7 +51,6 @@ using static CollapseLauncher.Dialogs.SimpleDialogs; using static CollapseLauncher.InnerLauncherConfig; using static CollapseLauncher.Helper.Background.BackgroundMediaUtility; -using static CollapseLauncher.FileDialogCOM.FileDialogNative; using static Hi3Helper.Data.ConverterTool; using static Hi3Helper.Locale; using static Hi3Helper.Logger; @@ -276,7 +275,7 @@ private async void StartLoadedRoutine(object sender, RoutedEventArgs e) } catch (ArgumentNullException ex) { - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); + await SentryHelper.ExceptionHandlerAsync(ex, SentryHelper.ExceptionType.UnhandledOther); LogWriteLine($"The necessary section of Launcher Scope's config.ini is broken.\r\n{ex}", LogType.Error, true); } catch (Exception ex) @@ -369,7 +368,7 @@ await ImageLoaderHelper.ResizeImageStream(copyIconFileStream, cachedIconFileStre } catch (Exception ex) { - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); + await SentryHelper.ExceptionHandlerAsync(ex, SentryHelper.ExceptionType.UnhandledOther); LogWriteLine($"Failed while loading EventPanel image icon\r\n{ex}", LogType.Error, true); } } @@ -401,12 +400,12 @@ public async void StartCarouselAutoScroll(int delaySeconds = 5) } catch (Exception ex) { - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); + await SentryHelper.ExceptionHandlerAsync(ex, SentryHelper.ExceptionType.UnhandledOther); LogWriteLine($"[HomePage::StartCarouselAutoScroll] Task returns error!\r\n{ex}", LogType.Error, true); } } - private void CarouselPointerExited(object sender = null, PointerRoutedEventArgs e = null) => CarouselRestartScroll(5); + private void CarouselPointerExited(object sender = null, PointerRoutedEventArgs e = null) => CarouselRestartScroll(); private async void CarouselPointerEntered(object sender = null, PointerRoutedEventArgs e = null) => await CarouselStopScroll(); public async void CarouselRestartScroll(int delaySeconds = 5) @@ -808,7 +807,7 @@ private async Task TagPropertyAction_OpenExternalApp(string propertiesStri { case ContentDialogResult.Primary: // Try to get the file path - file = await GetFilePicker(new Dictionary { { applicationName, applicationExecName } }, string.Format(Lang._HomePage.CommunityToolsBtn_OpenExecutableAppDialogTitle, applicationName)); + file = await FileDialogNative.GetFilePicker(new Dictionary { { applicationName, applicationExecName } }, string.Format(Lang._HomePage.CommunityToolsBtn_OpenExecutableAppDialogTitle, applicationName)); // If the file returns null because of getting cancelled, then back to loop again. if (string.IsNullOrEmpty(file)) continue; // Otherwise, assign the value to applicationPath variable and save it to the app config @@ -848,8 +847,8 @@ private async Task TagPropertyAction_OpenExternalApp(string propertiesStri { // If error happened while running the app, then log and return true as successful // Thoughts @Cry0? Should we mark it as successful (true) or failed (false)? - // Mark is as true, since the app still ran but it's an error outside our scope. - SentryHelper.ExceptionHandler(ex); + // Mark is as true, since the app still ran, but it's an error outside our scope. + await SentryHelper.ExceptionHandlerAsync(ex); LogWriteLine($"Unable to start app {applicationName}! {ex}", LogType.Error, true); return true; } @@ -1091,7 +1090,7 @@ private async void CheckRunningGameInstance(CancellationToken Token) } catch (Exception ex) { - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); + await SentryHelper.ExceptionHandlerAsync(ex, SentryHelper.ExceptionType.UnhandledOther); LogWriteLine($"Error when checking if game is running!\r\n{ex}", LogType.Error, true); } } @@ -1175,7 +1174,7 @@ private async void SpawnPreloadBox() } catch (Exception ex) { - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); + await SentryHelper.ExceptionHandlerAsync(ex, SentryHelper.ExceptionType.UnhandledOther); LogWriteLine($"An error occured while trying to determine delta-patch availability\r\n{ex}", LogType.Error, true); } } @@ -1191,7 +1190,7 @@ private async void PredownloadDialog(object sender, RoutedEventArgs e) try { // Prevent device from sleep - InvokeProp.PreventSleep(); + PInvoke.PreventSleep(ILoggerHelper.GetILogger()); // Set the notification trigger to "Running" state CurrentGameProperty._GameInstall.UpdateCompletenessStatus(CompletenessStatus.Running); @@ -1223,10 +1222,10 @@ private async void PredownloadDialog(object sender, RoutedEventArgs e) PreloadDialogBox.Title = Lang._HomePage.PreloadDownloadNotifbarVerifyTitle; verifResult = await CurrentGameProperty._GameInstall.StartPackageVerification(); - + // Restore sleep before the dialog // so system won't be stuck when download is finished because of the download verified dialog - InvokeProp.RestoreSleep(); + PInvoke.RestoreSleep(); if (verifResult == -1) { @@ -1276,7 +1275,7 @@ private async void PredownloadDialog(object sender, RoutedEventArgs e) CurrentGameProperty._GameInstall.Flush(); // Turn the sleep back on - InvokeProp.RestoreSleep(); + PInvoke.RestoreSleep(); } } @@ -1314,7 +1313,7 @@ private async void InstallGameDialog(object sender, RoutedEventArgs e) try { // Prevent device from sleep - InvokeProp.PreventSleep(); + PInvoke.PreventSleep(ILoggerHelper.GetILogger()); // Set the notification trigger to "Running" state CurrentGameProperty._GameInstall.UpdateCompletenessStatus(CompletenessStatus.Running); @@ -1463,7 +1462,7 @@ await SpawnDialog(Lang._HomePage.InstallFolderRootTitle, IsPageUnload = true; LogWriteLine($"Error while installing game {CurrentGameProperty._GameVersion.GamePreset.ZoneFullname}.\r\n{ex}", LogType.Error, true); - ErrorSender.SendException(ex, ErrorType.Unhandled); + ErrorSender.SendException(ex); } finally { @@ -1482,7 +1481,7 @@ await SpawnDialog(Lang._HomePage.InstallFolderRootTitle, ReturnToHomePage(); // Turn the sleep back on - InvokeProp.RestoreSleep(); + PInvoke.RestoreSleep(); } } @@ -1523,9 +1522,9 @@ private void GameInstall_ProgressChanged_Inner(TotalPerfileProgress e) private void GameInstallSophon_StatusChanged(object sender, TotalPerfileStatus e) { if (DispatcherQueue.HasThreadAccess) - GameInstallSophon_StatusChanged_Inner(sender, e); + GameInstallSophon_StatusChanged_Inner(e); else - DispatcherQueue?.TryEnqueue(() => GameInstallSophon_StatusChanged_Inner(sender, e)); + DispatcherQueue?.TryEnqueue(() => GameInstallSophon_StatusChanged_Inner(e)); } private void GameInstallSophon_ProgressChanged(object sender, TotalPerfileProgress e) @@ -1536,7 +1535,7 @@ private void GameInstallSophon_ProgressChanged(object sender, TotalPerfileProgre DispatcherQueue?.TryEnqueue(() => GameInstallSophon_ProgressChanged_Inner(e)); } - private void GameInstallSophon_StatusChanged_Inner(object sender, TotalPerfileStatus e) + private void GameInstallSophon_StatusChanged_Inner(TotalPerfileStatus e) { SophonProgressStatusTitleText.Text = e.ActivityStatus; SophonProgressPerFile.Visibility = e.IsIncludePerFileIndicator ? Visibility.Visible : Visibility.Collapsed; @@ -1793,6 +1792,7 @@ internal async void StartResizableWindowPayload(string executableName, IGa ResizableWindowHookToken = new CancellationTokenSource(); executableName = Path.GetFileNameWithoutExtension(executableName); + string gameExecutableDirectory = CurrentGameProperty._GameVersion.GameDirPath; ResizableWindowHook resizableWindowHook = new ResizableWindowHook(); // Set the pos + size reinitialization to true if the game is Honkai: Star Rail @@ -1800,8 +1800,8 @@ internal async void StartResizableWindowPayload(string executableName, IGa // it impossible to use custom resolution (but since you are using Collapse, it's now // possible :teriStare:) bool isNeedToResetPos = gameType == GameNameType.StarRail; - await resizableWindowHook.StartHook(executableName, height, width, ResizableWindowHookToken.Token, - isNeedToResetPos); + await Task.Run(() => resizableWindowHook.StartHook(executableName, height, width, ResizableWindowHookToken.Token, + isNeedToResetPos, ILoggerHelper.GetILogger(), gameExecutableDirectory)); } catch (Exception ex) { @@ -1844,7 +1844,7 @@ private async void SetBackScreenSettings(IGameSettingsUniversal settingsUniversa } catch(Exception ex) { - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); + await SentryHelper.ExceptionHandlerAsync(ex, SentryHelper.ExceptionType.UnhandledOther); LogWriteLine($"[SetBackScreenSettings] Failed to set Screen Settings!\r\n{ex}", LogType.Error, true); } @@ -1874,7 +1874,7 @@ internal string GetLaunchArguments(IGameSettingsUniversal _Settings) { LogWriteLine($"You are going to use DX12 mode in your game.\r\n\tUsing CustomScreenResolution or FullscreenExclusive value may break the game!", LogType.Warning); if (_Settings.SettingsCollapseScreen.UseCustomResolution && _Settings.SettingsScreen.isfullScreen) - parameter.AppendFormat("-screen-width {0} -screen-height {1} ", ScreenProp.GetScreenSize().Width, ScreenProp.GetScreenSize().Height); + parameter.AppendFormat("-screen-width {0} -screen-height {1} ", WindowUtility.CurrentScreenProp?.GetScreenSize().Width, WindowUtility.CurrentScreenProp?.GetScreenSize().Height); else parameter.AppendFormat("-screen-width {0} -screen-height {1} ", screenSize.Width, screenSize.Height); } @@ -1944,7 +1944,7 @@ internal string GetLaunchArguments(IGameSettingsUniversal _Settings) { LogWriteLine($"You are going to use DX12 mode in your game.\r\n\tUsing CustomScreenResolution or FullscreenExclusive value may break the game!", LogType.Warning); if (_Settings.SettingsCollapseScreen.UseCustomResolution && _Settings.SettingsScreen.isfullScreen) - parameter.AppendFormat("-screen-width {0} -screen-height {1} ", ScreenProp.GetScreenSize().Width, ScreenProp.GetScreenSize().Height); + parameter.AppendFormat("-screen-width {0} -screen-height {1} ", WindowUtility.CurrentScreenProp?.GetScreenSize().Width, WindowUtility.CurrentScreenProp?.GetScreenSize().Height); else parameter.AppendFormat("-screen-width {0} -screen-height {1} ", screenSize.Width, screenSize.Height); } @@ -1972,7 +1972,7 @@ internal string GetLaunchArguments(IGameSettingsUniversal _Settings) { LogWriteLine($"You are going to use DX12 mode in your game.\r\n\tUsing CustomScreenResolution or FullscreenExclusive value may break the game!", LogType.Warning); if (_Settings.SettingsCollapseScreen.UseCustomResolution && _Settings.SettingsScreen.isfullScreen) - parameter.AppendFormat("-screen-width {0} -screen-height {1} ", ScreenProp.GetScreenSize().Width, ScreenProp.GetScreenSize().Height); + parameter.AppendFormat("-screen-width {0} -screen-height {1} ", WindowUtility.CurrentScreenProp?.GetScreenSize().Width, WindowUtility.CurrentScreenProp?.GetScreenSize().Height); else parameter.AppendFormat("-screen-width {0} -screen-height {1} ", screenSize.Width, screenSize.Height); } @@ -2038,7 +2038,7 @@ public bool UseCustomBGRegion { bool value = CurrentGameProperty?._GameSettings?.SettingsCollapseMisc?.UseCustomRegionBG ?? false; ChangeGameBGButton.IsEnabled = value; - string path = CurrentGameProperty?._GameSettings?.SettingsCollapseMisc.CustomRegionBGPath ?? ""; + string path = CurrentGameProperty?._GameSettings?.SettingsCollapseMisc?.CustomRegionBGPath ?? ""; BGPathDisplay.Text = Path.GetFileName(path); return value; } @@ -2046,7 +2046,10 @@ public bool UseCustomBGRegion { ChangeGameBGButton.IsEnabled = value; - var regionBgPath = CurrentGameProperty?._GameSettings?.SettingsCollapseMisc.CustomRegionBGPath; + if (CurrentGameProperty?._GameSettings == null) + return; + + var regionBgPath = CurrentGameProperty._GameSettings.SettingsCollapseMisc.CustomRegionBGPath; if (string.IsNullOrEmpty(regionBgPath) || !File.Exists(regionBgPath)) { regionBgPath = Path.GetFileName(GetAppConfigValue("CustomBGPath").ToString()); @@ -2055,7 +2058,7 @@ public bool UseCustomBGRegion } CurrentGameProperty._GameSettings.SettingsCollapseMisc.UseCustomRegionBG = value; - CurrentGameProperty?._GameSettings?.SaveBaseSettings(); + CurrentGameProperty._GameSettings.SaveBaseSettings(); m_mainPage?.ChangeBackgroundImageAsRegionAsync(); BGPathDisplay.Text = Path.GetFileName(regionBgPath); @@ -2126,11 +2129,11 @@ public async void TryInstallMediaPack() #region Exclusive Window Payload public async void StartExclusiveWindowPayload() { - IntPtr _windowPtr = InvokeProp.GetProcessWindowHandle(CurrentGameProperty._GameVersion.GamePreset.GameExecutableName); + IntPtr _windowPtr = PInvoke.GetProcessWindowHandle(CurrentGameProperty._GameVersion.GamePreset.GameExecutableName ?? ""); await Task.Delay(1000); - new InvokeProp.InvokePresence(_windowPtr).HideWindow(); + PInvoke.HideWindow(_windowPtr); await Task.Delay(1000); - new InvokeProp.InvokePresence(_windowPtr).ShowWindow(); + PInvoke.ShowWindow(_windowPtr); } #endregion @@ -2301,7 +2304,7 @@ private async void CleanupFilesButton_Click(object sender, RoutedEventArgs e) { GameStartupSetting.Flyout.Hide(); if (CurrentGameProperty?._GameInstall != null) - await CurrentGameProperty._GameInstall.CleanUpGameFiles(true); + await CurrentGameProperty._GameInstall.CleanUpGameFiles(); } catch (Exception ex) { @@ -2337,7 +2340,7 @@ private async void StopGameButton_Click(object sender, RoutedEventArgs e) private async void ChangeGameBGButton_Click(object sender, RoutedEventArgs e) { - var file = await GetFilePicker(ImageLoaderHelper.SupportedImageFormats); + var file = await FileDialogNative.GetFilePicker(ImageLoaderHelper.SupportedImageFormats); if (string.IsNullOrEmpty(file)) return; var currentMediaType = GetMediaType(file); @@ -2350,7 +2353,7 @@ private async void ChangeGameBGButton_Click(object sender, RoutedEventArgs e) SetAlternativeFileStream(croppedImage); } - if (((IGameSettingsUniversal)CurrentGameProperty?._GameSettings)?.SettingsCollapseMisc != null) + if (CurrentGameProperty?._GameSettings?.SettingsCollapseMisc != null) { CurrentGameProperty._GameSettings.SettingsCollapseMisc.CustomRegionBGPath = file; CurrentGameProperty._GameSettings.SaveBaseSettings(); @@ -2379,7 +2382,7 @@ private async void MoveGameLocationButton_Click(object sender, RoutedEventArgs e catch (Exception ex) { LogWriteLine($"Error has occurred while running Move Game Location tool!\r\n{ex}", LogType.Error, true); - ErrorSender.SendException(ex, ErrorType.Unhandled); + ErrorSender.SendException(ex); } } #endregion @@ -2517,7 +2520,7 @@ private async void UpdateGameDialog(object sender, RoutedEventArgs e) try { // Prevent device from sleep - InvokeProp.PreventSleep(); + PInvoke.PreventSleep(ILoggerHelper.GetILogger()); // Set the notification trigger to "Running" state CurrentGameProperty._GameInstall.UpdateCompletenessStatus(CompletenessStatus.Running); @@ -2620,7 +2623,7 @@ private async void UpdateGameDialog(object sender, RoutedEventArgs e) ReturnToHomePage(); // Turn the sleep back on - InvokeProp.RestoreSleep(); + PInvoke.RestoreSleep(); } } #endregion @@ -2698,7 +2701,7 @@ private async void CollapsePrioControl(Process proc) } catch (Exception ex) { - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); + await SentryHelper.ExceptionHandlerAsync(ex, SentryHelper.ExceptionType.UnhandledOther); LogWriteLine($"Error in Collapse Priority Control module!\r\n{ex}", LogType.Error, true); } } @@ -2755,7 +2758,7 @@ private async void GameBoost_Invoke(GamePresetProperty gameProp) } catch (Exception ex) { - SentryHelper.ExceptionHandler(ex, SentryHelper.ExceptionType.UnhandledOther); + await SentryHelper.ExceptionHandlerAsync(ex, SentryHelper.ExceptionType.UnhandledOther); LogWriteLine($"[HomePage::GameBoost_Invoke] There has been error while boosting game priority to Above Normal!\r\n" + $"\tTarget Process : {toTargetProc?.ProcessName} [{toTargetProc?.Id}]\r\n{ex}", LogType.Error, true); } diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/OOBE/OOBEStartUpMenu.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/OOBE/OOBEStartUpMenu.xaml.cs index 7302dde57..d0ed3eae0 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/OOBE/OOBEStartUpMenu.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/OOBE/OOBEStartUpMenu.xaml.cs @@ -1,5 +1,4 @@ using CollapseLauncher.AnimatedVisuals.Lottie; -using CollapseLauncher.Classes.FileDialogCOM; using CollapseLauncher.Dialogs; using CollapseLauncher.Extension; using CollapseLauncher.FileDialogCOM; @@ -12,8 +11,9 @@ using CommunityToolkit.WinUI.Animations; using Hi3Helper; using Hi3Helper.CommunityToolkit.WinUI.Controls; -using Hi3Helper.Data; using Hi3Helper.Shared.ClassStruct; +using Hi3Helper.Win32.FileDialogCOM; +using Hi3Helper.Win32.Native; using Microsoft.UI.Composition; using Microsoft.UI.Text; using Microsoft.UI.Xaml; @@ -442,7 +442,7 @@ private static int GetInitialTheme() string themeValue = GetAppConfigValue("ThemeMode").ToString(); if (Enum.TryParse(themeValue, true, out CurrentAppTheme)) return (int)CurrentAppTheme; - CurrentAppTheme = !InvokeProp.ShouldAppsUseDarkMode() ? AppThemeMode.Light : AppThemeMode.Dark; + CurrentAppTheme = !PInvoke.ShouldAppsUseDarkMode() ? AppThemeMode.Light : AppThemeMode.Dark; LogWriteLine($"ThemeMode: {themeValue} is invalid! Falling back to Dark-mode (Valid values are: {string.Join(',', Enum.GetNames(typeof(AppThemeMode)))})", LogType.Warning, true); diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/RepairPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/RepairPage.xaml.cs index 3d4eaf12e..572d36471 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/RepairPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/RepairPage.xaml.cs @@ -5,6 +5,7 @@ using CollapseLauncher.Statics; using Hi3Helper; using Hi3Helper.Shared.ClassStruct; + using Hi3Helper.Win32.Native; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls.Primitives; @@ -45,7 +46,7 @@ private void StartGameCheck(object sender, RoutedEventArgs e) private async void RunCheckRoutine(object sender, bool isFast, bool isMainButton) { - InvokeProp.PreventSleep(); + PInvoke.PreventSleep(ILoggerHelper.GetILogger()); CheckFilesBtn.Flyout.Hide(); CheckFilesBtn.IsEnabled = false; @@ -96,13 +97,13 @@ private async void RunCheckRoutine(object sender, bool isFast, bool isMainButton finally { RemoveEvent(); - InvokeProp.RestoreSleep(); + PInvoke.RestoreSleep(); } } private async void StartGameRepair(object sender, RoutedEventArgs e) { - InvokeProp.PreventSleep(); + PInvoke.PreventSleep(ILoggerHelper.GetILogger()); RepairFilesBtn.IsEnabled = false; CancelBtn.IsEnabled = true; @@ -146,7 +147,7 @@ private async void StartGameRepair(object sender, RoutedEventArgs e) finally { RemoveEvent(); - InvokeProp.RestoreSleep(); + PInvoke.RestoreSleep(); } } diff --git a/CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml.cs index 84b9cf149..93f0d69cc 100644 --- a/CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml.cs @@ -18,6 +18,7 @@ using Hi3Helper.SentryHelper; using Hi3Helper.Shared.ClassStruct; using Hi3Helper.Shared.Region; + using Hi3Helper.Win32.FileDialogCOM; using Microsoft.UI.Input; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; @@ -36,7 +37,6 @@ using static CollapseLauncher.Helper.Image.Waifu2X; using static CollapseLauncher.InnerLauncherConfig; using static CollapseLauncher.WindowSize.WindowSize; - using static CollapseLauncher.FileDialogCOM.FileDialogNative; using static Hi3Helper.Locale; using static Hi3Helper.Logger; using static Hi3Helper.Shared.Region.LauncherConfig; @@ -411,7 +411,7 @@ private void ClickButtonLinkFromTag(object sender, RoutedEventArgs e) private async void SelectBackgroundImg(object sender, RoutedEventArgs e) { - string file = await GetFilePicker(ImageLoaderHelper.SupportedImageFormats); + string file = await FileDialogNative.GetFilePicker(ImageLoaderHelper.SupportedImageFormats); if (!string.IsNullOrEmpty(file)) { var currentMediaType = BackgroundMediaUtility.GetMediaType(file); diff --git a/CollapseLauncher/XAMLs/MainApp/TrayIcon.xaml.cs b/CollapseLauncher/XAMLs/MainApp/TrayIcon.xaml.cs index 34bd18305..0acf918d8 100644 --- a/CollapseLauncher/XAMLs/MainApp/TrayIcon.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/TrayIcon.xaml.cs @@ -4,6 +4,7 @@ using H.NotifyIcon.Core; using Hi3Helper; using Hi3Helper.Shared.Region; +using Hi3Helper.Win32.Native; using Microsoft.UI.Xaml; using System; using System.Drawing; @@ -11,10 +12,11 @@ using Hi3Helper.SentryHelper; using static CollapseLauncher.InnerLauncherConfig; using static CollapseLauncher.Pages.HomePage; -using static Hi3Helper.InvokeProp; using static Hi3Helper.Locale; using static Hi3Helper.Logger; +// Resharper disable all + namespace CollapseLauncher { public sealed partial class TrayIcon @@ -159,9 +161,9 @@ public void ToggleConsoleVisibility(bool forceShow = false) { if (LauncherConfig.GetAppConfigValue("EnableConsole").ToBool()) { - IntPtr consoleWindowHandle = GetConsoleWindow(); + IntPtr consoleWindowHandle = PInvoke.GetConsoleWindow(); if (LoggerConsole.ConsoleHandle == IntPtr.Zero) return; - if (IsWindowVisible(consoleWindowHandle) && !forceShow) + if (PInvoke.IsWindowVisible(consoleWindowHandle) && !forceShow) { LoggerConsole.DisposeConsole(); ConsoleTaskbarToggle.Text = _showConsole; @@ -170,7 +172,7 @@ public void ToggleConsoleVisibility(bool forceShow = false) else { LoggerConsole.AllocateConsole(); - SetForegroundWindow(GetConsoleWindow()); + PInvoke.SetForegroundWindow(PInvoke.GetConsoleWindow()); ConsoleTaskbarToggle.Text = _hideConsole; LogWriteLine("Console is visible!"); } @@ -183,7 +185,7 @@ public void ToggleConsoleVisibility(bool forceShow = false) public void ToggleMainVisibility(bool forceShow = false) { IntPtr mainWindowHandle = WindowUtility.CurrentWindowPtr; - var isVisible = IsWindowVisible(mainWindowHandle); + var isVisible = PInvoke.IsWindowVisible(mainWindowHandle); if (isVisible && !forceShow) { @@ -205,7 +207,7 @@ public void ToggleMainVisibility(bool forceShow = false) { WindowUtility.CurrentWindow?.Show(false); EfficiencyModeWrapper(false); - SetForegroundWindow(mainWindowHandle); + PInvoke.SetForegroundWindow(mainWindowHandle); MainTaskbarToggle.Text = _hideApp; // Revert refresh rate to its default RefreshRate = RefreshRateDefault; @@ -218,11 +220,11 @@ public void ToggleMainVisibility(bool forceShow = false) /// public void ToggleAllVisibility() { - IntPtr consoleWindowHandle = GetConsoleWindow(); + IntPtr consoleWindowHandle = PInvoke.GetConsoleWindow(); IntPtr mainWindowHandle = WindowUtility.CurrentWindowPtr; - bool isMainWindowVisible = IsWindowVisible(mainWindowHandle); + bool isMainWindowVisible = PInvoke.IsWindowVisible(mainWindowHandle); - bool isConsoleVisible = LauncherConfig.GetAppConfigValue("EnableConsole").ToBool() && IsWindowVisible(consoleWindowHandle); + bool isConsoleVisible = LauncherConfig.GetAppConfigValue("EnableConsole").ToBool() && PInvoke.IsWindowVisible(consoleWindowHandle); if (isMainWindowVisible && !isConsoleVisible) { @@ -246,27 +248,27 @@ public void ToggleAllVisibility() public void BringToForeground() { IntPtr mainWindowHandle = WindowUtility.CurrentWindowPtr; - IntPtr consoleWindowHandle = GetConsoleWindow(); + IntPtr consoleWindowHandle = PInvoke.GetConsoleWindow(); - bool isMainWindowVisible = IsWindowVisible(mainWindowHandle); + bool isMainWindowVisible = PInvoke.IsWindowVisible(mainWindowHandle); if (LauncherConfig.GetAppConfigValue("EnableConsole").ToBool()) { - if (!IsWindowVisible(consoleWindowHandle)) + if (!PInvoke.IsWindowVisible(consoleWindowHandle)) { ToggleConsoleVisibility(true); } //Stupid workaround for console window not showing up using SetForegroundWindow //Basically do minimize then maximize action using ShowWindow 6->9 (nice) - ShowWindow(consoleWindowHandle, 6); - ShowWindow(consoleWindowHandle, 9); + PInvoke.ShowWindow(consoleWindowHandle, 6); + PInvoke.ShowWindow(consoleWindowHandle, 9); //SetForegroundWindow(consoleWindowHandle); } if (!isMainWindowVisible) ToggleMainVisibility(true); - ShowWindow(mainWindowHandle, 9); - SetForegroundWindow(mainWindowHandle); + PInvoke.ShowWindow(mainWindowHandle, 9); + PInvoke.SetForegroundWindow(mainWindowHandle); } /// @@ -287,11 +289,11 @@ public void UpdateContextMenu() } // Force refresh all text based on their respective window state - IntPtr consoleWindowHandle = GetConsoleWindow(); + IntPtr consoleWindowHandle = PInvoke.GetConsoleWindow(); IntPtr mainWindowHandle = WindowUtility.CurrentWindowPtr; - bool isMainWindowVisible = IsWindowVisible(mainWindowHandle); - bool isConsoleVisible = LauncherConfig.GetAppConfigValue("EnableConsole").ToBool() && IsWindowVisible(consoleWindowHandle); + bool isMainWindowVisible = PInvoke.IsWindowVisible(mainWindowHandle); + bool isConsoleVisible = LauncherConfig.GetAppConfigValue("EnableConsole").ToBool() && PInvoke.IsWindowVisible(consoleWindowHandle); ConsoleTaskbarToggle.Text = isConsoleVisible ? _hideConsole : _showConsole; MainTaskbarToggle.Text = isMainWindowVisible ? _hideApp : _showApp; diff --git a/CollapseLauncher/XAMLs/Updater/Classes/Updater.cs b/CollapseLauncher/XAMLs/Updater/Classes/Updater.cs index d67d1a521..75a1918c7 100644 --- a/CollapseLauncher/XAMLs/Updater/Classes/Updater.cs +++ b/CollapseLauncher/XAMLs/Updater/Classes/Updater.cs @@ -71,7 +71,7 @@ public Updater(string ChannelName) ); UpdateDownloader = new UpdateManagerHttpAdapter(); #if USEVELOPACK - UpdateManagerLogger = ILoggerHelper.CreateCollapseILogger(); + UpdateManagerLogger = ILoggerHelper.GetILogger(); VelopackLocator updateManagerLocator = VelopackLocator.GetDefault(UpdateManagerLogger); UpdateOptions updateManagerOptions = new UpdateOptions { diff --git a/CollapseLauncher/packages.lock.json b/CollapseLauncher/packages.lock.json index f66cd34ba..0f312f985 100644 --- a/CollapseLauncher/packages.lock.json +++ b/CollapseLauncher/packages.lock.json @@ -389,16 +389,17 @@ "h.notifyicon.winui": { "type": "Project", "dependencies": { - "H.NotifyIcon": "[0.0.0, )", - "Microsoft.Web.WebView2": "[1.0.2950-prerelease, )", + "H.NotifyIcon": "[1.0.0, )", + "Microsoft.Web.WebView2": "[1.0.2895-prerelease, )", "Microsoft.Windows.SDK.BuildTools": "[10.0.26100.1742, )", - "Microsoft.WindowsAppSDK": "[1.6.241114003, )" + "Microsoft.WindowsAppSDK": "[1.6.240923002, )" } }, "hi3helper.core": { "type": "Project", "dependencies": { "Hi3Helper.EncTool": "[1.0.0, )", + "Hi3Helper.Win32": "[1.0.0, )", "Microsoft.Windows.CsWinRT": "[2.2.0, )", "Sentry": "[4.13.0, )" } @@ -408,6 +409,7 @@ "dependencies": { "Google.Protobuf": "[3.28.3, )", "Hi3Helper.Http": "[2.0.0, )", + "Hi3Helper.Win32": "[1.0.0, )", "System.IO.Hashing": "[9.0.0, )" } }, @@ -422,6 +424,12 @@ "System.IO.Hashing": "[9.0.0, )" } }, + "hi3helper.win32": { + "type": "Project", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "[9.0.0, )" + } + }, "ImageCropper": { "type": "Project", "dependencies": { @@ -438,11 +446,8 @@ "imageex": { "type": "Project", "dependencies": { - "CommunityToolkit.Common": "[8.4.0-preview2, )", - "CommunityToolkit.WinUI.Extensions": "[8.2.241112-preview1, )", - "Microsoft.Web.WebView2": "[1.0.2950-prerelease, )", - "Microsoft.Windows.SDK.BuildTools": "[10.0.26100.1742, )", - "Microsoft.WindowsAppSDK": "[1.6.241114003, )" + "CommunityToolkit.WinUI.Extensions": "[8.1.240916, )", + "Microsoft.WindowsAppSDK": "[1.6.240829007, )" } }, "innosetuphelper": { diff --git a/H.NotifyIcon b/H.NotifyIcon index 9b3c318a5..8ae464206 160000 --- a/H.NotifyIcon +++ b/H.NotifyIcon @@ -1 +1 @@ -Subproject commit 9b3c318a55521fc470d2f250f1a09e467a1443d4 +Subproject commit 8ae464206f5c633b2b7e5e7b81ff40df6a83d79a diff --git a/Hi3Helper.Core/Classes/Data/InvokeProp.cs b/Hi3Helper.Core/Classes/Data/InvokeProp.cs deleted file mode 100644 index 2dace4c85..000000000 --- a/Hi3Helper.Core/Classes/Data/InvokeProp.cs +++ /dev/null @@ -1,739 +0,0 @@ -using System; -using System.Buffers; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Numerics; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using static Hi3Helper.Logger; -// ReSharper disable InconsistentNaming -// ReSharper disable IdentifierTypo -// ReSharper disable MemberCanBePrivate.Global - -namespace Hi3Helper -{ - public static class InvokeProp - { - #region Enums - // Reference: - // https://pinvoke.net/default.aspx/Enums.SystemMetric - public enum SystemMetric - { - SM_CXSCREEN = 0, - SM_CYSCREEN = 1, - SM_CYCAPTION = 4, - SM_CYSIZEFRAME = 33, - SM_CXPADDEDBORDER = 92, - } - - // Reference: - // https://pinvoke.net/default.aspx/Enums/SetWindowPosFlags.html - [Flags] - public enum SetWindowPosFlags : uint - { - SWP_NOSIZE = 1, - SWP_NOMOVE = 2, - SWP_NOZORDER = 4, - SWP_FRAMECHANGED = 0x20, - SWP_SHOWWINDOW = 0x40, - } - - [Flags] - public enum GLOBAL_ALLOC_FLAGS : uint - { - GHND = 0x0042, - GMEM_FIXED = 0x00000000, - GMEM_MOVEABLE = 0x00000002, - GMEM_ZEROINIT = 0x00000040, - GPTR = 0x00000040, - } - - public enum HandleEnum - { - SW_HIDE = 0, - SW_SHOWNORMAL = 1, - SW_SHOWMINIMIZED = 2, - SW_SHOWMAXIMIZED = 3, - SW_SHOW = 5, - } - - public enum Monitor_DPI_Type - { - MDT_Effective_DPI = 0, - MDT_Angular_DPI = 1, - MDT_Raw_DPI = 2, - MDT_Default = MDT_Effective_DPI - } - - public enum PreferredAppMode - { - Default, - AllowDark, - ForceDark, - ForceLight, - Max - }; - - [Flags] - private enum ExecutionState : uint - { - EsAwaymodeRequired = 0x00000040, - EsContinuous = 0x80000000, - EsDisplayRequired = 0x00000002, - EsSystemRequired = 0x00000001 - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - private struct SHFILEOPSTRUCT - { - public IntPtr hwnd; - public uint wFunc; - public string pFrom; - public string pTo; - public ushort fFlags; - public int fAnyOperationsAborted; - public IntPtr hNameMappings; - public string lpszProgressTitle; - } - #endregion - - #region Kernel32 - [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode); - - [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode); - - [DllImport("kernel32.dll", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern IntPtr GetConsoleWindow(); - - [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle); - - [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool AllocConsole(); - - [DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, uint lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, uint hTemplateFile); - - [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern IntPtr GlobalAlloc(GLOBAL_ALLOC_FLAGS uFlags, nuint uBytes); - - [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern IntPtr GlobalFree(IntPtr hMem); - - [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern IntPtr GlobalLock(IntPtr hMem); - - [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool GlobalUnlock(IntPtr hMem); - - [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool SetConsoleCtrlHandler(HandlerRoutine handlerRoutine, bool add); - - [DllImport("kernel32.dll", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern ExecutionState SetThreadExecutionState(ExecutionState esFlags); - - [DllImport("Kernel32.dll", CharSet = CharSet.Unicode )] - public static extern bool CreateHardLink( - string lpFileName, - string lpExistingFileName, - IntPtr lpSecurityAttributes - ); - #endregion - - #region User32 - public struct WINDOWPOS - { - public IntPtr hwnd; - public IntPtr hwndInsertAfter; - public int x; - public int y; - public int cx; - public int cy; - public uint flags; - } - - [DllImport("user32.dll", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); - - [DllImport("user32.dll", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern int GetSystemMetrics(SystemMetric nIndex); - - [DllImport("user32.dll", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); - - [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags); - - [DllImport("user32.dll", EntryPoint = "SendMessageW", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, UIntPtr wParam, IntPtr lParam); - - [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool OpenClipboard(IntPtr hWndNewOwner); - - [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool CloseClipboard(); - - [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern IntPtr SetClipboardData(uint uFormat, IntPtr data); - - [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool EmptyClipboard(); - - [DllImport("user32.dll", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool IsWindowVisible(IntPtr hWnd); - - [DllImport("user32.dll", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool SetForegroundWindow(IntPtr hWnd); - - [DllImport("user32.dll", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern IntPtr GetForegroundWindow(); - - [DllImport("user32.dll", EntryPoint = "SetWindowLongPtrW", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); - - [DllImport("user32.dll", EntryPoint = "FindWindowExW", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); - - [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern bool DestroyWindow(IntPtr hwnd); - - [DllImport("user32.dll", EntryPoint = "CallWindowProcW", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam); - #endregion - - #region Shcore - [DllImport("Shcore.dll", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern int GetDpiForMonitor(IntPtr hmonitor, Monitor_DPI_Type dpiType, out uint dpiX, out uint dpiY); - #endregion - - #region Ntdll - // https://github.com/dotnet/runtime/blob/f4d39134b8daefb5ab0db6750a203f980eecb4f0/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Win32.cs#L299 - // https://github.com/dotnet/runtime/blob/f4d39134b8daefb5ab0db6750a203f980eecb4f0/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Win32.cs#L346 - // https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/Interop/Windows/NtDll/Interop.NtQuerySystemInformation.cs#L11 - - private const int SystemProcessInformation = 5; - - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa380518.aspx - // https://msdn.microsoft.com/en-us/library/windows/hardware/ff564879.aspx - [StructLayout(LayoutKind.Sequential)] - private unsafe struct UNICODE_STRING - { - /// - /// Length in bytes, not including the null terminator, if any. - /// - internal ushort Length; - - /// - /// Max size of the buffer in bytes - /// - internal ushort MaximumLength; - internal void* Buffer; - } - - [DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private unsafe static extern uint NtQuerySystemInformation(int SystemInformationClass, byte* SystemInformation, uint SystemInformationLength, out uint ReturnLength); - - [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] - private static extern nint OpenProcess(int dwDesiredAccess, bool bInheritHandle, uint dwProcessId); - - [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "QueryFullProcessImageNameW")] - public static unsafe extern bool QueryFullProcessImageName(nint hProcess, int dwFlags, char* lpExeName, ref int lpdwSize); - - private const int DefaultNtQueryChangedLen = 4 << 17; - private static int DynamicNtQueryChangedBufferLen = DefaultNtQueryChangedLen; - - public unsafe static bool IsProcessExist(ReadOnlySpan processName, string checkForOriginPath = "") - { - // If the buffer length is more than 2 MiB, then reset the length to default - if (DynamicNtQueryChangedBufferLen > (2 << 20)) - { - DynamicNtQueryChangedBufferLen = DefaultNtQueryChangedLen; - } - - // Initialize the first buffer to 512 KiB - ArrayPool arrayPool = ArrayPool.Shared; - byte[] NtQueryCachedBuffer = arrayPool.Rent(DynamicNtQueryChangedBufferLen); - bool isReallocate = false; - uint length = 0; - - // Get size of UNICODE_STRING struct - int sizeOfUnicodeString = Marshal.SizeOf(); - - StartOver: - try - { - // If the buffer request is more than 2 MiB, then return false - if (DynamicNtQueryChangedBufferLen > (2 << 20)) - return false; - - // If buffer reallocation is requested, then re-rent the buffer - // from ArrayPool.Shared - if (isReallocate) - NtQueryCachedBuffer = arrayPool.Rent(DynamicNtQueryChangedBufferLen); - - // Get the pointer of the buffer - fixed (byte* dataBufferPtr = &NtQueryCachedBuffer[0]) - { - // Get the query of the current running process and store it to the buffer - uint hNtQuerySystemInformationResult = NtQuerySystemInformation(SystemProcessInformation, dataBufferPtr, (uint)NtQueryCachedBuffer.Length, out length); - - // If the required length of the data is exceeded than the current buffer, - // then try to reallocate and start over to the top. - const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; - if (hNtQuerySystemInformationResult == STATUS_INFO_LENGTH_MISMATCH || length > NtQueryCachedBuffer.Length) - { - // Round up length - DynamicNtQueryChangedBufferLen = (int)BitOperations.RoundUpToPowerOf2(length); - LogWriteLine($"Buffer requested is insufficient! Requested: {length} > Capacity: {NtQueryCachedBuffer.Length}, Resizing the buffer...", LogType.Warning, true); - isReallocate = true; - goto StartOver; - } - - // If other error has occurred, then return false as failed. - if (hNtQuerySystemInformationResult != 0) - { - LogWriteLine($"Error happened while operating NtQuerySystemInformation(): {Marshal.GetLastWin32Error()}", LogType.Error, true); - return false; - } - - // Start reading data from the buffer - int currentOffset = 0; - bool isCommandPathEqual = false; - ReadQueryData: - // Get the current position of the pointer based on its offset - byte* curPosPtr = dataBufferPtr + currentOffset; - - // Get the increment of the next entry offset - // and get the struct from the given pointer offset + 56 bytes ahead - // to obtain the process name. - int nextEntryOffset = *(int*)curPosPtr; - UNICODE_STRING* unicodeString = (UNICODE_STRING*)(curPosPtr + 56); - - // Use the struct buffer into the ReadOnlySpan to be compared with - // the input from "processName" argument. - ReadOnlySpan imageNameSpan = new ReadOnlySpan(unicodeString->Buffer, unicodeString->Length / 2); - bool isMatchedExecutable = imageNameSpan.Equals(processName, StringComparison.OrdinalIgnoreCase); - if (isMatchedExecutable) - { - // If the origin path argument is null, then return as true. - if (string.IsNullOrEmpty(checkForOriginPath)) - return true; - - // If the string is not null, then check if the file path is exactly the same. - // START!! - - // Move the offset of the current pointer and get the processId value - uint processId = *(uint*)(curPosPtr + 56 + sizeOfUnicodeString + 8); - - // Try open the process and get the handle - const int QueryLimitedInformation = 0x1000; - nint processHandle = OpenProcess(QueryLimitedInformation, false, processId); - - // If failed, then log the Win32 error and return false. - if (processHandle == nint.Zero) - { - LogWriteLine($"Error happened while operating OpenProcess(): {Marshal.GetLastWin32Error()}", LogType.Error, true); - return false; - } - - // Try rent the new buffer to get the command line - int bufferProcessCmdLen = 1 << 10; - int bufferProcessCmdLenReturn = bufferProcessCmdLen; - char[] bufferProcessCmd = ArrayPool.Shared.Rent(bufferProcessCmdLen); - try - { - // Cast processCmd buffer as pointer - fixed (char* bufferProcessCmdPtr = &bufferProcessCmd[0]) - { - // Get the command line query of the process - bool hQueryFullProcessImageNameResult = QueryFullProcessImageName(processHandle, 0, bufferProcessCmdPtr, ref bufferProcessCmdLenReturn); - // If the query is unsuccessful, then log the Win32 error and return false. - if (!hQueryFullProcessImageNameResult) - { - LogWriteLine($"Error happened while operating QueryFullProcessImageName(): {Marshal.GetLastWin32Error()}", LogType.Error, true); - return false; - } - - // If the requested return length is more than capacity (-2 for null terminator), then return false. - if (bufferProcessCmdLenReturn > bufferProcessCmdLen - 2) - { - LogWriteLine($"The process command line length is more than requested length: {bufferProcessCmdLen - 2} < return {bufferProcessCmdLenReturn}", LogType.Error, true); - return false; - } - - // Get the command line query - ReadOnlySpan processCmdLineSpan = new ReadOnlySpan(bufferProcessCmdPtr, bufferProcessCmdLenReturn); - - // Get the span of origin path to compare - ReadOnlySpan checkForOriginPathDir = checkForOriginPath; - - // Compare and return if any of result is equal - isCommandPathEqual = processCmdLineSpan.Equals(checkForOriginPathDir, StringComparison.OrdinalIgnoreCase); - if (isCommandPathEqual) - return true; - } - } - finally - { - // Return the buffer - ArrayPool.Shared.Return(bufferProcessCmd); - } - } - - // Otherwise, if the next entry offset is not 0 (not ended), then read - // the next data and move forward based on the given offset. - currentOffset += nextEntryOffset; - if (nextEntryOffset != 0) - goto ReadQueryData; - } - } - finally - { - // Return the buffer to the ArrayPool.Shared - arrayPool.Return(NtQueryCachedBuffer); - } - - return false; - } - -#nullable enable - public static unsafe string? GetProcessPathByProcessId(int processId) - { - // Try open the process and get the handle - const int QueryLimitedInformation = 0x1000; - nint processHandle = OpenProcess(QueryLimitedInformation, false, (uint)processId); - - // If failed, then log the Win32 error and return null. - if (processHandle == nint.Zero) - { - LogWriteLine($"Error happened while operating OpenProcess(): {Marshal.GetLastWin32Error()}", LogType.Error, true); - return null; - } - - // Try rent the new buffer to get the command line - int bufferProcessCmdLen = 1 << 10; - int bufferProcessCmdLenReturn = bufferProcessCmdLen; - char[] bufferProcessCmd = ArrayPool.Shared.Rent(bufferProcessCmdLen); - - try - { - // Cast processCmd buffer as pointer - fixed (char* bufferProcessCmdPtr = &bufferProcessCmd[0]) - { - // Get the command line query of the process - bool hQueryFullProcessImageNameResult = QueryFullProcessImageName(processHandle, 0, bufferProcessCmdPtr, ref bufferProcessCmdLenReturn); - // If the query is unsuccessful, then log the Win32 error and return false. - if (!hQueryFullProcessImageNameResult) - { - LogWriteLine($"Error happened while operating QueryFullProcessImageName(): {Marshal.GetLastWin32Error()}", LogType.Error, true); - return null; - } - - // If the requested return length is more than capacity (-2 for null terminator), then return false. - if (bufferProcessCmdLenReturn > bufferProcessCmdLen - 2) - { - LogWriteLine($"The process command line length is more than requested length: {bufferProcessCmdLen - 2} < return {bufferProcessCmdLenReturn}", LogType.Error, true); - return null; - } - - // Return string - return new string(bufferProcessCmdPtr, 0, bufferProcessCmdLenReturn); - } - } - finally - { - ArrayPool.Shared.Return(bufferProcessCmd); - } - } -#nullable restore - #endregion - - #region shell32 - [DllImport("shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern uint ExtractIconEx(string lpszFile, int nIconIndex, IntPtr[] phiconLarge, IntPtr[] phiconSmall, uint nIcons); - - public static void SetWindowIcon(IntPtr hWnd, IntPtr hIconLarge, IntPtr hIconSmall) - { - const uint WM_SETICON = 0x0080; - const UIntPtr ICON_BIG = 1; - const UIntPtr ICON_SMALL = 0; - SendMessage(hWnd, WM_SETICON, ICON_BIG, hIconLarge); - SendMessage(hWnd, WM_SETICON, ICON_SMALL, hIconSmall); - } - - [DllImport("shell32.dll", CharSet = CharSet.Auto)] - private static extern int SHFileOperation(ref SHFILEOPSTRUCT FileOp); - #endregion - - public static void MoveFileToRecycleBin(IList filePaths) - { - uint FO_DELETE = 0x0003; - ushort FOF_ALLOWUNDO = 0x0040; - ushort FOF_NOCONFIRMATION = 0x0010; - - var concat = string.Join('\0', filePaths) + '\0' + '\0'; - - SHFILEOPSTRUCT fileOp = new SHFILEOPSTRUCT - { - wFunc = FO_DELETE, - pFrom = concat, - fFlags = (ushort)(FOF_ALLOWUNDO | FOF_NOCONFIRMATION) - }; - - SHFileOperation(ref fileOp); - } - -#nullable enable - public static CancellationTokenSource? _preventSleepToken; - private static bool _preventSleepRunning; - - public static async void RestoreSleep() - { - // Return early if token is disposed/already cancelled - if (_preventSleepToken == null || _preventSleepToken.IsCancellationRequested) - return; - await (_preventSleepToken?.CancelAsync() ?? Task.CompletedTask); - } - - public static async void PreventSleep() - { - // Only run this loop once - if (_preventSleepRunning) return; - - // Initialize instance if it's still null - _preventSleepToken ??= new CancellationTokenSource(); - - // If the instance cancellation has been requested, return - if (_preventSleepToken.IsCancellationRequested) return; - - // Set flag - _preventSleepRunning = true; - - try - { - LogWriteLine("[InvokeProp::PreventSleep()] Starting to prevent sleep!", LogType.Warning, true); - while (!_preventSleepToken.IsCancellationRequested) - { - // Set ES to SystemRequired every 60s - SetThreadExecutionState(ExecutionState.EsContinuous | ExecutionState.EsSystemRequired); - await Task.Delay(60000, _preventSleepToken.Token); - } - } - catch (TaskCanceledException) - { - //do nothing, its cancelled :) - } - catch (Exception ex) - { - await SentryHelper.SentryHelper.ExceptionHandlerAsync(ex, SentryHelper.SentryHelper.ExceptionType.UnhandledOther); - LogWriteLine($"[InvokeProp::PreventSleep()] Errors while preventing sleep!\r\n{ex}", - LogType.Error, true); - } - finally - { - // Reset flag and ES - _preventSleepRunning = false; - SetThreadExecutionState(ExecutionState.EsContinuous); - LogWriteLine("[InvokeProp::PreventSleep()] Stopped preventing sleep!", LogType.Warning, true); - - // Null the token for the next time method is called - _preventSleepToken = null; - } - } -#nullable restore - - public static unsafe void CopyStringToClipboard(string inputString) - { - // Initialize the memory pointer - // ReSharper disable RedundantAssignment - IntPtr stringBufferPtr = IntPtr.Zero; - // ReSharper restore RedundantAssignment - IntPtr hMem = IntPtr.Zero; - - // Set the Clipboard bool status - bool isOpenClipboardSuccess = false; - - try - { - // If inputString is null or empty, then return - if (string.IsNullOrEmpty(inputString)) - { - LogWriteLine($"[InvokeProp::CopyStringToClipboard()] inputString cannot be empty! Clipboard will not be set!", LogType.Warning, true); - return; - } - - // Try open the Clipboard - if (!(isOpenClipboardSuccess = OpenClipboard(IntPtr.Zero))) - LogWriteLine($"[InvokeProp::CopyStringToClipboard()] Error has occurred while opening clipboard buffer! Error: {Marshal.GetLastPInvokeErrorMessage()}", LogType.Error, true); - - // Set the bufferSize + 1, the additional 1 byte will be used to interpret the null byte - int bufferSize = (inputString.Length + 1); - - // Allocate the Global-Movable buffer to the kernel with given size and lock the buffer - hMem = GlobalAlloc(GLOBAL_ALLOC_FLAGS.GMEM_MOVEABLE, (nuint)bufferSize); - stringBufferPtr = GlobalLock(hMem); - - // Write the inputString as a UTF-8 bytes into the string buffer - if (!Encoding.UTF8.TryGetBytes(inputString, new Span((byte*)stringBufferPtr, inputString.Length), out int bufferWritten)) - LogWriteLine($"[InvokeProp::CopyStringToClipboard()] Loading inputString into buffer has failed! Clipboard will not be set!", LogType.Error, true); - - // Always set the null byte at the end of the buffer - ((byte*)stringBufferPtr!)![bufferWritten] = 0x00; // Write the null (terminator) byte - - // Unlock the buffer - GlobalUnlock(hMem); - - // Empty the previous Clipboard and set to the new one from this buffer. If - // the clearance is failed, then clear the buffer at "finally" block - if (!EmptyClipboard() || SetClipboardData(1, hMem) == IntPtr.Zero) - { - LogWriteLine($"[InvokeProp::CopyStringToClipboard()] Error has occurred while clearing and set clipboard buffer! Error: {Marshal.GetLastPInvokeErrorMessage()}", LogType.Error, true); - return; - } - - LogWriteLine($"[InvokeProp::CopyStringToClipboard()] Content has been set to Clipboard buffer with size: {bufferSize} bytes", LogType.Debug, true); - } - finally - { - // If the buffer is allocated (not zero), then free it. - if (hMem != IntPtr.Zero) GlobalFree(hMem); - - // Close the buffer if the clipboard is successfully opened. - if (isOpenClipboardSuccess) CloseClipboard(); - } - } - - public static IntPtr GetProcessWindowHandle(string ProcName) => Process.GetProcessesByName(Path.GetFileNameWithoutExtension(ProcName), ".")[0].MainWindowHandle; - - public class InvokePresence - { - IntPtr m_WindowPtr; - public InvokePresence(IntPtr windowPtr) - { - m_WindowPtr = windowPtr; - } - - public void ShowWindow() => ShowWindowAsync(m_WindowPtr, (int)HandleEnum.SW_SHOWNORMAL); - public void ShowWindowMaximized() => ShowWindowAsync(m_WindowPtr, (int)HandleEnum.SW_SHOWMAXIMIZED); - public void HideWindow() => ShowWindowAsync(m_WindowPtr, (int)HandleEnum.SW_SHOWMINIMIZED); - } - - public delegate bool HandlerRoutine(uint dwCtrlType); - - public static Process[] GetInstanceProcesses() - { - var currentProcess = Process.GetCurrentProcess(); - var processes = Process.GetProcessesByName(currentProcess.ProcessName); - - return processes; - } - - public static int EnumerateInstances() - { - var instanceProc = GetInstanceProcesses(); - var instanceCount = instanceProc.Length; - - var finalInstanceCount = 0; - - if (instanceCount > 1) - { - var curPId = Process.GetCurrentProcess().Id; - LogWriteLine($"Detected {instanceCount} instances! Current PID: {curPId}", LogType.Default, true); - LogWriteLine($"Enumerating instances..."); - foreach (Process p in instanceProc) - { - if (p == null) continue; - try - { - if (p.MainWindowHandle == IntPtr.Zero) - { - LogWriteLine("Process does not have window, skipping...", LogType.NoTag, true); - continue; - } - - LogWriteLine($"Name: {p.ProcessName}", LogType.NoTag, true); - LogWriteLine($"MainModule: {p.MainModule?.FileName}", LogType.NoTag, true); - LogWriteLine($"PID: {p.Id}", LogType.NoTag, true); - - finalInstanceCount++; - } - catch (Exception ex) - { - SentryHelper.SentryHelper.ExceptionHandler(ex, SentryHelper.SentryHelper.ExceptionType.UnhandledOther); - LogWriteLine($"Failed when trying to fetch an instance information! " + - $"InstanceCount is not incremented.\r\n{ex}", - LogType.Error, true); - } - } - - LogWriteLine($"Multiple instances found! This is instance #{finalInstanceCount}", - LogType.Scheme, true); - } - else finalInstanceCount = 1; - - return finalInstanceCount; - } - - #region dwmapi - public struct MARGINS - { - public int cxLeftWidth; - public int cxRightWidth; - public int cyTopHeight; - public int cyBottomHeight; - } - - [DllImport("dwmapi.dll", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern uint DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset); - #endregion - - #region uxtheme - [DllImport("uxtheme.dll", EntryPoint = "#132", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return:MarshalAs(UnmanagedType.I1)] - public static extern bool ShouldAppsUseDarkMode(); - - // Note: Can only use "Default" and "AllowDark" to support Windows 10 1809 - [DllImport("uxtheme.dll", EntryPoint = "#135", ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern PreferredAppMode SetPreferredAppMode(PreferredAppMode preferredAppMode); - #endregion - } -} diff --git a/Hi3Helper.Core/Classes/Data/ScreenData.cs b/Hi3Helper.Core/Classes/Data/ScreenData.cs deleted file mode 100644 index e845762a5..000000000 --- a/Hi3Helper.Core/Classes/Data/ScreenData.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.Collections.Generic; -using System.Drawing; -using static Hi3Helper.InvokeProp; - -namespace Hi3Helper.Screen -{ - public class ScreenProp : ScreenInterop - { - internal protected static DEVMODE devMode; - public static List screenResolutions; - public static Size currentResolution { get => GetScreenSize(); } - public static void InitScreenResolution() - { - devMode = new DEVMODE(); - screenResolutions = new List(); - - for (int i = 0; EnumDisplaySettings(null, i, ref devMode); i++) - { - if (screenResolutions.Count == 0) - screenResolutions.Add(new Size { Width = (int)devMode.dmPelsWidth, Height = (int)devMode.dmPelsHeight }); - else if (!(screenResolutions[^1].Width == devMode.dmPelsWidth && screenResolutions[^1].Height == devMode.dmPelsHeight)) - screenResolutions.Add(new Size { Width = (int)devMode.dmPelsWidth, Height = (int)devMode.dmPelsHeight }); - } - - // Some corner case - if (screenResolutions.Count == 0) - { - screenResolutions.Add(GetScreenSize()); - } - } - - public static Size GetScreenSize() => new Size - { - Width = GetSystemMetrics(SystemMetric.SM_CXSCREEN), - Height = GetSystemMetrics(SystemMetric.SM_CYSCREEN) - }; - - public static int GetMaxHeight() - { - devMode = new DEVMODE(); - int maxHeight = 0; - - for (int i = 0; EnumDisplaySettings(null, i, ref devMode); i++) - { - if (devMode.dmPelsHeight > maxHeight) maxHeight = (int)devMode.dmPelsHeight; - } - - return maxHeight; - } - } -} diff --git a/Hi3Helper.Core/Classes/Data/ScreenInterop.cs b/Hi3Helper.Core/Classes/Data/ScreenInterop.cs deleted file mode 100644 index 9b95792bd..000000000 --- a/Hi3Helper.Core/Classes/Data/ScreenInterop.cs +++ /dev/null @@ -1,184 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Hi3Helper.Screen -{ - public class ScreenInterop - { - // Reference: - // http://www.codeproject.com/KB/dotnet/changing-display-settings.aspx - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public struct DEVMODE - { - // You can define the following constant - // but OUTSIDE the structure because you know - // that size and layout of the structure is very important - // CCHDEVICENAME = 32 = 0x50 - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] - public string dmDeviceName; - // In addition you can define the last character array - // as following: - //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - //public Char[] dmDeviceName; - - // After the 32-bytes array - [MarshalAs(UnmanagedType.U2)] - public ushort dmSpecVersion; - - [MarshalAs(UnmanagedType.U2)] - public ushort dmDriverVersion; - - [MarshalAs(UnmanagedType.U2)] - public ushort dmSize; - - [MarshalAs(UnmanagedType.U2)] - public ushort dmDriverExtra; - - [MarshalAs(UnmanagedType.U4)] - public uint dmFields; - - public POINTL dmPosition; - - [MarshalAs(UnmanagedType.U4)] - public uint dmDisplayOrientation; - - [MarshalAs(UnmanagedType.U4)] - public uint dmDisplayFixedOutput; - - [MarshalAs(UnmanagedType.I2)] - public short dmColor; - - [MarshalAs(UnmanagedType.I2)] - public short dmDuplex; - - [MarshalAs(UnmanagedType.I2)] - public short dmYResolution; - - [MarshalAs(UnmanagedType.I2)] - public short dmTTOption; - - [MarshalAs(UnmanagedType.I2)] - public short dmCollate; - - // CCHDEVICENAME = 32 = 0x50 - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] - public string dmFormName; - // Also can be defined as - //[MarshalAs(UnmanagedType.ByValArray, - // SizeConst = 32, ArraySubType = UnmanagedType.U1)] - //public Byte[] dmFormName; - - [MarshalAs(UnmanagedType.U2)] - public ushort dmLogPixels; - - [MarshalAs(UnmanagedType.U4)] - public uint dmBitsPerPel; - - [MarshalAs(UnmanagedType.U4)] - public uint dmPelsWidth; - - [MarshalAs(UnmanagedType.U4)] - public uint dmPelsHeight; - - [MarshalAs(UnmanagedType.U4)] - public uint dmDisplayFlags; - - [MarshalAs(UnmanagedType.U4)] - public uint dmDisplayFrequency; - - [MarshalAs(UnmanagedType.U4)] - public uint dmICMMethod; - - [MarshalAs(UnmanagedType.U4)] - public uint dmICMIntent; - - [MarshalAs(UnmanagedType.U4)] - public uint dmMediaType; - - [MarshalAs(UnmanagedType.U4)] - public uint dmDitherType; - - [MarshalAs(UnmanagedType.U4)] - public uint dmReserved1; - - [MarshalAs(UnmanagedType.U4)] - public uint dmReserved2; - - [MarshalAs(UnmanagedType.U4)] - public uint dmPanningWidth; - - [MarshalAs(UnmanagedType.U4)] - public uint dmPanningHeight; - - /// - /// Initializes the structure variables. - /// - public void Initialize() - { - dmDeviceName = new string(new char[32]); - dmFormName = new string(new char[32]); - dmSize = (ushort)Marshal.SizeOf(this); - } - } - - // 8-bytes structure - [StructLayout(LayoutKind.Sequential)] - public struct POINTL - { - public int x; - public int y; - } - - [DllImport("User32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool EnumDisplaySettings( - [param: MarshalAs(UnmanagedType.LPTStr)] - string lpszDeviceName, // display device - [param: MarshalAs(UnmanagedType.U4)] - int iModeNum, // graphics mode - [In, Out] - ref DEVMODE lpDevMode // graphics mode settings - ); - - public const int ENUM_CURRENT_SETTINGS = -1; - public const int DMDO_DEFAULT = 0; - public const int DMDO_90 = 1; - public const int DMDO_180 = 2; - public const int DMDO_270 = 3; - - - [DllImport("User32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] - [return: MarshalAs(UnmanagedType.I4)] - public static extern int ChangeDisplaySettings( - [In, Out] - ref DEVMODE lpDevMode, - [param: MarshalAs(UnmanagedType.U4)] - uint dwflags); - - - - [DllImport("kernel32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern uint FormatMessage( - [param: MarshalAs(UnmanagedType.U4)] - uint dwFlags, - [param: MarshalAs(UnmanagedType.U4)] - uint lpSource, - [param: MarshalAs(UnmanagedType.U4)] - uint dwMessageId, - [param: MarshalAs(UnmanagedType.U4)] - uint dwLanguageId, - [param: MarshalAs(UnmanagedType.LPTStr)] - out string lpBuffer, - [param: MarshalAs(UnmanagedType.U4)] - uint nSize, - [param: MarshalAs(UnmanagedType.U4)] - uint Arguments); - - public const uint FORMAT_MESSAGE_FROM_HMODULE = 0x800; - - public const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x100; - public const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x200; - public const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x1000; - public const uint FORMAT_MESSAGE_FLAGS = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM; - } -} \ No newline at end of file diff --git a/CollapseLauncher/Classes/Helper/ILoggerHelper.cs b/Hi3Helper.Core/Classes/Logger/ILoggerHelper.cs similarity index 78% rename from CollapseLauncher/Classes/Helper/ILoggerHelper.cs rename to Hi3Helper.Core/Classes/Logger/ILoggerHelper.cs index 68081b990..b5d70401f 100644 --- a/CollapseLauncher/Classes/Helper/ILoggerHelper.cs +++ b/Hi3Helper.Core/Classes/Logger/ILoggerHelper.cs @@ -1,21 +1,17 @@ -#if USEVELOPACK -using Hi3Helper; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using System; -namespace CollapseLauncher.Helper +namespace Hi3Helper { #nullable enable - internal static class ILoggerHelper + public static class ILoggerHelper { private static ILogger? Logger; - internal static ILogger CreateCollapseILogger() => Logger ??= new CollapseILoggerWrapper(); + public static ILogger GetILogger() => Logger ??= new ILoggerWrapper(); } - public class CollapseILoggerWrapper : ILogger + internal class ILoggerWrapper : ILogger { - internal CollapseILoggerWrapper() { } - public IDisposable BeginScope(TState state) where TState : notnull => default!; @@ -47,5 +43,4 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except Logger.LogWriteLine(message, logType, isWriteToLog); } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/Hi3Helper.Core/Classes/Logger/LoggerBase.cs b/Hi3Helper.Core/Classes/Logger/LoggerBase.cs index 3f7e5ac02..569275dec 100644 --- a/Hi3Helper.Core/Classes/Logger/LoggerBase.cs +++ b/Hi3Helper.Core/Classes/Logger/LoggerBase.cs @@ -3,6 +3,7 @@ using System.Text; #if !APPLYUPDATE using Hi3Helper.Shared.Region; +using Hi3Helper.Win32.Native; // ReSharper disable CheckNamespace #endif @@ -244,7 +245,7 @@ private void InitializeWriter(bool isFallback, Encoding logEncoding) _isWriterOnDispose = false; } - private int GetTotalInstance() => InvokeProp.EnumerateInstances(); + private int GetTotalInstance() => PInvoke.EnumerateInstances(ILoggerHelper.GetILogger()); #endif private ArgumentException ThrowInvalidType() => new ArgumentException("Type must be Default, Error, Warning, Scheme, Game, Debug, GLC, Remote or Empty!"); diff --git a/Hi3Helper.Core/Classes/Logger/Type/LoggerConsole.cs b/Hi3Helper.Core/Classes/Logger/Type/LoggerConsole.cs index cb65fd722..80c3e5cb9 100644 --- a/Hi3Helper.Core/Classes/Logger/Type/LoggerConsole.cs +++ b/Hi3Helper.Core/Classes/Logger/Type/LoggerConsole.cs @@ -1,8 +1,8 @@ -using System; +using Hi3Helper.Win32.Native; +using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text; -using static Hi3Helper.InvokeProp; #if !APPLYUPDATE using static Hi3Helper.Shared.Region.LauncherConfig; #endif @@ -87,8 +87,8 @@ public static void DisposeConsole() { if (ConsoleHandle != IntPtr.Zero) { - IntPtr consoleWindow = GetConsoleWindow(); - ShowWindow(consoleWindow, 0); + IntPtr consoleWindow = PInvoke.GetConsoleWindow(); + PInvoke.ShowWindow(consoleWindow, 0); } } @@ -96,12 +96,12 @@ public static void AllocateConsole() { if (ConsoleHandle != IntPtr.Zero) { - IntPtr consoleWindow = GetConsoleWindow(); - ShowWindow(consoleWindow, 5); + IntPtr consoleWindow = PInvoke.GetConsoleWindow(); + PInvoke.ShowWindow(consoleWindow, 5); return; } - if (!AllocConsole()) + if (!PInvoke.AllocConsole()) { throw new ContextMarshalException($"Failed to allocate console with error code: {Marshal.GetLastPInvokeError()}"); } @@ -110,33 +110,33 @@ public static void AllocateConsole() const uint GENERIC_WRITE = 0x40000000; const uint FILE_SHARE_WRITE = 2; const uint OPEN_EXISTING = 3; - ConsoleHandle = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); + ConsoleHandle = PInvoke.CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); const int STD_OUTPUT_HANDLE = -11; - SetStdHandle(STD_OUTPUT_HANDLE, ConsoleHandle); + PInvoke.SetStdHandle(STD_OUTPUT_HANDLE, ConsoleHandle); Console.OutputEncoding = Encoding.UTF8; var instanceIndicator = ""; - var instanceCount = EnumerateInstances(); + var instanceCount = PInvoke.EnumerateInstances(ILoggerHelper.GetILogger()); if (instanceCount > 1) instanceIndicator = $" - #{instanceCount}"; Console.Title = $"Collapse Console{instanceIndicator}"; - if (GetConsoleMode(ConsoleHandle, out uint mode)) + if (PInvoke.GetConsoleMode(ConsoleHandle, out uint mode)) { const uint ENABLE_PROCESSED_OUTPUT = 1; const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4; const uint DISABLE_NEWLINE_AUTO_RETURN = 8; mode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN; - if (SetConsoleMode(ConsoleHandle, mode)) + if (PInvoke.SetConsoleMode(ConsoleHandle, mode)) { _virtualTerminal = true; } } #if !APPLYUPDATE - SetWindowIcon(GetConsoleWindow(), AppIconLarge, AppIconSmall); + PInvoke.SetWindowIcon(PInvoke.GetConsoleWindow(), AppIconLarge, AppIconSmall); #endif } #endregion diff --git a/Hi3Helper.Core/Classes/Shared/Region/LauncherConfig.cs b/Hi3Helper.Core/Classes/Shared/Region/LauncherConfig.cs index 90bcb346e..4e327d758 100644 --- a/Hi3Helper.Core/Classes/Shared/Region/LauncherConfig.cs +++ b/Hi3Helper.Core/Classes/Shared/Region/LauncherConfig.cs @@ -1,6 +1,6 @@ using Hi3Helper.Data; -using Hi3Helper.Screen; using Hi3Helper.Shared.ClassStruct; +using Hi3Helper.Win32.Screen; using System; using System.Collections.Generic; using System.Diagnostics; @@ -28,10 +28,10 @@ public struct CDNURLProperty : IEquatable public static class LauncherConfig { #region Main Launcher Config Methods - public static void InitAppPreset() + public static void InitAppPreset(ScreenProp screenProp) { // Initialize resolution settings first and assign AppConfigFile to ProfilePath - InitScreenResSettings(); + InitScreenResSettings(screenProp); appIni.ProfilePath = AppConfigFile; // Set user permission check to its default and check for the existence of config file. @@ -113,9 +113,9 @@ public static void CheckAndSetDefaultConfigValue() #region Misc Methods public static void LoadGamePreset() => AppGameFolder = Path.Combine(GetAppConfigValue("GameFolder").ToString()!); - public static void GetScreenResolutionString() + public static void GetScreenResolutionString(ScreenProp screenProp) { - foreach (var res in ScreenProp.screenResolutions!) + foreach (var res in screenProp.ScreenResolutions!) ScreenResolutionsList!.Add($"{res.Width}x{res.Height}"); } @@ -124,10 +124,9 @@ private static bool IsDriveExist(string path) return new DriveInfo(Path.GetPathRoot(path)!).IsReady; } - private static void InitScreenResSettings() + private static void InitScreenResSettings(ScreenProp screenProp) { - ScreenProp.InitScreenResolution(); - GetScreenResolutionString(); + GetScreenResolutionString(screenProp); } #endregion diff --git a/Hi3Helper.Core/Hi3Helper.Core.csproj b/Hi3Helper.Core/Hi3Helper.Core.csproj index 1d73a5782..738a4200f 100644 --- a/Hi3Helper.Core/Hi3Helper.Core.csproj +++ b/Hi3Helper.Core/Hi3Helper.Core.csproj @@ -1,4 +1,4 @@ - + net9.0-windows10.0.22621.0 @@ -48,6 +48,7 @@ + diff --git a/Hi3Helper.Core/packages.lock.json b/Hi3Helper.Core/packages.lock.json index 11fc01336..2e304f8e5 100644 --- a/Hi3Helper.Core/packages.lock.json +++ b/Hi3Helper.Core/packages.lock.json @@ -25,6 +25,19 @@ "resolved": "3.28.3", "contentHash": "OewySX3aQCdKfMJsj2DzBMXQJPI+lm0CBzamU9ViFu3CU9tXYrQWqJ1CZ+/UWtkwOjUeIzbXmoOjRc7B8pbMrA==" }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "+6f2qv2a3dLwd5w6JanPIPs47CxRbnk+ZocMJUhv9NxP88VlOcJYZs9jY+MYSjxvady08bUZn6qgiNh7DadGgg==" + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "g0UfujELzlLbHoVG8kPKVBaW470Ewi+jnptGS9KUi6jcb+k2StujtK3m26DFSGGwQ/+bVgZfsWqNzlP6YOejvw==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0" + } + }, "System.IO.Hashing": { "type": "Transitive", "resolved": "9.0.0", @@ -35,11 +48,18 @@ "dependencies": { "Google.Protobuf": "[3.28.3, )", "Hi3Helper.Http": "[2.0.0, )", + "Hi3Helper.Win32": "[1.0.0, )", "System.IO.Hashing": "[9.0.0, )" } }, "hi3helper.http": { "type": "Project" + }, + "hi3helper.win32": { + "type": "Project", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "[9.0.0, )" + } } } } diff --git a/Hi3Helper.EncTool b/Hi3Helper.EncTool index 6dc4c191a..4688fa97d 160000 --- a/Hi3Helper.EncTool +++ b/Hi3Helper.EncTool @@ -1 +1 @@ -Subproject commit 6dc4c191a46719d2a03fed399194bc8976225126 +Subproject commit 4688fa97d8b3260ce4ae0395049daf9d7723ebcf diff --git a/Hi3Helper.TaskScheduler/Hi3Helper.TaskScheduler.csproj b/Hi3Helper.TaskScheduler/Hi3Helper.TaskScheduler.csproj index e17e80e85..d3d98e871 100644 --- a/Hi3Helper.TaskScheduler/Hi3Helper.TaskScheduler.csproj +++ b/Hi3Helper.TaskScheduler/Hi3Helper.TaskScheduler.csproj @@ -23,11 +23,11 @@ all - runtime; build; native; contentfiles; analyzers; buildtransitive + runtime; build; native; contentfiles; analyzers; buildtransitive; compile all - runtime; build; native; contentfiles; analyzers; buildtransitive + runtime; build; native; contentfiles; analyzers; buildtransitive; compile diff --git a/Hi3Helper.Win32 b/Hi3Helper.Win32 new file mode 160000 index 000000000..1f62137df --- /dev/null +++ b/Hi3Helper.Win32 @@ -0,0 +1 @@ +Subproject commit 1f62137df58f42edebca928972ea3314f25a9f0f diff --git a/ImageEx b/ImageEx index bca25959f..0b4d7d392 160000 --- a/ImageEx +++ b/ImageEx @@ -1 +1 @@ -Subproject commit bca25959fbe0035d001f9c905075e450962e4b72 +Subproject commit 0b4d7d39258b2e18e208b3747a9d9a42253f6ee1 diff --git a/SevenZipExtractor b/SevenZipExtractor index bad142e16..9591ba583 160000 --- a/SevenZipExtractor +++ b/SevenZipExtractor @@ -1 +1 @@ -Subproject commit bad142e16d01b3b73bba77c03e2de1c7e23b2632 +Subproject commit 9591ba583794256d440c4f5bd3d5631fa63c23f5