22// Licensed under the MIT License.
33
44using DiscUtils . Udf ;
5+ using Files . App . Services . SizeProvider ;
56using Microsoft . Management . Infrastructure ;
7+ using Microsoft . Win32 ;
8+ using System . Runtime . InteropServices ;
69using Windows . Devices . Enumeration ;
710using Windows . Devices . Portable ;
811using Windows . Storage ;
912using Windows . Storage . FileProperties ;
13+ using Windows . Storage . Provider ;
1014using Windows . Win32 ;
1115using Windows . Win32 . Foundation ;
16+ using WinRT ;
1217
1318namespace Files . App . Utils . Storage
1419{
1520 public static class DriveHelpers
1621 {
22+ private static readonly Guid IID_IStorageProviderStatusUISourceFactory = new Guid ( "12e46b74-4e5a-58d1-a62f-0376e8ee7dd8" ) ;
23+
1724 public static async void EjectDeviceAsync ( string path )
1825 {
1926 await ContextMenu . InvokeVerb ( "eject" , path ) ;
@@ -168,5 +175,60 @@ public static async Task<StorageItemThumbnail> GetThumbnailAsync(StorageFolder f
168175 => ( StorageItemThumbnail ) await FilesystemTasks . Wrap ( ( )
169176 => folder . GetThumbnailAsync ( ThumbnailMode . SingleItem , 40 , ThumbnailOptions . UseCurrentScale ) . AsTask ( )
170177 ) ;
178+
179+ public static async Task < ( bool Success , ulong Capacity , ulong Used ) > GetSyncRootQuotaAsync ( string path )
180+ {
181+ Windows . Storage . StorageFolder folder = await Windows . Storage . StorageFolder . GetFolderFromPathAsync ( path ) ;
182+ StorageProviderSyncRootInfo ? syncRootInfo = null ;
183+
184+ try
185+ {
186+ syncRootInfo = StorageProviderSyncRootManager . GetSyncRootInformationForFolder ( folder ) ;
187+ }
188+ catch
189+ {
190+ return ( false , 0 , 0 ) ;
191+ }
192+
193+ RegistryKey ? key ;
194+ if ( ( key = Registry . LocalMachine . OpenSubKey ( $ "SOFTWARE\\ Microsoft\\ Windows\\ CurrentVersion\\ Explorer\\ SyncRootManager\\ { syncRootInfo . Id } ") ) is null )
195+ {
196+ return ( false , 0 , 0 ) ;
197+ }
198+
199+ using ( key )
200+ {
201+ if ( key . GetValue ( "StorageProviderStatusUISourceFactory" ) is string statusUIclass )
202+ {
203+ StorageProviderStatusUI statusUI ;
204+
205+ unsafe
206+ {
207+ if ( PInvoke . CoCreateInstance ( Guid . Parse ( statusUIclass ) , null , Windows . Win32 . System . Com . CLSCTX . CLSCTX_LOCAL_SERVER , IID_IStorageProviderStatusUISourceFactory , out void * statusUISourceFactoryAbi ) != 0 )
208+ {
209+ return ( false , 0 , 0 ) ;
210+ }
211+
212+ // CsWinRT wrappers won't work.
213+ // TODO: look to replace MarshalString with MarshalString.Pinnable?
214+
215+ nint statusUISourceAbi = 0 ;
216+ nint syncRootIdHstring = MarshalString . FromManaged ( syncRootInfo . Id ) ;
217+ nint statusUIAbi = 0 ;
218+ ExceptionHelpers . ThrowExceptionForHR ( ( ( delegate * unmanaged[ MemberFunction ] < IntPtr , IntPtr , IntPtr * , int > ) ( * ( IntPtr * ) ( ( nint ) ( * ( IntPtr * ) statusUISourceFactoryAbi ) + ( nint ) 6 * ( nint ) sizeof ( delegate * unmanaged[ Stdcall] < IntPtr , IntPtr , IntPtr * , int > ) ) ) ) ( ( nint ) statusUISourceFactoryAbi , syncRootIdHstring , & statusUISourceAbi ) ) ;
219+ ExceptionHelpers. ThrowExceptionForHR ( ( ( delegate * unmanaged[ MemberFunction ] < nint , nint * , int > ) ( * ( IntPtr * ) ( ( nint ) ( * ( IntPtr * ) statusUISourceAbi ) + ( nint ) 6 * ( nint ) sizeof ( delegate * unmanaged[ Stdcall] < nint , nint * , int > ) ) ) ) ( statusUISourceAbi , & statusUIAbi ) ) ;
220+ statusUI = StorageProviderStatusUI. FromAbi ( statusUIAbi ) ;
221+ Marshal. Release ( statusUISourceAbi ) ;
222+ Marshal. Release ( ( nint ) statusUISourceFactoryAbi ) ;
223+ MarshalString. DisposeAbi ( statusUISourceAbi ) ;
224+ }
225+ return ( true , statusUI . QuotaUI . QuotaTotalInBytes , statusUI . QuotaUI . QuotaUsedInBytes ) ;
226+ }
227+ else
228+ {
229+ return ( false , 0 , 0 ) ;
230+ }
231+ }
232+ }
171233 }
172234}
0 commit comments