diff --git a/src/Files.App.CsWin32/Windows.Win32.ComHeapPtr.cs b/src/Files.App.CsWin32/ComHeapPtr`1.cs similarity index 100% rename from src/Files.App.CsWin32/Windows.Win32.ComHeapPtr.cs rename to src/Files.App.CsWin32/ComHeapPtr`1.cs diff --git a/src/Files.App.CsWin32/Windows.Win32.ComPtr.cs b/src/Files.App.CsWin32/ComPtr`1.cs similarity index 100% rename from src/Files.App.CsWin32/Windows.Win32.ComPtr.cs rename to src/Files.App.CsWin32/ComPtr`1.cs diff --git a/src/Files.App.CsWin32/Windows.Win32.Extras.cs b/src/Files.App.CsWin32/Extras.cs similarity index 100% rename from src/Files.App.CsWin32/Windows.Win32.Extras.cs rename to src/Files.App.CsWin32/Extras.cs diff --git a/src/Files.App.CsWin32/HRESULT.Extensions.cs b/src/Files.App.CsWin32/HRESULT.Extensions.cs new file mode 100644 index 000000000000..8d8315526d71 --- /dev/null +++ b/src/Files.App.CsWin32/HRESULT.Extensions.cs @@ -0,0 +1,26 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +using System.Runtime.InteropServices; +using Windows.Win32.Foundation; + +namespace Windows.Win32 +{ + public static class HRESULTExtensions + { + /// + /// Throws an exception if the indicates a failure in debug mode. Otherwise, it returns the original . + /// + /// Represents the result of an operation, indicating success or failure. + /// Returns the original value regardless of the operation's success. + public static HRESULT ThrowIfFailedOnDebug(this HRESULT hr) + { +#if DEBUG + if (hr.Failed) + Marshal.ThrowExceptionForHR(hr.Value); +#endif + + return hr; + } + } +} diff --git a/src/Files.App.CsWin32/IStorageProviderQuotaUI.cs b/src/Files.App.CsWin32/IStorageProviderQuotaUI.cs new file mode 100644 index 000000000000..3e28cfcabded --- /dev/null +++ b/src/Files.App.CsWin32/IStorageProviderQuotaUI.cs @@ -0,0 +1,47 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Windows.Win32.Foundation; + +namespace Windows.Win32.System.WinRT +{ + public unsafe struct IStorageProviderQuotaUI : IComIID + { + private void** lpVtbl; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HRESULT GetQuotaTotalInBytes(ulong* value) + { + return ((delegate* unmanaged[Stdcall])(lpVtbl[6]))((IStorageProviderQuotaUI*)Unsafe.AsPointer(ref this), value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HRESULT GetQuotaUsedInBytes(ulong* value) + { + return ((delegate* unmanaged[Stdcall])(lpVtbl[8]))((IStorageProviderQuotaUI*)Unsafe.AsPointer(ref this), value); + } + + public static ref readonly Guid Guid + { + get + { + // BA6295C3-312E-544F-9FD5-1F81B21F3649 + ReadOnlySpan data = + [ + 0xC3, 0x95, 0x62, 0xBA, + 0x2E, 0x31, + 0x4F, 0x54, + 0x9F, 0xD5, + 0x1F, 0x81, 0xB2, 0x1F, 0x36, 0x49 + ]; + + Debug.Assert(data.Length == sizeof(Guid)); + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + } +} diff --git a/src/Files.App.CsWin32/IStorageProviderStatusUI.cs b/src/Files.App.CsWin32/IStorageProviderStatusUI.cs new file mode 100644 index 000000000000..ab7bdcc050d4 --- /dev/null +++ b/src/Files.App.CsWin32/IStorageProviderStatusUI.cs @@ -0,0 +1,41 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Windows.Win32.Foundation; + +namespace Windows.Win32.System.WinRT +{ + public unsafe struct IStorageProviderStatusUI : IComIID + { + private void** lpVtbl; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HRESULT GetQuotaUI(IStorageProviderQuotaUI** result) + { + return ((delegate* unmanaged[Stdcall])lpVtbl[14])((IStorageProviderStatusUI*)Unsafe.AsPointer(ref this), result); + } + + public static ref readonly Guid Guid + { + get + { + // d6b6a758-198d-5b80-977f-5ff73da33118 + ReadOnlySpan data = + [ + 0x58, 0xa7, 0xb6, 0xd6, + 0x8d, 0x19, + 0x80, 0x5b, + 0x97, 0x7f, + 0x5f, 0xf7, 0x3d, 0xa3, 0x31, 0x18 + ]; + + Debug.Assert(data.Length == sizeof(Guid)); + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + } +} diff --git a/src/Files.App.CsWin32/IStorageProviderStatusUISource.cs b/src/Files.App.CsWin32/IStorageProviderStatusUISource.cs new file mode 100644 index 000000000000..b7d80b4efb8f --- /dev/null +++ b/src/Files.App.CsWin32/IStorageProviderStatusUISource.cs @@ -0,0 +1,41 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Windows.Win32.Foundation; + +namespace Windows.Win32.System.WinRT +{ + public unsafe struct IStorageProviderStatusUISource : IComIID + { + private void** lpVtbl; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HRESULT GetStatusUI(IStorageProviderStatusUI** result) + { + return ((delegate* unmanaged[Stdcall])lpVtbl[6])((IStorageProviderStatusUISource*)Unsafe.AsPointer(ref this), result); + } + + public static ref readonly Guid Guid + { + get + { + // A306C249-3D66-5E70-9007-E43DF96051FF + ReadOnlySpan data = + [ + 0x49, 0xc2, 0x06, 0xa3, + 0x66, 0x3d, + 0x70, 0x5e, + 0x90, 0x07, + 0xe4, 0x3d, 0xf9, 0x60, 0x51, 0xff + ]; + + Debug.Assert(data.Length == sizeof(Guid)); + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + } +} diff --git a/src/Files.App.CsWin32/IStorageProviderStatusUISourceFactory.cs b/src/Files.App.CsWin32/IStorageProviderStatusUISourceFactory.cs new file mode 100644 index 000000000000..4927fa32577e --- /dev/null +++ b/src/Files.App.CsWin32/IStorageProviderStatusUISourceFactory.cs @@ -0,0 +1,41 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Windows.Win32.Foundation; + +namespace Windows.Win32.System.WinRT +{ + public unsafe struct IStorageProviderStatusUISourceFactory : IComIID + { + private void** lpVtbl; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HRESULT GetStatusUISource(nint syncRootId, IStorageProviderStatusUISource** result) + { + return ((delegate* unmanaged[Stdcall])lpVtbl[6])((IStorageProviderStatusUISourceFactory*)Unsafe.AsPointer(ref this), syncRootId, result); + } + + public static ref readonly Guid Guid + { + get + { + // 12E46B74-4E5A-58D1-A62F-0376E8EE7DD8 + ReadOnlySpan data = + [ + 0x74, 0x6b, 0xe4, 0x12, + 0x5a, 0x4e, + 0xd1, 0x58, + 0xa6, 0x2f, + 0x03, 0x76, 0xe8, 0xee, 0x7d, 0xd8 + ]; + + Debug.Assert(data.Length == sizeof(Guid)); + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + } +} diff --git a/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs b/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs index 16b17c2b5ca3..e013316b9b34 100644 --- a/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs +++ b/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs @@ -1,144 +1,62 @@ -using Microsoft.Win32; +// Copyright (c) Files Community +// Licensed under the MIT License. + +using Microsoft.Win32; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Windows.Storage.Provider; using Windows.Win32; using Windows.Win32.Foundation; +using Windows.Win32.System.Com; +using Windows.Win32.System.WinRT; using WinRT; namespace Files.App.Utils.Storage { internal static class SyncRootHelpers { - private unsafe struct IStorageProviderStatusUISourceFactory : IComIID - { - private void** vtbl; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public HRESULT GetStatusUISource(nint syncRootId, IStorageProviderStatusUISource** result) - { - return ((delegate* unmanaged[Stdcall])vtbl[6])((IStorageProviderStatusUISourceFactory*)Unsafe.AsPointer(ref this), syncRootId, result); - } - - public static ref readonly Guid Guid - { - get - { - // 12e46b74-4e5a-58d1-a62f-0376e8ee7dd8 - ReadOnlySpan data = new byte[] - { - 0x74, 0x6b, 0xe4, 0x12, - 0x5a, 0x4e, - 0xd1, 0x58, - 0xa6, 0x2f, - 0x03, 0x76, 0xe8, 0xee, 0x7d, 0xd8 - }; - Debug.Assert(data.Length == sizeof(Guid)); - return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); - } - } - } - - private unsafe struct IStorageProviderStatusUISource : IComIID - { - private void** vtbl; - - public HRESULT GetStatusUI(IStorageProviderStatusUI** result) - { - return ((delegate* unmanaged[Stdcall])vtbl[6])((IStorageProviderStatusUISource*)Unsafe.AsPointer(ref this), result); - } - - public static ref readonly Guid Guid - { - get - { - // a306c249-3d66-5e70-9007-e43df96051ff - ReadOnlySpan data = new byte[] - { - 0x49, 0xc2, 0x06, 0xa3, - 0x66, 0x3d, - 0x70, 0x5e, - 0x90, 0x07, - 0xe4, 0x3d, 0xf9, 0x60, 0x51, 0xff - }; - Debug.Assert(data.Length == sizeof(Guid)); - return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); - } - } - } - - private unsafe struct IStorageProviderStatusUI : IComIID - { - public static ref readonly Guid Guid - { - get - { - // d6b6a758-198d-5b80-977f-5ff73da33118 - ReadOnlySpan data = new byte[] - { - 0x58, 0xa7, 0xb6, 0xd6, - 0x8d, 0x19, - 0x80, 0x5b, - 0x97, 0x7f, - 0x5f, 0xf7, 0x3d, 0xa3, 0x31, 0x18 - }; - Debug.Assert(data.Length == sizeof(Guid)); - return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); - } - } - } - private static unsafe (bool Success, ulong Capacity, ulong Used) GetSyncRootQuotaFromSyncRootId(string syncRootId) { - RegistryKey? key; - if ((key = Registry.LocalMachine.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SyncRootManager\\{syncRootId}")) is null) - { + using var key = Registry.LocalMachine.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SyncRootManager\\{syncRootId}"); + if (key?.GetValue("StorageProviderStatusUISourceFactory") is not string factoryClsidString || + !Guid.TryParse(factoryClsidString, out var factoryClsid)) return (false, 0, 0); - } - using (key) - { - if (key.GetValue("StorageProviderStatusUISourceFactory") is string statusUIclass) - { - StorageProviderStatusUI statusUI; - using (ComPtr sourceFactoryNative = default) - { - Guid statusUIclassGuid = Guid.Parse(statusUIclass); - if (PInvoke.CoCreateInstance(&statusUIclassGuid, null, Windows.Win32.System.Com.CLSCTX.CLSCTX_LOCAL_SERVER, (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IStorageProviderStatusUISourceFactory.Guid)), (void**)sourceFactoryNative.GetAddressOf()) != 0) - { - return (false, 0, 0); - } + HRESULT hr = default; + ulong ulTotalSize = 0ul, ulUsedSize = 0ul; + using ComPtr pStorageProviderStatusUISourceFactory = default; + using ComPtr pStorageProviderStatusUISource = default; + using ComPtr pStorageProviderStatusUI = default; + using ComPtr pStorageProviderQuotaUI = default; - MarshalString.Pinnable syncRootIdHstring = new(syncRootId); - fixed (char* ptr = syncRootIdHstring) - using (ComPtr sourceNative = default) - { - ExceptionHelpers.ThrowExceptionForHR(sourceFactoryNative.Get()->GetStatusUISource(syncRootIdHstring.GetAbi(), sourceNative.GetAddressOf())); + if (PInvoke.CoCreateInstance( + &factoryClsid, + null, + CLSCTX.CLSCTX_LOCAL_SERVER, + (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IStorageProviderStatusUISourceFactory.Guid)), + (void**)pStorageProviderStatusUISourceFactory.GetAddressOf()).ThrowIfFailedOnDebug().Failed) + return (false, 0, 0); - using (ComPtr statusNative = default) - { - ExceptionHelpers.ThrowExceptionForHR(sourceNative.Get()->GetStatusUI(statusNative.GetAddressOf())); - statusUI = StorageProviderStatusUI.FromAbi((nint)statusNative.Get()); - } - } - } - return (true, statusUI.QuotaUI.QuotaTotalInBytes, statusUI.QuotaUI.QuotaUsedInBytes); - } - else - { + var syncRootIdHString = new MarshalString.Pinnable(syncRootId); + fixed (char* pSyncRootIdHString = syncRootIdHString) + { + if (pStorageProviderStatusUISourceFactory.Get()->GetStatusUISource(syncRootIdHString.GetAbi(), pStorageProviderStatusUISource.GetAddressOf()).ThrowIfFailedOnDebug().Failed || + pStorageProviderStatusUISource.Get()->GetStatusUI(pStorageProviderStatusUI.GetAddressOf()).ThrowIfFailedOnDebug().Failed || + pStorageProviderStatusUI.Get()->GetQuotaUI(pStorageProviderQuotaUI.GetAddressOf()).ThrowIfFailedOnDebug().Failed || + pStorageProviderQuotaUI.Get()->GetQuotaTotalInBytes(&ulTotalSize).ThrowIfFailedOnDebug().Failed || + pStorageProviderQuotaUI.Get()->GetQuotaUsedInBytes(&ulUsedSize).ThrowIfFailedOnDebug().Failed) return (false, 0, 0); - } } + + return (true, ulTotalSize, ulUsedSize); } public static async Task<(bool Success, ulong Capacity, ulong Used)> GetSyncRootQuotaAsync(string path) { Windows.Storage.StorageFolder folder = await Windows.Storage.StorageFolder.GetFolderFromPathAsync(path); - StorageProviderSyncRootInfo? syncRootInfo = null; + Windows.Storage.Provider.StorageProviderSyncRootInfo? syncRootInfo = null; try { - syncRootInfo = StorageProviderSyncRootManager.GetSyncRootInformationForFolder(folder); + syncRootInfo = Windows.Storage.Provider.StorageProviderSyncRootManager.GetSyncRootInformationForFolder(folder); } catch {