|
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 | | -using System.Runtime.InteropServices; |
4 | | -using Windows.Storage.Provider; |
5 | 6 | using Windows.Win32; |
6 | 7 | using Windows.Win32.Foundation; |
| 8 | +using Windows.Win32.System.Com; |
| 9 | +using Windows.Win32.System.WinRT; |
7 | 10 | using WinRT; |
8 | 11 |
|
9 | 12 | namespace Files.App.Utils.Storage |
10 | 13 | { |
11 | 14 | internal static class SyncRootHelpers |
12 | 15 | { |
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 |
43 | | - { |
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 | | - } |
69 | | - |
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 | | - } |
90 | | - |
91 | 16 | private static unsafe (bool Success, ulong Capacity, ulong Used) GetSyncRootQuotaFromSyncRootId(string syncRootId) |
92 | 17 | { |
93 | | - RegistryKey? key; |
94 | | - if ((key = Registry.LocalMachine.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SyncRootManager\\{syncRootId}")) is null) |
95 | | - { |
| 18 | + using var key = Registry.LocalMachine.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SyncRootManager\\{syncRootId}"); |
| 19 | + if (key?.GetValue("StorageProviderStatusUISourceFactory") is not string factoryClsidString || |
| 20 | + !Guid.TryParse(factoryClsidString, out var factoryClsid)) |
96 | 21 | return (false, 0, 0); |
97 | | - } |
98 | 22 |
|
99 | | - using (key) |
100 | | - { |
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 | | - } |
| 23 | + HRESULT hr = default; |
| 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; |
111 | 29 |
|
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())); |
| 30 | + if (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()).ThrowIfFailedOnDebug().Failed) |
| 36 | + return (false, 0, 0); |
117 | 37 |
|
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 | | - { |
| 38 | + var syncRootIdHString = new MarshalString.Pinnable(syncRootId); |
| 39 | + fixed (char* pSyncRootIdHString = syncRootIdHString) |
| 40 | + { |
| 41 | + if (pStorageProviderStatusUISourceFactory.Get()->GetStatusUISource(syncRootIdHString.GetAbi(), pStorageProviderStatusUISource.GetAddressOf()).ThrowIfFailedOnDebug().Failed || |
| 42 | + pStorageProviderStatusUISource.Get()->GetStatusUI(pStorageProviderStatusUI.GetAddressOf()).ThrowIfFailedOnDebug().Failed || |
| 43 | + pStorageProviderStatusUI.Get()->GetQuotaUI(pStorageProviderQuotaUI.GetAddressOf()).ThrowIfFailedOnDebug().Failed || |
| 44 | + pStorageProviderQuotaUI.Get()->GetQuotaTotalInBytes(&ulTotalSize).ThrowIfFailedOnDebug().Failed || |
| 45 | + pStorageProviderQuotaUI.Get()->GetQuotaUsedInBytes(&ulUsedSize).ThrowIfFailedOnDebug().Failed) |
129 | 46 | return (false, 0, 0); |
130 | | - } |
131 | 47 | } |
| 48 | + |
| 49 | + return (true, ulTotalSize, ulUsedSize); |
132 | 50 | } |
133 | 51 |
|
134 | 52 | public static async Task<(bool Success, ulong Capacity, ulong Used)> GetSyncRootQuotaAsync(string path) |
135 | 53 | { |
136 | 54 | Windows.Storage.StorageFolder folder = await Windows.Storage.StorageFolder.GetFolderFromPathAsync(path); |
137 | | - StorageProviderSyncRootInfo? syncRootInfo = null; |
| 55 | + Windows.Storage.Provider.StorageProviderSyncRootInfo? syncRootInfo = null; |
138 | 56 |
|
139 | 57 | try |
140 | 58 | { |
141 | | - syncRootInfo = StorageProviderSyncRootManager.GetSyncRootInformationForFolder(folder); |
| 59 | + syncRootInfo = Windows.Storage.Provider.StorageProviderSyncRootManager.GetSyncRootInformationForFolder(folder); |
142 | 60 | } |
143 | 61 | catch |
144 | 62 | { |
|
0 commit comments