|
1 |
| -using Microsoft.Win32; |
| 1 | +// Copyright (c) Files Community |
| 2 | +// Licensed under the MIT License. |
| 3 | + |
| 4 | +using Microsoft.Win32; |
2 | 5 | using System.Runtime.CompilerServices;
|
3 | 6 | using System.Runtime.InteropServices;
|
4 |
| -using Windows.Storage.Provider; |
5 | 7 | using Windows.Win32;
|
6 | 8 | using Windows.Win32.Foundation;
|
| 9 | +using Windows.Win32.System.Com; |
| 10 | +using Windows.Win32.System.WinRT; |
7 | 11 | using WinRT;
|
8 | 12 |
|
9 | 13 | namespace Files.App.Utils.Storage
|
10 | 14 | {
|
11 | 15 | internal static class SyncRootHelpers
|
12 | 16 | {
|
13 |
| - private unsafe struct IStorageProviderStatusUISourceFactory : IComIID |
14 |
| - { |
15 |
| - private void** vtbl; |
16 |
| - |
17 |
| - [MethodImpl(MethodImplOptions.AggressiveInlining)] |
18 |
| - public HRESULT GetStatusUISource(nint syncRootId, IStorageProviderStatusUISource** result) |
19 |
| - { |
20 |
| - return ((delegate* unmanaged[Stdcall]<IStorageProviderStatusUISourceFactory*, nint, IStorageProviderStatusUISource**, HRESULT>)vtbl[6])((IStorageProviderStatusUISourceFactory*)Unsafe.AsPointer(ref this), syncRootId, result); |
21 |
| - } |
22 |
| - |
23 |
| - public static ref readonly Guid Guid |
24 |
| - { |
25 |
| - get |
26 |
| - { |
27 |
| - // 12e46b74-4e5a-58d1-a62f-0376e8ee7dd8 |
28 |
| - ReadOnlySpan<byte> data = new byte[] |
29 |
| - { |
30 |
| - 0x74, 0x6b, 0xe4, 0x12, |
31 |
| - 0x5a, 0x4e, |
32 |
| - 0xd1, 0x58, |
33 |
| - 0xa6, 0x2f, |
34 |
| - 0x03, 0x76, 0xe8, 0xee, 0x7d, 0xd8 |
35 |
| - }; |
36 |
| - Debug.Assert(data.Length == sizeof(Guid)); |
37 |
| - return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data)); |
38 |
| - } |
39 |
| - } |
40 |
| - } |
41 |
| - |
42 |
| - private unsafe struct IStorageProviderStatusUISource : IComIID |
| 17 | + private static unsafe (bool Success, ulong Capacity, ulong Used) GetSyncRootQuotaFromSyncRootId(string syncRootId) |
43 | 18 | {
|
44 |
| - private void** vtbl; |
45 |
| - |
46 |
| - public HRESULT GetStatusUI(IStorageProviderStatusUI** result) |
47 |
| - { |
48 |
| - return ((delegate* unmanaged[Stdcall]<IStorageProviderStatusUISource*, IStorageProviderStatusUI**, HRESULT>)vtbl[6])((IStorageProviderStatusUISource*)Unsafe.AsPointer(ref this), result); |
49 |
| - } |
50 |
| - |
51 |
| - public static ref readonly Guid Guid |
52 |
| - { |
53 |
| - get |
54 |
| - { |
55 |
| - // a306c249-3d66-5e70-9007-e43df96051ff |
56 |
| - ReadOnlySpan<byte> data = new byte[] |
57 |
| - { |
58 |
| - 0x49, 0xc2, 0x06, 0xa3, |
59 |
| - 0x66, 0x3d, |
60 |
| - 0x70, 0x5e, |
61 |
| - 0x90, 0x07, |
62 |
| - 0xe4, 0x3d, 0xf9, 0x60, 0x51, 0xff |
63 |
| - }; |
64 |
| - Debug.Assert(data.Length == sizeof(Guid)); |
65 |
| - return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data)); |
66 |
| - } |
67 |
| - } |
68 |
| - } |
| 19 | + using var key = Registry.LocalMachine.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SyncRootManager\\{syncRootId}"); |
| 20 | + if (key?.GetValue("StorageProviderStatusUISourceFactory") is not string factoryClsidString || |
| 21 | + !Guid.TryParse(factoryClsidString, out var factoryClsid)) |
| 22 | + return (false, 0, 0); |
69 | 23 |
|
70 |
| - private unsafe struct IStorageProviderStatusUI : IComIID |
71 |
| - { |
72 |
| - public static ref readonly Guid Guid |
73 |
| - { |
74 |
| - get |
75 |
| - { |
76 |
| - // d6b6a758-198d-5b80-977f-5ff73da33118 |
77 |
| - ReadOnlySpan<byte> data = new byte[] |
78 |
| - { |
79 |
| - 0x58, 0xa7, 0xb6, 0xd6, |
80 |
| - 0x8d, 0x19, |
81 |
| - 0x80, 0x5b, |
82 |
| - 0x97, 0x7f, |
83 |
| - 0x5f, 0xf7, 0x3d, 0xa3, 0x31, 0x18 |
84 |
| - }; |
85 |
| - Debug.Assert(data.Length == sizeof(Guid)); |
86 |
| - return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data)); |
87 |
| - } |
88 |
| - } |
89 |
| - } |
| 24 | + ulong ulTotalSize = 0ul, ulUsedSize = 0ul; |
| 25 | + using ComPtr<IStorageProviderStatusUISourceFactory> pStorageProviderStatusUISourceFactory = default; |
| 26 | + using ComPtr<IStorageProviderStatusUISource> pStorageProviderStatusUISource = default; |
| 27 | + using ComPtr<IStorageProviderStatusUI> pStorageProviderStatusUI = default; |
| 28 | + using ComPtr<IStorageProviderQuotaUI> pStorageProviderQuotaUI = default; |
90 | 29 |
|
91 |
| - private static unsafe (bool Success, ulong Capacity, ulong Used) GetSyncRootQuotaFromSyncRootId(string syncRootId) |
92 |
| - { |
93 |
| - RegistryKey? key; |
94 |
| - if ((key = Registry.LocalMachine.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SyncRootManager\\{syncRootId}")) is null) |
95 |
| - { |
| 30 | + var hr = PInvoke.CoCreateInstance( |
| 31 | + &factoryClsid, |
| 32 | + null, |
| 33 | + CLSCTX.CLSCTX_LOCAL_SERVER, |
| 34 | + (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IStorageProviderStatusUISourceFactory.Guid)), |
| 35 | + (void**)pStorageProviderStatusUISourceFactory.GetAddressOf()).ThrowOnFailure(); |
| 36 | + if (hr.Failed) |
96 | 37 | return (false, 0, 0);
|
97 |
| - } |
98 | 38 |
|
99 |
| - using (key) |
| 39 | + var syncRootIdHString = new MarshalString.Pinnable(syncRootId); |
| 40 | + fixed (char* pSyncRootIdHString = syncRootIdHString) |
100 | 41 | {
|
101 |
| - if (key.GetValue("StorageProviderStatusUISourceFactory") is string statusUIclass) |
102 |
| - { |
103 |
| - StorageProviderStatusUI statusUI; |
104 |
| - using (ComPtr<IStorageProviderStatusUISourceFactory> sourceFactoryNative = default) |
105 |
| - { |
106 |
| - Guid statusUIclassGuid = Guid.Parse(statusUIclass); |
107 |
| - 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) |
108 |
| - { |
109 |
| - return (false, 0, 0); |
110 |
| - } |
111 |
| - |
112 |
| - MarshalString.Pinnable syncRootIdHstring = new(syncRootId); |
113 |
| - fixed (char* ptr = syncRootIdHstring) |
114 |
| - using (ComPtr<IStorageProviderStatusUISource> sourceNative = default) |
115 |
| - { |
116 |
| - ExceptionHelpers.ThrowExceptionForHR(sourceFactoryNative.Get()->GetStatusUISource(syncRootIdHstring.GetAbi(), sourceNative.GetAddressOf())); |
| 42 | + hr = pStorageProviderStatusUISourceFactory.Get()->GetStatusUISource(syncRootIdHString.GetAbi(), pStorageProviderStatusUISource.GetAddressOf()).ThrowOnFailure(); |
| 43 | + hr = pStorageProviderStatusUISource.Get()->GetStatusUI(pStorageProviderStatusUI.GetAddressOf()).ThrowOnFailure(); |
| 44 | + hr = pStorageProviderStatusUI.Get()->GetQuotaUI((nint*)pStorageProviderQuotaUI.GetAddressOf()).ThrowOnFailure(); |
117 | 45 |
|
118 |
| - using (ComPtr<IStorageProviderStatusUI> statusNative = default) |
119 |
| - { |
120 |
| - ExceptionHelpers.ThrowExceptionForHR(sourceNative.Get()->GetStatusUI(statusNative.GetAddressOf())); |
121 |
| - statusUI = StorageProviderStatusUI.FromAbi((nint)statusNative.Get()); |
122 |
| - } |
123 |
| - } |
124 |
| - } |
125 |
| - return (true, statusUI.QuotaUI.QuotaTotalInBytes, statusUI.QuotaUI.QuotaUsedInBytes); |
126 |
| - } |
127 |
| - else |
128 |
| - { |
129 |
| - return (false, 0, 0); |
130 |
| - } |
| 46 | + hr = pStorageProviderQuotaUI.Get()->GetQuotaTotalInBytes(&ulTotalSize); |
| 47 | + hr = pStorageProviderQuotaUI.Get()->GetQuotaUsedInBytes(&ulUsedSize); |
131 | 48 | }
|
| 49 | + |
| 50 | + return (true, ulTotalSize, ulUsedSize); |
132 | 51 | }
|
133 | 52 |
|
134 | 53 | public static async Task<(bool Success, ulong Capacity, ulong Used)> GetSyncRootQuotaAsync(string path)
|
135 | 54 | {
|
136 | 55 | Windows.Storage.StorageFolder folder = await Windows.Storage.StorageFolder.GetFolderFromPathAsync(path);
|
137 |
| - StorageProviderSyncRootInfo? syncRootInfo = null; |
| 56 | + Windows.Storage.Provider.StorageProviderSyncRootInfo? syncRootInfo = null; |
138 | 57 |
|
139 | 58 | try
|
140 | 59 | {
|
141 |
| - syncRootInfo = StorageProviderSyncRootManager.GetSyncRootInformationForFolder(folder); |
| 60 | + syncRootInfo = Windows.Storage.Provider.StorageProviderSyncRootManager.GetSyncRootInformationForFolder(folder); |
142 | 61 | }
|
143 | 62 | catch
|
144 | 63 | {
|
|
0 commit comments