|
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