diff --git a/src/Files.App.CsWin32/ComPtr`1.cs b/src/Files.App.CsWin32/ComPtr`1.cs deleted file mode 100644 index 2cceed532893..000000000000 --- a/src/Files.App.CsWin32/ComPtr`1.cs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) Files Community -// Licensed under the MIT License. - -using System; -using System.Runtime.CompilerServices; -using Windows.Win32.Foundation; -using Windows.Win32.System.Com; - -namespace Windows.Win32 -{ - /// - /// Contains a COM pointer and a set of methods to work with the pointer safely. - /// - public unsafe struct ComPtr : IDisposable where T : unmanaged, IComIID - { - private T* _ptr; - - public readonly bool IsNull - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _ptr is null; - } - - // Constructors - - public ComPtr(T* ptr) - { - _ptr = ptr; - - if (ptr is not null) - ((IUnknown*)ptr)->AddRef(); - } - - // Methods - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Attach(T* other) - { - if (_ptr is not null) - ((IUnknown*)_ptr)->Release(); - - _ptr = other; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public T* Detach() - { - T* ptr = _ptr; - _ptr = null; - return ptr; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly T* Get() - { - return _ptr; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly T** GetAddressOf() - { - return (T**)Unsafe.AsPointer(ref Unsafe.AsRef(in this)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly HRESULT As(U** other) where U : unmanaged, IComIID - { - return ((IUnknown*)_ptr)->QueryInterface((Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in U.Guid)), (void**)other); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly HRESULT As(Guid* riid, IUnknown** other) where U : unmanaged, IComIID - { - return ((IUnknown*)_ptr)->QueryInterface(riid, (void**)other); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly HRESULT CoCreateInstance(Guid* rclsid, IUnknown* pUnkOuter = null, CLSCTX dwClsContext = CLSCTX.CLSCTX_LOCAL_SERVER) - { - return PInvoke.CoCreateInstance(rclsid, pUnkOuter, dwClsContext, (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in T.Guid)), (void**)this.GetAddressOf()); - } - - // Disposer - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dispose() - { - T* ptr = _ptr; - if (ptr is not null) - { - _ptr = null; - ((IUnknown*)ptr)->Release(); - } - } - } -} diff --git a/src/Files.App.CsWin32/Extras.cs b/src/Files.App.CsWin32/Extras.cs index 99fd57262dba..396aa7a1997e 100644 --- a/src/Files.App.CsWin32/Extras.cs +++ b/src/Files.App.CsWin32/Extras.cs @@ -11,13 +11,13 @@ namespace Windows.Win32 namespace Graphics.Gdi { [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public unsafe delegate BOOL MONITORENUMPROC([In] HMONITOR param0, [In] HDC param1, [In][Out] RECT* param2, [In] LPARAM param3); + public unsafe delegate BOOL MonitorEnumProcDelegate([In] HMONITOR param0, [In] HDC param1, [In][Out] RECT* param2, [In] LPARAM param3); } namespace UI.WindowsAndMessaging { [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate LRESULT WNDPROC(HWND hWnd, uint msg, WPARAM wParam, LPARAM lParam); + public delegate LRESULT WndProcDelegate(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam); } public static partial class PInvoke diff --git a/src/Files.App.CsWin32/Files.App.CsWin32.csproj b/src/Files.App.CsWin32/Files.App.CsWin32.csproj index d3a5a5198de2..6533328aacb0 100644 --- a/src/Files.App.CsWin32/Files.App.CsWin32.csproj +++ b/src/Files.App.CsWin32/Files.App.CsWin32.csproj @@ -11,6 +11,7 @@ win-x86;win-x64;win-arm64 true true + true diff --git a/src/Files.App.CsWin32/IStorageProviderQuotaUI.cs b/src/Files.App.CsWin32/IStorageProviderQuotaUI.cs index c7cd816b77fc..98d07bdd2c65 100644 --- a/src/Files.App.CsWin32/IStorageProviderQuotaUI.cs +++ b/src/Files.App.CsWin32/IStorageProviderQuotaUI.cs @@ -1,21 +1,44 @@ // Copyright (c) Files Community // Licensed under the MIT License. -using Files.Shared.Attributes; using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; using Windows.Win32.Foundation; namespace Windows.Win32.System.WinRT { - public unsafe partial struct IStorageProviderQuotaUI : IComIID + [GeneratedComInterface, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("BA6295C3-312E-544F-9FD5-1F81B21F3649")] + public partial interface IStorageProviderQuotaUI { - [GeneratedVTableFunction(Index = 6)] - public partial HRESULT GetQuotaTotalInBytes(ulong* value); + // Slot: 3 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetIids(out uint iidCount, out nint iids); - [GeneratedVTableFunction(Index = 8)] - public partial HRESULT GetQuotaUsedInBytes(ulong* value); + // Slot: 4 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetRuntimeClassName(out HSTRING className); - [GuidRVAGen.Guid("BA6295C3-312E-544F-9FD5-1F81B21F3649")] - public static partial ref readonly Guid Guid { get; } + // Slot: 5 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetTrustLevel(out TrustLevel trustLevel); + + // Slot: 6 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT get_QuotaTotalInBytes(out ulong value); + + // Slot: 7 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT put_QuotaTotalInBytes(ulong value); + + // Slot: 8 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT get_QuotaUsedInBytes(out ulong value); } } diff --git a/src/Files.App.CsWin32/IStorageProviderStatusUI.cs b/src/Files.App.CsWin32/IStorageProviderStatusUI.cs index 3aa60c4255f9..1bb40406bfcc 100644 --- a/src/Files.App.CsWin32/IStorageProviderStatusUI.cs +++ b/src/Files.App.CsWin32/IStorageProviderStatusUI.cs @@ -1,18 +1,75 @@ // Copyright (c) Files Community // Licensed under the MIT License. -using Files.Shared.Attributes; using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Windows.Storage.Provider; using Windows.Win32.Foundation; namespace Windows.Win32.System.WinRT { - public unsafe partial struct IStorageProviderStatusUI : IComIID + [GeneratedComInterface, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("D6B6A758-198D-5B80-977F-5FF73DA33118")] + public partial interface IStorageProviderStatusUI { - [GeneratedVTableFunction(Index = 14)] - public partial HRESULT GetQuotaUI(IStorageProviderQuotaUI** result); + // Slot: 3 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetIids(out uint iidCount, out nint iids); - [GuidRVAGen.Guid("D6B6A758-198D-5B80-977F-5FF73DA33118")] - public static partial ref readonly Guid Guid { get; } + // Slot: 4 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetRuntimeClassName(out HSTRING className); + + // Slot: 5 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetTrustLevel(out TrustLevel trustLevel); + + // Slot: 6 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT get_ProviderState(out StorageProviderState value); + + // Slot: 7 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT put_ProviderState(StorageProviderState value); + + // Slot: 8 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT get_ProviderStateLabel(out HSTRING value); + + // Slot: 9 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT put_ProviderStateLabel(HSTRING value); + + // Slot: 10 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT get_ProviderStateIcon([MarshalAs(UnmanagedType.Interface)] out object /*IUriRuntimeClass*/ value); + + // Slot: 11 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT put_ProviderStateIcon([MarshalAs(UnmanagedType.Interface)] object /*IUriRuntimeClass*/ value); + + // Slot: 12 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT get_SyncStatusCommand([MarshalAs(UnmanagedType.Interface)] out IStorageProviderUICommand value); + + // Slot: 13 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT put_SyncStatusCommand([MarshalAs(UnmanagedType.Interface)] IStorageProviderUICommand value); + + // Slot: 14 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT get_QuotaUI([MarshalAs(UnmanagedType.Interface)] out IStorageProviderQuotaUI value); } } diff --git a/src/Files.App.CsWin32/IStorageProviderStatusUISource.cs b/src/Files.App.CsWin32/IStorageProviderStatusUISource.cs index 9f4ede28194f..064fffa9d06e 100644 --- a/src/Files.App.CsWin32/IStorageProviderStatusUISource.cs +++ b/src/Files.App.CsWin32/IStorageProviderStatusUISource.cs @@ -3,16 +3,33 @@ using Files.Shared.Attributes; using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; using Windows.Win32.Foundation; namespace Windows.Win32.System.WinRT { - public unsafe partial struct IStorageProviderStatusUISource : IComIID + [GeneratedComInterface, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("A306C249-3D66-5E70-9007-E43DF96051FF")] + public partial interface IStorageProviderStatusUISource { - [GeneratedVTableFunction(Index = 6)] - public partial HRESULT GetStatusUI(IStorageProviderStatusUI** result); + // Slot: 3 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetIids(out uint iidCount, out nint iids); - [GuidRVAGen.Guid("A306C249-3D66-5E70-9007-E43DF96051FF")] - public static partial ref readonly Guid Guid { get; } + // Slot: 4 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetRuntimeClassName(out HSTRING className); + + // Slot: 5 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetTrustLevel(out TrustLevel trustLevel); + + // Slot: 6 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetStatusUI([MarshalAs(UnmanagedType.Interface)] out IStorageProviderStatusUI value); } } diff --git a/src/Files.App.CsWin32/IStorageProviderStatusUISourceFactory.cs b/src/Files.App.CsWin32/IStorageProviderStatusUISourceFactory.cs index 4065c1800c10..016b375d1180 100644 --- a/src/Files.App.CsWin32/IStorageProviderStatusUISourceFactory.cs +++ b/src/Files.App.CsWin32/IStorageProviderStatusUISourceFactory.cs @@ -1,18 +1,34 @@ // Copyright (c) Files Community // Licensed under the MIT License. -using Files.Shared.Attributes; using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; using Windows.Win32.Foundation; namespace Windows.Win32.System.WinRT { - public unsafe partial struct IStorageProviderStatusUISourceFactory : IComIID + [GeneratedComInterface, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("12E46B74-4E5A-58D1-A62F-0376E8EE7DD8")] + public partial interface IStorageProviderStatusUISourceFactory { - [GeneratedVTableFunction(Index = 6)] - public partial HRESULT GetStatusUISource(nint syncRootId, IStorageProviderStatusUISource** result); + // Slot: 3 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetIids(out uint iidCount, out nint iids); - [GuidRVAGen.Guid("12E46B74-4E5A-58D1-A62F-0376E8EE7DD8")] - public static partial ref readonly Guid Guid { get; } + // Slot: 4 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetRuntimeClassName(out HSTRING className); + + // Slot: 5 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetTrustLevel(out TrustLevel trustLevel); + + // Slot: 6 + [PreserveSig] + [return: MarshalAs(UnmanagedType.Error)] + HRESULT GetStatusUISource([MarshalAs(UnmanagedType.LPWStr)] string syncRootId, [MarshalAs(UnmanagedType.Interface)] out IStorageProviderStatusUISource result); } } diff --git a/src/Files.App.CsWin32/ManualGuid.cs b/src/Files.App.CsWin32/ManualGuid.cs index f95973c45048..64cad9b16cae 100644 --- a/src/Files.App.CsWin32/ManualGuid.cs +++ b/src/Files.App.CsWin32/ManualGuid.cs @@ -9,9 +9,6 @@ namespace Windows.Win32 { public static unsafe partial class IID { - public static Guid* IID_IStorageProviderStatusUISourceFactory - => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IStorageProviderStatusUISourceFactory.Guid)); - [GuidRVAGen.Guid("000214E4-0000-0000-C000-000000000046")] public static partial Guid* IID_IContextMenu { get; } diff --git a/src/Files.App.CsWin32/NativeMethods.json b/src/Files.App.CsWin32/NativeMethods.json index 2e32fa443533..af32e10fa478 100644 --- a/src/Files.App.CsWin32/NativeMethods.json +++ b/src/Files.App.CsWin32/NativeMethods.json @@ -1,8 +1,8 @@ { "$schema": "https://aka.ms/CsWin32.schema.json", - "allowMarshaling": false, "public": true, "comInterop": { + "useComSourceGenerators": true, "preserveSigMethods": [ "*" ] diff --git a/src/Files.App.CsWin32/NativeMethods.txt b/src/Files.App.CsWin32/NativeMethods.txt index 9f10fdd3870b..f2af324c371f 100644 --- a/src/Files.App.CsWin32/NativeMethods.txt +++ b/src/Files.App.CsWin32/NativeMethods.txt @@ -1,6 +1,7 @@ // Copyright (c) Files Community // Licensed under the MIT License. +IActivationFactory WNDPROC WNDCLASSEXW RegisterClassEx @@ -125,6 +126,7 @@ SHQUERYRBINFO SHQueryRecycleBin FileOperation IFileOperation +IFileOperationProgressSink IShellItem2 PSGetPropertyKeyFromName ShellExecuteEx diff --git a/src/Files.App.Server/Helpers.cs b/src/Files.App.Server/Helpers.cs index 8ab3253540d5..f35a00f69afa 100644 --- a/src/Files.App.Server/Helpers.cs +++ b/src/Files.App.Server/Helpers.cs @@ -12,7 +12,7 @@ namespace Files.App.Server; unsafe partial class Helpers { [UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])] - public static HRESULT GetActivationFactory(HSTRING activatableClassId, IActivationFactory** factory) + public static HRESULT GetActivationFactory(HSTRING activatableClassId, IActivationFactory_unmanaged** factory) { if (activatableClassId.IsNull || factory is null) { @@ -21,7 +21,7 @@ public static HRESULT GetActivationFactory(HSTRING activatableClassId, IActivati try { - *factory = (IActivationFactory*)Module.GetActivationFactory(MarshalString.FromAbi((IntPtr)activatableClassId)); + *factory = (IActivationFactory_unmanaged*)Module.GetActivationFactory(MarshalString.FromAbi((IntPtr)activatableClassId)); return *factory is null ? HRESULT.CLASS_E_CLASSNOTAVAILABLE : HRESULT.S_OK; } catch (Exception e) diff --git a/src/Files.App.Server/Program.cs b/src/Files.App.Server/Program.cs index b00061eaba85..ab497e73e5e7 100644 --- a/src/Files.App.Server/Program.cs +++ b/src/Files.App.Server/Program.cs @@ -42,13 +42,13 @@ static async Task Main() unsafe { - delegate* unmanaged[Stdcall][] callbacks = new delegate* unmanaged[Stdcall][classIds.Length]; + delegate* unmanaged[Stdcall][] callbacks = new delegate* unmanaged[Stdcall][classIds.Length]; for (int i = 0; i < callbacks.Length; i++) { callbacks[i] = &Helpers.GetActivationFactory; } - fixed (delegate* unmanaged[Stdcall]* pCallbacks = callbacks) + fixed (delegate* unmanaged[Stdcall]* pCallbacks = callbacks) { if (PInvoke.RoRegisterActivationFactories(classIds, pCallbacks, out cookie) is HRESULT hr && hr.Value != 0) { diff --git a/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Icon.cs b/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Icon.cs index 01df95e5a916..2646b63be59f 100644 --- a/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Icon.cs +++ b/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Icon.cs @@ -44,14 +44,13 @@ public unsafe static HRESULT TryGetThumbnail(this IWindowsStorable storable, int { thumbnailData = null; - using ComPtr pShellItemImageFactory = default; - storable.ThisPtr->QueryInterface(IID.IID_IShellItemImageFactory, (void**)pShellItemImageFactory.GetAddressOf()); - if (pShellItemImageFactory.IsNull) + var shellItemImageFactory = (IShellItemImageFactory)storable.ThisPtr; + if (shellItemImageFactory is null) return HRESULT.E_NOINTERFACE; // Get HBITMAP HBITMAP hBitmap = default; - HRESULT hr = pShellItemImageFactory.Get()->GetImage(new(size, size), options, &hBitmap); + HRESULT hr = shellItemImageFactory.GetImage(new(size, size), options, &hBitmap); if (hr.ThrowIfFailedOnDebug().Failed) { if (!hBitmap.IsNull) PInvoke.DeleteObject(hBitmap); @@ -168,22 +167,21 @@ public unsafe static bool TryConvertGpBitmapToByteArray(GpBitmap* gpBitmap, out encoder = GetEncoderClsid(format); } - using ComPtr pStream = default; - HRESULT hr = PInvoke.CreateStreamOnHGlobal(HGLOBAL.Null, true, pStream.GetAddressOf()); + HRESULT hr = PInvoke.CreateStreamOnHGlobal(HGLOBAL.Null, true, out var stream); if (hr.ThrowIfFailedOnDebug().Failed) { if (gpBitmap is not null) PInvoke.GdipDisposeImage((GpImage*)gpBitmap); return false; } - if (PInvoke.GdipSaveImageToStream((GpImage*)gpBitmap, pStream.Get(), &encoder, (EncoderParameters*)null) is not Status.Ok) + if (PInvoke.GdipSaveImageToStream((GpImage*)gpBitmap, stream, &encoder, (EncoderParameters*)null) is not Status.Ok) { if (gpBitmap is not null) PInvoke.GdipDisposeImage((GpImage*)gpBitmap); return false; } STATSTG stat = default; - hr = pStream.Get()->Stat(&stat, (uint)STATFLAG.STATFLAG_NONAME); + hr = stream.Stat(&stat, STATFLAG.STATFLAG_NONAME); if (hr.ThrowIfFailedOnDebug().Failed) { if (gpBitmap is not null) PInvoke.GdipDisposeImage((GpImage*)gpBitmap); @@ -193,8 +191,8 @@ public unsafe static bool TryConvertGpBitmapToByteArray(GpBitmap* gpBitmap, out ulong statSize = stat.cbSize & 0xFFFFFFFF; byte* RawThumbnailData = (byte*)NativeMemory.Alloc((nuint)statSize); - pStream.Get()->Seek(0L, (SystemIO.SeekOrigin)STREAM_SEEK.STREAM_SEEK_SET, null); - hr = pStream.Get()->Read(RawThumbnailData, (uint)statSize); + stream.Seek(0L, (SystemIO.SeekOrigin)STREAM_SEEK.STREAM_SEEK_SET, null); + hr = stream.Read(RawThumbnailData, (uint)statSize); if (hr.ThrowIfFailedOnDebug().Failed) { if (gpBitmap is not null) PInvoke.GdipDisposeImage((GpImage*)gpBitmap); @@ -266,14 +264,12 @@ public unsafe static HRESULT TrySetShortcutIcon(this IWindowsStorable storable, if (iconFile.ToString() is not { } iconFilePath) return HRESULT.E_INVALIDARG; - using ComPtr pShellLink = default; - - HRESULT hr = storable.ThisPtr->BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IShellLinkW, (void**)pShellLink.GetAddressOf()); + HRESULT hr = storable.ThisPtr.BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IShellLinkW, out var shellLinkObj); + var shellLink = (IShellLinkW)shellLinkObj; if (hr.ThrowIfFailedOnDebug().Failed) return hr; - fixed (char* pszIconFilePath = iconFilePath) - hr = pShellLink.Get()->SetIconLocation(iconFilePath, index); + hr = shellLink.SetIconLocation(iconFilePath, index); if (hr.ThrowIfFailedOnDebug().Failed) return hr; diff --git a/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Shell.cs b/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Shell.cs index 41eb10877af7..f80f3b33c242 100644 --- a/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Shell.cs +++ b/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Shell.cs @@ -19,8 +19,8 @@ public unsafe static partial class WindowsStorableHelpers { public static HRESULT GetPropertyValue(this IWindowsStorable storable, string propKey, out TValue value) { - using ComPtr pShellItem2 = default; - HRESULT hr = storable.ThisPtr->QueryInterface(IID.IID_IShellItem2, (void**)pShellItem2.GetAddressOf()); + HRESULT hr = default; + var shellItem2 = (IShellItem2)storable.ThisPtr; PROPERTYKEY propertyKey = default; fixed (char* pszPropertyKey = propKey) @@ -29,7 +29,7 @@ public static HRESULT GetPropertyValue(this IWindowsStorable storable, s if (typeof(TValue) == typeof(string)) { ComHeapPtr szPropertyValue = default; - hr = pShellItem2.Get()->GetString(&propertyKey, szPropertyValue.Get()); + hr = shellItem2.GetString(&propertyKey, szPropertyValue.Get()); value = (TValue)(object)szPropertyValue.Get()->ToString(); return hr; @@ -37,7 +37,7 @@ public static HRESULT GetPropertyValue(this IWindowsStorable storable, s if (typeof(TValue) == typeof(bool)) { bool fPropertyValue = false; - hr = pShellItem2.Get()->GetBool(&propertyKey, (BOOL*)&fPropertyValue); + hr = shellItem2.GetBool(&propertyKey, (BOOL*)&fPropertyValue); value = Unsafe.As(ref fPropertyValue); return hr; @@ -51,13 +51,13 @@ public static HRESULT GetPropertyValue(this IWindowsStorable storable, s public static bool HasShellAttributes(this IWindowsStorable storable, SFGAO_FLAGS attributes) { - return storable.ThisPtr->GetAttributes(attributes, out var dwRetAttributes).Succeeded && dwRetAttributes == attributes; + return storable.ThisPtr.GetAttributes(attributes, out var dwRetAttributes).Succeeded && dwRetAttributes == attributes; } public static string GetDisplayName(this IWindowsStorable storable, SIGDN options = SIGDN.SIGDN_FILESYSPATH) { using ComHeapPtr pszName = default; - HRESULT hr = storable.ThisPtr->GetDisplayName(options, (PWSTR*)pszName.GetAddressOf()); + HRESULT hr = storable.ThisPtr.GetDisplayName(options, (PWSTR*)pszName.GetAddressOf()); return hr.ThrowIfFailedOnDebug().Succeeded ? new string((char*)pszName.Get()) // this is safe as it gets memcpy'd internally @@ -68,10 +68,10 @@ public static HRESULT TryInvokeContextMenuVerb(this IWindowsStorable storable, s { Debug.Assert(Thread.CurrentThread.GetApartmentState() is ApartmentState.STA); - using ComPtr pContextMenu = default; - HRESULT hr = storable.ThisPtr->BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IContextMenu, (void**)pContextMenu.GetAddressOf()); + HRESULT hr = storable.ThisPtr.BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IContextMenu, out var contextMenuObj); + var contextMenu = (IContextMenu)contextMenuObj; HMENU hMenu = PInvoke.CreatePopupMenu(); - hr = pContextMenu.Get()->QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE); + hr = contextMenu.QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE); CMINVOKECOMMANDINFO cmici = default; cmici.cbSize = (uint)sizeof(CMINVOKECOMMANDINFO); @@ -80,7 +80,7 @@ public static HRESULT TryInvokeContextMenuVerb(this IWindowsStorable storable, s fixed (byte* pszVerbName = Encoding.ASCII.GetBytes(verbName)) { cmici.lpVerb = new(pszVerbName); - hr = pContextMenu.Get()->InvokeCommand(cmici); + hr = contextMenu.InvokeCommand(cmici); if (!PInvoke.DestroyMenu(hMenu)) return HRESULT.E_FAIL; @@ -93,10 +93,10 @@ public static HRESULT TryInvokeContextMenuVerbs(this IWindowsStorable storable, { Debug.Assert(Thread.CurrentThread.GetApartmentState() is ApartmentState.STA); - using ComPtr pContextMenu = default; - HRESULT hr = storable.ThisPtr->BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IContextMenu, (void**)pContextMenu.GetAddressOf()); + HRESULT hr = storable.ThisPtr.BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IContextMenu, out var contextMenuObj); + var contextMenu = (IContextMenu)contextMenuObj; HMENU hMenu = PInvoke.CreatePopupMenu(); - hr = pContextMenu.Get()->QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE); + hr = contextMenu.QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE); CMINVOKECOMMANDINFO cmici = default; cmici.cbSize = (uint)sizeof(CMINVOKECOMMANDINFO); @@ -107,7 +107,7 @@ public static HRESULT TryInvokeContextMenuVerbs(this IWindowsStorable storable, fixed (byte* pszVerbName = Encoding.ASCII.GetBytes(verbName)) { cmici.lpVerb = new(pszVerbName); - hr = pContextMenu.Get()->InvokeCommand(cmici); + hr = contextMenu.InvokeCommand(cmici); if (!PInvoke.DestroyMenu(hMenu)) return HRESULT.E_FAIL; @@ -124,12 +124,12 @@ public static HRESULT TryGetShellTooltip(this IWindowsStorable storable, out str { tooltip = null; - using ComPtr pQueryInfo = default; - HRESULT hr = storable.ThisPtr->BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IQueryInfo, (void**)pQueryInfo.GetAddressOf()); + HRESULT hr = storable.ThisPtr.BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IQueryInfo, out var queryInfoObj); + var queryInfo = (IQueryInfo)queryInfoObj; if (hr.ThrowIfFailedOnDebug().Failed) return hr; - pQueryInfo.Get()->GetInfoTip((uint)QITIPF_FLAGS.QITIPF_DEFAULT, out var pszTip); + queryInfo.GetInfoTip((uint)QITIPF_FLAGS.QITIPF_DEFAULT, out var pszTip); if (hr.ThrowIfFailedOnDebug().Failed) return hr; @@ -143,27 +143,22 @@ public static HRESULT TryPinFolderToQuickAccess(this IWindowsFolder @this) { HRESULT hr = default; - using ComPtr pExecuteCommand = default; - using ComPtr pObjectWithSelection = default; - - hr = PInvoke.CoCreateInstance(CLSID.CLSID_PinToFrequentExecute, null, CLSCTX.CLSCTX_INPROC_SERVER, IID.IID_IExecuteCommand, (void**)pExecuteCommand.GetAddressOf()); + hr = PInvoke.CoCreateInstance(*CLSID.CLSID_PinToFrequentExecute, null, CLSCTX.CLSCTX_INPROC_SERVER, out IExecuteCommand executeCommand); if (hr.ThrowIfFailedOnDebug().Failed) return hr; - using ComPtr pShellItemArray = default; - hr = PInvoke.SHCreateShellItemArrayFromShellItem(@this.ThisPtr, IID.IID_IShellItemArray, (void**)pShellItemArray.GetAddressOf()); + hr = PInvoke.SHCreateShellItemArrayFromShellItem(@this.ThisPtr, *IID.IID_IShellItemArray, out var shellItemArrayObj); + var shellItemArray = (IShellItemArray)shellItemArrayObj; if (hr.ThrowIfFailedOnDebug().Failed) return hr; - hr = pExecuteCommand.Get()->QueryInterface(IID.IID_IObjectWithSelection, (void**)pObjectWithSelection.GetAddressOf()); - if (hr.ThrowIfFailedOnDebug().Failed) - return hr; + var objectWithSelection = (IObjectWithSelection)executeCommand; - hr = pObjectWithSelection.Get()->SetSelection(pShellItemArray.Get()); + hr = objectWithSelection.SetSelection(shellItemArray); if (hr.ThrowIfFailedOnDebug().Failed) return hr; - hr = pExecuteCommand.Get()->Execute(); + hr = executeCommand.Execute(); if (hr.ThrowIfFailedOnDebug().Failed) return hr; @@ -174,27 +169,22 @@ public static HRESULT TryUnpinFolderFromQuickAccess(this IWindowsFolder @this) { HRESULT hr = default; - using ComPtr pExecuteCommand = default; - using ComPtr pObjectWithSelection = default; - - hr = PInvoke.CoCreateInstance(CLSID.CLSID_UnPinFromFrequentExecute, null, CLSCTX.CLSCTX_INPROC_SERVER, IID.IID_IExecuteCommand, (void**)pExecuteCommand.GetAddressOf()); + hr = PInvoke.CoCreateInstance(*CLSID.CLSID_UnPinFromFrequentExecute, null, CLSCTX.CLSCTX_INPROC_SERVER, out IExecuteCommand executeCommand); if (hr.ThrowIfFailedOnDebug().Failed) return hr; - using ComPtr pShellItemArray = default; - hr = PInvoke.SHCreateShellItemArrayFromShellItem(@this.ThisPtr, IID.IID_IShellItemArray, (void**)pShellItemArray.GetAddressOf()); + hr = PInvoke.SHCreateShellItemArrayFromShellItem(@this.ThisPtr, *IID.IID_IShellItemArray, out var shellItemArrayObj); + var shellItemArray = (IShellItemArray)shellItemArrayObj; if (hr.ThrowIfFailedOnDebug().Failed) return hr; - hr = pExecuteCommand.Get()->QueryInterface(IID.IID_IObjectWithSelection, (void**)pObjectWithSelection.GetAddressOf()); - if (hr.ThrowIfFailedOnDebug().Failed) - return hr; + var objectWithSelection = (IObjectWithSelection)executeCommand; - hr = pObjectWithSelection.Get()->SetSelection(pShellItemArray.Get()); + hr = objectWithSelection.SetSelection(shellItemArray); if (hr.ThrowIfFailedOnDebug().Failed) return hr; - hr = pExecuteCommand.Get()->Execute(); + hr = executeCommand.Execute(); if (hr.ThrowIfFailedOnDebug().Failed) return hr; @@ -205,52 +195,43 @@ public static IEnumerable GetShellNewItems(this IWindows { HRESULT hr = default; - IContextMenu* pNewMenu = default; - using ComPtr pShellExtInit = default; - using ComPtr pContextMenu2 = default; - - hr = PInvoke.CoCreateInstance(CLSID.CLSID_NewMenu, null, CLSCTX.CLSCTX_INPROC_SERVER, IID.IID_IContextMenu, (void**)&pNewMenu); + hr = PInvoke.CoCreateInstance(*CLSID.CLSID_NewMenu, null, CLSCTX.CLSCTX_INPROC_SERVER, out IContextMenu newMenu); if (hr.ThrowIfFailedOnDebug().Failed) return []; - hr = pNewMenu->QueryInterface(IID.IID_IContextMenu2, (void**)pContextMenu2.GetAddressOf()); - if (hr.ThrowIfFailedOnDebug().Failed) - return []; + var contextMenu2 = (IContextMenu2)newMenu; + var shellExtInit = (IShellExtInit)newMenu; - hr = pNewMenu->QueryInterface(IID.IID_IShellExtInit, (void**)pShellExtInit.GetAddressOf()); - if (hr.ThrowIfFailedOnDebug().Failed) - return []; - - @this.ShellNewMenu = pNewMenu; + @this.ShellNewMenu = newMenu; - ITEMIDLIST* pFolderPidl = default; - hr = PInvoke.SHGetIDListFromObject((IUnknown*)@this.ThisPtr, &pFolderPidl); + ITEMIDLIST* folderPidl = default; + hr = PInvoke.SHGetIDListFromObject(@this.ThisPtr, &folderPidl); if (hr.ThrowIfFailedOnDebug().Failed) return []; - hr = pShellExtInit.Get()->Initialize(pFolderPidl, null, default); + hr = shellExtInit.Initialize(folderPidl, null, default); if (hr.ThrowIfFailedOnDebug().Failed) return []; // Inserts "New (&W)" HMENU hMenu = PInvoke.CreatePopupMenu(); - hr = pNewMenu->QueryContextMenu(hMenu, 0, 1, 256, 0); + hr = newMenu.QueryContextMenu(hMenu, 0, 1, 256, 0); if (hr.ThrowIfFailedOnDebug().Failed) return []; // Invokes CNewMenu::_InitMenuPopup(), which populates the hSubMenu HMENU hSubMenu = PInvoke.GetSubMenu(hMenu, 0); - hr = pContextMenu2.Get()->HandleMenuMsg(PInvoke.WM_INITMENUPOPUP, (WPARAM)(nuint)hSubMenu.Value, 0); + hr = contextMenu2.HandleMenuMsg(PInvoke.WM_INITMENUPOPUP, (WPARAM)(nuint)hSubMenu.Value, 0); if (hr.ThrowIfFailedOnDebug().Failed) return []; - uint dwCount = unchecked((uint)PInvoke.GetMenuItemCount(hSubMenu)); - if (dwCount is unchecked((uint)-1)) + uint count = unchecked((uint)PInvoke.GetMenuItemCount(hSubMenu)); + if (count is unchecked((uint)-1)) return []; // Enumerates and populates the list List shellNewItems = []; - for (uint dwIndex = 0; dwIndex < dwCount; dwIndex++) + for (uint index = 0; index < count; index++) { MENUITEMINFOW mii = default; mii.cbSize = (uint)sizeof(MENUITEMINFOW); @@ -258,7 +239,7 @@ public static IEnumerable GetShellNewItems(this IWindows mii.dwTypeData = (char*)NativeMemory.Alloc(256U); mii.cch = 256; - if (PInvoke.GetMenuItemInfo(hSubMenu, dwIndex, true, &mii)) + if (PInvoke.GetMenuItemInfo(hSubMenu, index, true, &mii)) { shellNewItems.Add(new() { @@ -280,13 +261,11 @@ public static bool InvokeShellNewItem(this IWindowsFolder @this, WindowsContextM if (@this.ShellNewMenu is null) { - IContextMenu* pNewMenu = default; - - hr = PInvoke.CoCreateInstance(CLSID.CLSID_NewMenu, null, CLSCTX.CLSCTX_INPROC_SERVER, IID.IID_IContextMenu, (void**)&pNewMenu); + hr = PInvoke.CoCreateInstance(*CLSID.CLSID_NewMenu, null, CLSCTX.CLSCTX_INPROC_SERVER, out IContextMenu newMenu); if (hr.ThrowIfFailedOnDebug().Failed) return false; - @this.ShellNewMenu = pNewMenu; + @this.ShellNewMenu = newMenu; } CMINVOKECOMMANDINFO cmici = default; @@ -294,7 +273,7 @@ public static bool InvokeShellNewItem(this IWindowsFolder @this, WindowsContextM cmici.lpVerb = (PCSTR)(byte*)item.Id; cmici.nShow = (int)SHOW_WINDOW_CMD.SW_SHOWNORMAL; - hr = @this.ShellNewMenu->InvokeCommand(&cmici); + hr = @this.ShellNewMenu.InvokeCommand(&cmici); if (hr.ThrowIfFailedOnDebug().Failed) return false; diff --git a/src/Files.App.Storage/Windows/IWindowsFolder.cs b/src/Files.App.Storage/Windows/IWindowsFolder.cs index 92160da97f48..641e4735c514 100644 --- a/src/Files.App.Storage/Windows/IWindowsFolder.cs +++ b/src/Files.App.Storage/Windows/IWindowsFolder.cs @@ -10,6 +10,6 @@ public unsafe interface IWindowsFolder : IWindowsStorable, IChildFolder /// /// Gets or sets the cached for the ShellNew context menu. /// - public IContextMenu* ShellNewMenu { get; set; } + public IContextMenu ShellNewMenu { get; set; } } } diff --git a/src/Files.App.Storage/Windows/IWindowsStorable.cs b/src/Files.App.Storage/Windows/IWindowsStorable.cs index c79ef3ba66cb..dd02fc950b80 100644 --- a/src/Files.App.Storage/Windows/IWindowsStorable.cs +++ b/src/Files.App.Storage/Windows/IWindowsStorable.cs @@ -7,8 +7,8 @@ namespace Files.App.Storage { public unsafe interface IWindowsStorable : IStorableChild, IEquatable, IDisposable { - IShellItem* ThisPtr { get; set; } + IShellItem ThisPtr { get; set; } - IContextMenu* ContextMenu { get; set; } + IContextMenu ContextMenu { get; set; } } } diff --git a/src/Files.App.Storage/Windows/Managers/SystemTrayManager.cs b/src/Files.App.Storage/Windows/Managers/SystemTrayManager.cs index 6c861a097f74..1a838c101804 100644 --- a/src/Files.App.Storage/Windows/Managers/SystemTrayManager.cs +++ b/src/Files.App.Storage/Windows/Managers/SystemTrayManager.cs @@ -22,7 +22,7 @@ public unsafe partial class SystemTrayManager : IDisposable Action _callback = null!; private HWND _hWnd = default; - private WNDPROC? _wndProc; + private WndProcDelegate? _wndProc; private uint _dwTaskbarRestartMsgId; private bool _isShown; diff --git a/src/Files.App.Storage/Windows/Managers/TaskbarManager.cs b/src/Files.App.Storage/Windows/Managers/TaskbarManager.cs deleted file mode 100644 index 1d8772239428..000000000000 --- a/src/Files.App.Storage/Windows/Managers/TaskbarManager.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Files Community -// Licensed under the MIT License. - -using Windows.Win32; -using Windows.Win32.Foundation; -using Windows.Win32.System.Com; -using Windows.Win32.UI.Shell; - -namespace Files.App.Storage -{ - public unsafe class TaskbarManager : IDisposable - { - private ComPtr pTaskbarList = default; - - private static TaskbarManager? _Default = null; - public static TaskbarManager Default { get; } = _Default ??= new TaskbarManager(); - - public TaskbarManager() - { - Guid CLSID_TaskbarList = typeof(TaskbarList).GUID; - Guid IID_ITaskbarList3 = ITaskbarList3.IID_Guid; - HRESULT hr = PInvoke.CoCreateInstance( - &CLSID_TaskbarList, - null, - CLSCTX.CLSCTX_INPROC_SERVER, - &IID_ITaskbarList3, - (void**)pTaskbarList.GetAddressOf()); - - if (hr.ThrowIfFailedOnDebug().Succeeded) - hr = pTaskbarList.Get()->HrInit().ThrowIfFailedOnDebug(); - } - - public HRESULT SetProgressValue(HWND hwnd, ulong ullCompleted, ulong ullTotal) - { - return pTaskbarList.Get()->SetProgressValue(hwnd, ullCompleted, ullTotal); - } - - public HRESULT SetProgressState(HWND hwnd, TBPFLAG tbpFlags) - { - return pTaskbarList.Get()->SetProgressState(hwnd, tbpFlags); - } - - public void Dispose() - { - pTaskbarList.Dispose(); - } - } -} diff --git a/src/Files.App.Storage/Windows/WindowsBulkOperations.cs b/src/Files.App.Storage/Windows/WindowsBulkOperations.cs index d995d20ea71b..c48c2dbbf6a2 100644 --- a/src/Files.App.Storage/Windows/WindowsBulkOperations.cs +++ b/src/Files.App.Storage/Windows/WindowsBulkOperations.cs @@ -16,8 +16,8 @@ public unsafe partial class WindowsBulkOperations : IDisposable { // Fields - private readonly IFileOperation* _pFileOperation; - private readonly IFileOperationProgressSink* _pProgressSink; + private readonly IFileOperation _fileOperation; + private readonly IFileOperationProgressSink _pProgressSink; private readonly uint _progressSinkCookie; // Events @@ -70,20 +70,18 @@ public unsafe partial class WindowsBulkOperations : IDisposable /// Defines the behavior of the file operation, such as allowing undo and suppressing directory confirmation. public unsafe WindowsBulkOperations(HWND ownerHWnd = default, FILEOPERATION_FLAGS flags = FILEOPERATION_FLAGS.FOF_ALLOWUNDO | FILEOPERATION_FLAGS.FOF_NOCONFIRMMKDIR) { - IFileOperation* pFileOperation = null; - HRESULT hr = PInvoke.CoCreateInstance(CLSID.CLSID_FileOperation, null, CLSCTX.CLSCTX_LOCAL_SERVER, IID.IID_IFileOperation, (void**)&pFileOperation); + HRESULT hr = PInvoke.CoCreateInstance(CLSID.CLSID_FileOperation, null, CLSCTX.CLSCTX_LOCAL_SERVER, IID.IID_IFileOperation, out var fileOperationObj); + _fileOperation = (IFileOperation)fileOperationObj; hr.ThrowIfFailedOnDebug(); - _pFileOperation = pFileOperation; - if (ownerHWnd != default) - hr = _pFileOperation->SetOwnerWindow(ownerHWnd).ThrowIfFailedOnDebug(); + hr = _fileOperation.SetOwnerWindow(ownerHWnd).ThrowIfFailedOnDebug(); - hr = _pFileOperation->SetOperationFlags(flags).ThrowIfFailedOnDebug(); + hr = _fileOperation.SetOperationFlags(flags).ThrowIfFailedOnDebug(); - _pProgressSink = (IFileOperationProgressSink*)WindowsBulkOperationsSink.Create(this); - hr = _pFileOperation->Advise(_pProgressSink, out var progressSinkCookie).ThrowIfFailedOnDebug(); + _pProgressSink = new WindowsBulkOperationsSink(this); + hr = _fileOperation.Advise(_pProgressSink, out var progressSinkCookie).ThrowIfFailedOnDebug(); _progressSinkCookie = progressSinkCookie; } @@ -97,7 +95,7 @@ public unsafe WindowsBulkOperations(HWND ownerHWnd = default, FILEOPERATION_FLAG public unsafe HRESULT QueueCopyOperation(WindowsStorable targetItem, WindowsFolder destinationFolder, string? copyName) { fixed (char* pszCopyName = copyName) - return _pFileOperation->CopyItem(targetItem.ThisPtr, destinationFolder.ThisPtr, pszCopyName, _pProgressSink); + return _fileOperation.CopyItem(targetItem.ThisPtr, destinationFolder.ThisPtr, pszCopyName, _pProgressSink); } /// @@ -107,7 +105,7 @@ public unsafe HRESULT QueueCopyOperation(WindowsStorable targetItem, WindowsFold /// If this method succeeds, it returns . Otherwise, it returns an error code. public unsafe HRESULT QueueDeleteOperation(WindowsStorable targetItem) { - return _pFileOperation->DeleteItem(targetItem.ThisPtr, _pProgressSink); + return _fileOperation.DeleteItem(targetItem.ThisPtr, _pProgressSink); } /// @@ -120,7 +118,7 @@ public unsafe HRESULT QueueDeleteOperation(WindowsStorable targetItem) public unsafe HRESULT QueueMoveOperation(WindowsStorable targetItem, WindowsFolder destinationFolder, string? newName) { fixed (char* pszNewName = newName) - return _pFileOperation->MoveItem(targetItem.ThisPtr, destinationFolder.ThisPtr, pszNewName, null); + return _fileOperation.MoveItem(targetItem.ThisPtr, destinationFolder.ThisPtr, pszNewName, null); } /// @@ -134,7 +132,7 @@ public unsafe HRESULT QueueMoveOperation(WindowsStorable targetItem, WindowsFold public unsafe HRESULT QueueCreateOperation(WindowsFolder destinationFolder, FILE_FLAGS_AND_ATTRIBUTES fileAttributes, string name, string? templateName) { fixed (char* pszName = name, pszTemplateName = templateName) - return _pFileOperation->NewItem(destinationFolder.ThisPtr, (uint)fileAttributes, pszName, pszTemplateName, _pProgressSink); + return _fileOperation.NewItem(destinationFolder.ThisPtr, (uint)fileAttributes, pszName, pszTemplateName, _pProgressSink); } /// @@ -146,7 +144,7 @@ public unsafe HRESULT QueueCreateOperation(WindowsFolder destinationFolder, FILE public unsafe HRESULT QueueRenameOperation(WindowsStorable targetItem, string newName) { fixed (char* pszNewName = newName) - return _pFileOperation->RenameItem(targetItem.ThisPtr, pszNewName, _pProgressSink); + return _fileOperation.RenameItem(targetItem.ThisPtr, pszNewName, _pProgressSink); } /// @@ -155,7 +153,7 @@ public unsafe HRESULT QueueRenameOperation(WindowsStorable targetItem, string ne /// If this method succeeds, it returns . Otherwise, it returns an error code. public unsafe HRESULT PerformAllOperations() { - return _pFileOperation->PerformOperations(); + return _fileOperation.PerformOperations(); } // Disposer @@ -164,10 +162,7 @@ public unsafe HRESULT PerformAllOperations() public unsafe void Dispose() { if (_pProgressSink is not null) - _pFileOperation->Unadvise(_progressSinkCookie); - - _pFileOperation->Release(); - _pProgressSink->Release(); + _fileOperation.Unadvise(_progressSinkCookie); } } } diff --git a/src/Files.App.Storage/Windows/WindowsBulkOperationsSink.Methods.cs b/src/Files.App.Storage/Windows/WindowsBulkOperationsSink.Methods.cs deleted file mode 100644 index f4b9f764b87c..000000000000 --- a/src/Files.App.Storage/Windows/WindowsBulkOperationsSink.Methods.cs +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) Files Community -// Licensed under the MIT License. - -using Windows.Win32.Foundation; -using Windows.Win32.UI.Shell; - -namespace Files.App.Storage -{ - public sealed partial class WindowsBulkOperations : IDisposable - { - private unsafe partial struct WindowsBulkOperationsSink : IFileOperationProgressSink.Interface - { - public HRESULT StartOperations() - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - operations.OperationsStarted?.Invoke(operations, EventArgs.Empty); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public HRESULT FinishOperations(HRESULT hrResult) - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - operations.OperationsFinished?.Invoke(operations, new(result: hrResult)); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public unsafe HRESULT PreRenameItem(uint dwFlags, IShellItem* pSource, PCWSTR pszNewName) - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - operations.ItemRenaming?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(pSource), null, null, pszNewName.ToString(), null, default)); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public unsafe HRESULT PostRenameItem(uint dwFlags, IShellItem* pSource, PCWSTR pszNewName, HRESULT hrRename, IShellItem* psiNewlyCreated) - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - operations.ItemRenamed?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(pSource), null, WindowsStorable.TryParse(psiNewlyCreated), pszNewName.ToString(), null, hrRename)); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public unsafe HRESULT PreMoveItem(uint dwFlags, IShellItem* pSource, IShellItem* psiDestinationFolder, PCWSTR pszNewName) - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - operations.ItemMoving?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(pSource), new WindowsFolder(psiDestinationFolder), null, pszNewName.ToString(), null, default)); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public unsafe HRESULT PostMoveItem(uint dwFlags, IShellItem* pSource, IShellItem* psiDestinationFolder, PCWSTR pszNewName, HRESULT hrMove, IShellItem* psiNewlyCreated) - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - operations.ItemMoved?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(pSource), new WindowsFolder(psiDestinationFolder), WindowsStorable.TryParse(psiNewlyCreated), pszNewName.ToString(), null, hrMove)); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public unsafe HRESULT PreCopyItem(uint dwFlags, IShellItem* pSource, IShellItem* psiDestinationFolder, PCWSTR pszNewName) - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - operations.ItemCopying?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(pSource), new WindowsFolder(psiDestinationFolder), null, pszNewName.ToString(), null, default)); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public unsafe HRESULT PostCopyItem(uint dwFlags, IShellItem* pSource, IShellItem* psiDestinationFolder, PCWSTR pszNewName, HRESULT hrCopy, IShellItem* psiNewlyCreated) - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - operations.ItemCopied?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(pSource), new WindowsFolder(psiDestinationFolder), WindowsStorable.TryParse(psiNewlyCreated), pszNewName.ToString(), null, hrCopy)); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public unsafe HRESULT PreDeleteItem(uint dwFlags, IShellItem* pSource) - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - operations.ItemDeleting?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(pSource), null, null, null, null, default)); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public unsafe HRESULT PostDeleteItem(uint dwFlags, IShellItem* pSource, HRESULT hrDelete, IShellItem* psiNewlyCreated) - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - operations.ItemDeleted?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(pSource), null, WindowsStorable.TryParse(psiNewlyCreated), null, null, hrDelete)); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public unsafe HRESULT PreNewItem(uint dwFlags, IShellItem* psiDestinationFolder, PCWSTR pszNewName) - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - operations.ItemCreating?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, null, new WindowsFolder(psiDestinationFolder), null, pszNewName.ToString(), null, default)); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public unsafe HRESULT PostNewItem(uint dwFlags, IShellItem* psiDestinationFolder, PCWSTR pszNewName, PCWSTR pszTemplateName, uint dwFileAttributes, HRESULT hrNew, IShellItem* psiNewItem) - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - operations.ItemCreated?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, null, new WindowsFolder(psiDestinationFolder), WindowsStorable.TryParse(psiNewItem), pszNewName.ToString(), pszTemplateName.ToString(), hrNew)); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public HRESULT UpdateProgress(uint iWorkTotal, uint iWorkSoFar) - { - if (_operationsHandle.Target is WindowsBulkOperations operations) - { - var percentage = iWorkTotal is 0 ? 0 : iWorkSoFar * 100.0 / iWorkTotal; - operations.ProgressUpdated?.Invoke(operations, new((int)percentage, null)); - return HRESULT.S_OK; - } - - return HRESULT.E_FAIL; - } - - public HRESULT ResetTimer() - { - return HRESULT.E_NOTIMPL; - } - - public HRESULT PauseTimer() - { - return HRESULT.E_NOTIMPL; - } - - public HRESULT ResumeTimer() - { - return HRESULT.E_NOTIMPL; - } - } - } -} diff --git a/src/Files.App.Storage/Windows/WindowsBulkOperationsSink.VTable.cs b/src/Files.App.Storage/Windows/WindowsBulkOperationsSink.VTable.cs deleted file mode 100644 index 95c309023f76..000000000000 --- a/src/Files.App.Storage/Windows/WindowsBulkOperationsSink.VTable.cs +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) Files Community -// Licensed under the MIT License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Windows.Win32.Foundation; -using Windows.Win32.UI.Shell; -using WinRT.Interop; - -namespace Files.App.Storage -{ - public sealed partial class WindowsBulkOperations : IDisposable - { - private unsafe partial struct WindowsBulkOperationsSink - { - private static readonly void** _lpPopulatedVtbl = PopulateVTable(); - - private void** _lpVtbl; - private volatile int _refCount; - private GCHandle _operationsHandle; - - public static WindowsBulkOperationsSink* Create(WindowsBulkOperations operations) - { - WindowsBulkOperationsSink* operationsSink = (WindowsBulkOperationsSink*)NativeMemory.Alloc((nuint)sizeof(WindowsBulkOperationsSink)); - operationsSink->_lpVtbl = _lpPopulatedVtbl; - operationsSink->_refCount = 1; - operationsSink->_operationsHandle = GCHandle.Alloc(operations); - - return operationsSink; - } - - private static void** PopulateVTable() - { - void** vtbl = (void**)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(WindowsBulkOperationsSink), sizeof(void*) * 19); - vtbl[0] = (delegate* unmanaged)&Vtbl.QueryInterface; - vtbl[1] = (delegate* unmanaged)&Vtbl.AddRef; - vtbl[2] = (delegate* unmanaged)&Vtbl.Release; - vtbl[3] = (delegate* unmanaged)&Vtbl.StartOperations; - vtbl[4] = (delegate* unmanaged)&Vtbl.FinishOperations; - vtbl[5] = (delegate* unmanaged)&Vtbl.PreRenameItem; - vtbl[6] = (delegate* unmanaged)&Vtbl.PostRenameItem; - vtbl[7] = (delegate* unmanaged)&Vtbl.PreMoveItem; - vtbl[8] = (delegate* unmanaged)&Vtbl.PostMoveItem; - vtbl[9] = (delegate* unmanaged)&Vtbl.PreCopyItem; - vtbl[10] = (delegate* unmanaged)&Vtbl.PostCopyItem; - vtbl[11] = (delegate* unmanaged)&Vtbl.PreDeleteItem; - vtbl[12] = (delegate* unmanaged)&Vtbl.PostDeleteItem; - vtbl[13] = (delegate* unmanaged)&Vtbl.PreNewItem; - vtbl[14] = (delegate* unmanaged)&Vtbl.PostNewItem; - vtbl[15] = (delegate* unmanaged)&Vtbl.UpdateProgress; - vtbl[16] = (delegate* unmanaged)&Vtbl.ResetTimer; - vtbl[17] = (delegate* unmanaged)&Vtbl.PauseTimer; - vtbl[18] = (delegate* unmanaged)&Vtbl.ResumeTimer; - - return vtbl; - } - - private static class Vtbl - { - [UnmanagedCallersOnly] - public static HRESULT QueryInterface(WindowsBulkOperationsSink* @this, Guid* riid, void** ppv) - { - if (ppv is null) - return HRESULT.E_POINTER; - - if (riid->Equals(IID.IID_IUnknown) || riid->Equals(IFileOperationProgressSink.IID_Guid)) - { - Interlocked.Increment(ref @this->_refCount); - *ppv = @this; - return HRESULT.S_OK; - } - - return HRESULT.E_NOINTERFACE; - } - - [UnmanagedCallersOnly] - public static int AddRef(WindowsBulkOperationsSink* @this) - => Interlocked.Increment(ref @this->_refCount); - - [UnmanagedCallersOnly] - public static int Release(WindowsBulkOperationsSink* @this) - { - int newRefCount = Interlocked.Decrement(ref @this->_refCount); - if (newRefCount is 0) - { - if (@this->_operationsHandle.IsAllocated) - @this->_operationsHandle.Free(); - - NativeMemory.Free(@this); - } - - return newRefCount; - } - - [UnmanagedCallersOnly] - public static HRESULT StartOperations(WindowsBulkOperationsSink* @this) - => @this->StartOperations(); - - [UnmanagedCallersOnly] - public static HRESULT FinishOperations(WindowsBulkOperationsSink* @this, HRESULT hrResult) - => @this->FinishOperations(hrResult); - - [UnmanagedCallersOnly] - public static HRESULT PreRenameItem(WindowsBulkOperationsSink* @this, uint dwFlags, IShellItem* psiItem, PCWSTR pszNewName) - => @this->PreRenameItem(dwFlags, psiItem, pszNewName); - - [UnmanagedCallersOnly] - public static HRESULT PostRenameItem(WindowsBulkOperationsSink* @this, uint dwFlags, IShellItem* psiItem, PCWSTR pszNewName, HRESULT hrRename, IShellItem* psiNewlyCreated) - => @this->PostRenameItem(dwFlags, psiItem, pszNewName, hrRename, psiNewlyCreated); - - [UnmanagedCallersOnly] - public static HRESULT PreMoveItem(WindowsBulkOperationsSink* @this, uint dwFlags, IShellItem* psiItem, IShellItem* psiDestinationFolder, PCWSTR pszNewName) - => @this->PreMoveItem(dwFlags, psiItem, psiDestinationFolder, pszNewName); - - [UnmanagedCallersOnly] - public static HRESULT PostMoveItem(WindowsBulkOperationsSink* @this, uint dwFlags, IShellItem* psiItem, IShellItem* psiDestinationFolder, PCWSTR pszNewName, HRESULT hrMove, IShellItem* psiNewlyCreated) - => @this->PostMoveItem(dwFlags, psiItem, psiDestinationFolder, pszNewName, hrMove, psiNewlyCreated); - - [UnmanagedCallersOnly] - public static HRESULT PreCopyItem(WindowsBulkOperationsSink* @this, uint dwFlags, IShellItem* psiItem, IShellItem* psiDestinationFolder, PCWSTR pszNewName) - => @this->PreCopyItem(dwFlags, psiItem, psiDestinationFolder, pszNewName); - - [UnmanagedCallersOnly] - public static HRESULT PostCopyItem(WindowsBulkOperationsSink* @this, uint dwFlags, IShellItem* psiItem, IShellItem* psiDestinationFolder, PCWSTR pszNewName, HRESULT hrCopy, IShellItem* psiNewlyCreated) - => @this->PostCopyItem(dwFlags, psiItem, psiDestinationFolder, pszNewName, hrCopy, psiNewlyCreated); - - [UnmanagedCallersOnly] - public static HRESULT PreDeleteItem(WindowsBulkOperationsSink* @this, uint dwFlags, IShellItem* psiItem) - => @this->PreDeleteItem(dwFlags, psiItem); - - [UnmanagedCallersOnly] - public static HRESULT PostDeleteItem(WindowsBulkOperationsSink* @this, uint dwFlags, IShellItem* psiItem, HRESULT hrDelete, IShellItem* psiNewlyCreated) - => @this->PostDeleteItem(dwFlags, psiItem, hrDelete, psiNewlyCreated); - - [UnmanagedCallersOnly] - public static HRESULT PreNewItem(WindowsBulkOperationsSink* @this, uint dwFlags, IShellItem* psiDestinationFolder, PCWSTR pszNewName) - => @this->PreNewItem(dwFlags, psiDestinationFolder, pszNewName); - - [UnmanagedCallersOnly] - public static HRESULT PostNewItem(WindowsBulkOperationsSink* @this, uint dwFlags, IShellItem* psiDestinationFolder, PCWSTR pszNewName, PCWSTR pszTemplateName, uint dwFileAttributes, HRESULT hrNew, IShellItem* psiNewItem) - => @this->PostNewItem(dwFlags, psiDestinationFolder, pszNewName, pszTemplateName, dwFileAttributes, hrNew, psiNewItem); - - [UnmanagedCallersOnly] - public static HRESULT UpdateProgress(WindowsBulkOperationsSink* @this, uint iWorkTotal, uint iWorkSoFar) - => @this->UpdateProgress(iWorkTotal, iWorkSoFar); - - [UnmanagedCallersOnly] - public static HRESULT ResetTimer(WindowsBulkOperationsSink* @this) - => @this->ResetTimer(); - - [UnmanagedCallersOnly] - public static HRESULT PauseTimer(WindowsBulkOperationsSink* @this) - => @this->PauseTimer(); - - [UnmanagedCallersOnly] - public static HRESULT ResumeTimer(WindowsBulkOperationsSink* @this) - => @this->ResumeTimer(); - } - } - } -} diff --git a/src/Files.App.Storage/Windows/WindowsBulkOperationsSink.cs b/src/Files.App.Storage/Windows/WindowsBulkOperationsSink.cs new file mode 100644 index 000000000000..cfe74f49e126 --- /dev/null +++ b/src/Files.App.Storage/Windows/WindowsBulkOperationsSink.cs @@ -0,0 +1,131 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Windows.Win32.Foundation; +using Windows.Win32.UI.Shell; + +namespace Files.App.Storage +{ + public sealed partial class WindowsBulkOperations : IDisposable + { + [GeneratedComClass] + private partial class WindowsBulkOperationsSink : IFileOperationProgressSink + { + private WindowsBulkOperations _operations; + + public WindowsBulkOperationsSink(WindowsBulkOperations operations) + { + _operations = operations; + } + + public HRESULT StartOperations() + { + _operations.OperationsStarted?.Invoke(_operations, EventArgs.Empty); + + return HRESULT.S_OK; + } + + public HRESULT FinishOperations(HRESULT hrResult) + { + _operations.OperationsFinished?.Invoke(_operations, new(result: hrResult)); + + return HRESULT.S_OK; + } + + public HRESULT ResetTimer() + { + return HRESULT.E_NOTIMPL; + } + + public HRESULT PauseTimer() + { + return HRESULT.E_NOTIMPL; + } + + public HRESULT ResumeTimer() + { + return HRESULT.E_NOTIMPL; + } + + [return: MarshalAs(UnmanagedType.Error)] + public HRESULT PreRenameItem(uint dwFlags, IShellItem psiItem, PCWSTR pszNewName) + { + _operations.ItemRenaming?.Invoke(_operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(psiItem), null, null, pszNewName.ToString(), null, default)); + return HRESULT.S_OK; + } + + [return: MarshalAs(UnmanagedType.Error)] + public HRESULT PostRenameItem(uint dwFlags, IShellItem psiItem, PCWSTR pszNewName, HRESULT hrRename, IShellItem psiNewlyCreated) + { + _operations.ItemRenamed?.Invoke(_operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(psiItem), null, WindowsStorable.TryParse(psiNewlyCreated), pszNewName.ToString(), null, hrRename)); + return HRESULT.S_OK; + } + + [return: MarshalAs(UnmanagedType.Error)] + public HRESULT PreMoveItem(uint dwFlags, IShellItem psiItem, IShellItem psiDestinationFolder, PCWSTR pszNewName) + { + _operations.ItemMoving?.Invoke(_operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(psiItem), new WindowsFolder(psiDestinationFolder), null, pszNewName.ToString(), null, default)); + return HRESULT.S_OK; + } + + [return: MarshalAs(UnmanagedType.Error)] + public HRESULT PostMoveItem(uint dwFlags, IShellItem psiItem, IShellItem psiDestinationFolder, PCWSTR pszNewName, HRESULT hrMove, IShellItem psiNewlyCreated) + { + _operations.ItemMoved?.Invoke(_operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(psiItem), new WindowsFolder(psiDestinationFolder), WindowsStorable.TryParse(psiNewlyCreated), pszNewName.ToString(), null, hrMove)); + return HRESULT.S_OK; + } + + [return: MarshalAs(UnmanagedType.Error)] + public HRESULT PreCopyItem(uint dwFlags, IShellItem psiItem, IShellItem psiDestinationFolder, PCWSTR pszNewName) + { + _operations.ItemCopying?.Invoke(_operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(psiItem), new WindowsFolder(psiDestinationFolder), null, pszNewName.ToString(), null, default)); + return HRESULT.S_OK; + } + + [return: MarshalAs(UnmanagedType.Error)] + public HRESULT PostCopyItem(uint dwFlags, IShellItem psiItem, IShellItem psiDestinationFolder, PCWSTR pszNewName, HRESULT hrCopy, IShellItem psiNewlyCreated) + { + _operations.ItemCopied?.Invoke(_operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(psiItem), new WindowsFolder(psiDestinationFolder), WindowsStorable.TryParse(psiNewlyCreated), pszNewName.ToString(), null, hrCopy)); + return HRESULT.S_OK; + } + + [return: MarshalAs(UnmanagedType.Error)] + public HRESULT PreDeleteItem(uint dwFlags, IShellItem psiItem) + { + _operations.ItemDeleting?.Invoke(_operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(psiItem), null, null, null, null, default)); + return HRESULT.S_OK; + } + + [return: MarshalAs(UnmanagedType.Error)] + public HRESULT PostDeleteItem(uint dwFlags, IShellItem psiItem, HRESULT hrDelete, IShellItem psiNewlyCreated) + { + _operations.ItemDeleted?.Invoke(_operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(psiItem), null, WindowsStorable.TryParse(psiNewlyCreated), null, null, hrDelete)); + return HRESULT.S_OK; + } + + [return: MarshalAs(UnmanagedType.Error)] + public HRESULT PreNewItem(uint dwFlags, IShellItem psiDestinationFolder, PCWSTR pszNewName) + { + _operations.ItemCreating?.Invoke(_operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, null, new WindowsFolder(psiDestinationFolder), null, pszNewName.ToString(), null, default)); + return HRESULT.S_OK; + } + + [return: MarshalAs(UnmanagedType.Error)] + public HRESULT PostNewItem(uint dwFlags, IShellItem psiDestinationFolder, PCWSTR pszNewName, PCWSTR pszTemplateName, uint dwFileAttributes, HRESULT hrNew, IShellItem psiNewItem) + { + _operations.ItemCreated?.Invoke(_operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, null, new WindowsFolder(psiDestinationFolder), WindowsStorable.TryParse(psiNewItem), pszNewName.ToString(), pszTemplateName.ToString(), hrNew)); + return HRESULT.S_OK; + } + + public HRESULT UpdateProgress(uint iWorkTotal, uint iWorkSoFar) + { + var percentage = iWorkTotal is 0 ? 0 : iWorkSoFar * 100.0 / iWorkTotal; + _operations.ProgressUpdated?.Invoke(_operations, new((int)percentage, null)); + return HRESULT.S_OK; + } + + } + } +} diff --git a/src/Files.App.Storage/Windows/WindowsFile.cs b/src/Files.App.Storage/Windows/WindowsFile.cs index ef4b7d85d24b..1c4f71939176 100644 --- a/src/Files.App.Storage/Windows/WindowsFile.cs +++ b/src/Files.App.Storage/Windows/WindowsFile.cs @@ -9,9 +9,9 @@ namespace Files.App.Storage [DebuggerDisplay("{" + nameof(ToString) + "()}")] public unsafe class WindowsFile : WindowsStorable, IWindowsFile { - public WindowsFile(IShellItem* ptr) + public WindowsFile(IShellItem shellItem) { - ThisPtr = ptr; + ThisPtr = shellItem; } public Task OpenStreamAsync(FileAccess accessMode, CancellationToken cancellationToken = default) diff --git a/src/Files.App.Storage/Windows/WindowsFolder.cs b/src/Files.App.Storage/Windows/WindowsFolder.cs index 510300fa5f6d..14f754efe715 100644 --- a/src/Files.App.Storage/Windows/WindowsFolder.cs +++ b/src/Files.App.Storage/Windows/WindowsFolder.cs @@ -13,7 +13,7 @@ namespace Files.App.Storage public unsafe class WindowsFolder : WindowsStorable, IWindowsFolder { /// - public IContextMenu* ShellNewMenu + public IContextMenu ShellNewMenu { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; @@ -22,50 +22,50 @@ public IContextMenu* ShellNewMenu set; } - public WindowsFolder(IShellItem* ptr) + public WindowsFolder(IShellItem shellItem) { - ThisPtr = ptr; + ThisPtr = shellItem; } public WindowsFolder(Guid folderId) { - IShellItem* pShellItem = default; - - HRESULT hr = PInvoke.SHGetKnownFolderItem(&folderId, KNOWN_FOLDER_FLAG.KF_FLAG_DEFAULT, HANDLE.Null, IID.IID_IShellItem, (void**)&pShellItem); + HRESULT hr = PInvoke.SHGetKnownFolderItem(&folderId, KNOWN_FOLDER_FLAG.KF_FLAG_DEFAULT, HANDLE.Null, IID.IID_IShellItem, out var shellItemObj); + var shellItem = (IShellItem)shellItemObj; if (hr.Failed) { - fixed (char* pszShellPath = $"Shell:::{folderId:B}") - hr = PInvoke.SHCreateItemFromParsingName(pszShellPath, null, IID.IID_IShellItem, (void**)&pShellItem); + hr = PInvoke.SHCreateItemFromParsingName($"Shell:::{folderId:B}", null, typeof(IShellItem).GUID, out shellItemObj); + shellItem = (IShellItem)shellItemObj; // Invalid FOLDERID; this should never happen. hr.ThrowOnFailure(); } - ThisPtr = pShellItem; + ThisPtr = shellItem; } public IAsyncEnumerable GetItemsAsync(StorableType type = StorableType.All, CancellationToken cancellationToken = default) { - using ComPtr pEnumShellItems = default; - - HRESULT hr = ThisPtr->BindToHandler(null, BHID.BHID_EnumItems, IID.IID_IEnumShellItems, (void**)pEnumShellItems.GetAddressOf()); + HRESULT hr = ThisPtr.BindToHandler(null, BHID.BHID_EnumItems, IID.IID_IEnumShellItems, out var enumShellItemsObj); + var enumShellItems = (IEnumShellItems)enumShellItemsObj; if (hr.ThrowIfFailedOnDebug().Failed) return Enumerable.Empty().ToAsyncEnumerable(); List childItems = []; - IShellItem* pChildShellItem = null; - while ((hr = pEnumShellItems.Get()->Next(1, &pChildShellItem)) == HRESULT.S_OK) + var childItemArray = new IShellItem[1]; + while ((hr = enumShellItems.Next(1, childItemArray)) == HRESULT.S_OK) { - bool isFolder = pChildShellItem->GetAttributes(SFGAO_FLAGS.SFGAO_FOLDER, out var dwAttributes).Succeeded && dwAttributes is SFGAO_FLAGS.SFGAO_FOLDER; + IShellItem childItem = childItemArray[0]; + + bool isFolder = childItem.GetAttributes(SFGAO_FLAGS.SFGAO_FOLDER, out var dwAttributes).Succeeded && dwAttributes is SFGAO_FLAGS.SFGAO_FOLDER; if (type.HasFlag(StorableType.File) && !isFolder) { - childItems.Add(new WindowsFile(pChildShellItem)); + childItems.Add(new WindowsFile(childItem)); } else if (type.HasFlag(StorableType.Folder) && isFolder) { - childItems.Add(new WindowsFolder(pChildShellItem)); + childItems.Add(new WindowsFolder(childItem)); } } @@ -74,12 +74,5 @@ public IAsyncEnumerable GetItemsAsync(StorableType type = Storab return childItems.ToAsyncEnumerable(); } - - public override void Dispose() - { - base.Dispose(); - - if (ShellNewMenu is not null) ShellNewMenu->Release(); - } } } diff --git a/src/Files.App.Storage/Windows/WindowsStorable.cs b/src/Files.App.Storage/Windows/WindowsStorable.cs index d7ed69cc2f31..016e0080e4bc 100644 --- a/src/Files.App.Storage/Windows/WindowsStorable.cs +++ b/src/Files.App.Storage/Windows/WindowsStorable.cs @@ -12,7 +12,7 @@ namespace Files.App.Storage public unsafe abstract class WindowsStorable : IWindowsStorable { /// - public IShellItem* ThisPtr + public IShellItem ThisPtr { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; @@ -22,7 +22,7 @@ public IShellItem* ThisPtr } /// - public IContextMenu* ContextMenu + public IContextMenu ContextMenu { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; @@ -37,25 +37,21 @@ public IContextMenu* ContextMenu /// public string Name => this.GetDisplayName(SIGDN.SIGDN_PARENTRELATIVEFORUI); - public static WindowsStorable? TryParse(string szPath) + public static WindowsStorable? TryParse(string parseablePath) { - HRESULT hr = default; - IShellItem* pShellItem = null; - - fixed (char* pszPath = szPath) - hr = PInvoke.SHCreateItemFromParsingName(pszPath, null, IID.IID_IShellItem, (void**)&pShellItem); - - if (pShellItem is null) + HRESULT hr = PInvoke.SHCreateItemFromParsingName(parseablePath, null, typeof(IShellItem).GUID, out var shellItemObj); + var shellItem = (IShellItem)shellItemObj; + if (shellItem is null) return null; - return TryParse(pShellItem); + return TryParse(shellItem); } - public static WindowsStorable? TryParse(IShellItem* pShellItem) + public static WindowsStorable? TryParse(IShellItem shellItem) { - bool isFolder = pShellItem->GetAttributes(SFGAO_FLAGS.SFGAO_FOLDER, out var returnedAttributes).Succeeded && returnedAttributes is SFGAO_FLAGS.SFGAO_FOLDER; + bool isFolder = shellItem.GetAttributes(SFGAO_FLAGS.SFGAO_FOLDER, out var returnedAttributes).Succeeded && returnedAttributes is SFGAO_FLAGS.SFGAO_FOLDER; - return isFolder ? new WindowsFolder(pShellItem) : new WindowsFile(pShellItem); + return isFolder ? new WindowsFolder(shellItem) : new WindowsFile(shellItem); } /// @@ -63,12 +59,11 @@ public IContextMenu* ContextMenu { cancellationToken.ThrowIfCancellationRequested(); - IShellItem* pParentFolder = default; - HRESULT hr = ThisPtr->GetParent(&pParentFolder); + HRESULT hr = ThisPtr.GetParent(out var parentFolder); if (hr.ThrowIfFailedOnDebug().Failed) return Task.FromResult(null); - return Task.FromResult(new WindowsFolder(pParentFolder)); + return Task.FromResult(new WindowsFolder(parentFolder)); } /// @@ -86,8 +81,6 @@ public override int GetHashCode() /// public virtual void Dispose() { - if (ThisPtr is not null) ThisPtr->Release(); - if (ContextMenu is not null) ContextMenu->Release(); } /// @@ -102,7 +95,7 @@ public unsafe bool Equals(IWindowsStorable? other) if (other is null) return false; - return ThisPtr->Compare(other.ThisPtr, (uint)_SICHINTF.SICHINT_DISPLAY, out int order).Succeeded && order is 0; + return ThisPtr.Compare(other.ThisPtr, (uint)_SICHINTF.SICHINT_DISPLAY, out int order).Succeeded && order is 0; } public static bool operator ==(WindowsStorable left, WindowsStorable right) diff --git a/src/Files.App/Data/Items/WidgetRecentItem.cs b/src/Files.App/Data/Items/WidgetRecentItem.cs index ec26009caefb..80de5db469ee 100644 --- a/src/Files.App/Data/Items/WidgetRecentItem.cs +++ b/src/Files.App/Data/Items/WidgetRecentItem.cs @@ -10,7 +10,7 @@ namespace Files.App.Data.Items /// /// Represents an item for recent item of File Explorer on Windows. /// - public sealed partial class RecentItem : WidgetCardItem, IEquatable, IDisposable + public sealed partial class RecentItem : WidgetCardItem, IEquatable { private BitmapImage? _Icon; /// @@ -38,7 +38,7 @@ public BitmapImage? Icon /// /// This has to be removed in the future. /// - public unsafe required ComPtr ShellItem { get; init; } + public required IShellItem ShellItem { get; init; } /// /// Loads thumbnail icon of the recent item. @@ -56,10 +56,5 @@ public async Task LoadRecentItemIconAsync() public override int GetHashCode() => (Path, Name).GetHashCode(); public override bool Equals(object? other) => other is RecentItem item && Equals(item); public bool Equals(RecentItem? other) => other is not null && other.Name == Name && other.Path == Path; - - public unsafe void Dispose() - { - ShellItem.Dispose(); - } } } diff --git a/src/Files.App/Data/Items/WindowEx.cs b/src/Files.App/Data/Items/WindowEx.cs index b00cb0565279..627a47f35dad 100644 --- a/src/Files.App/Data/Items/WindowEx.cs +++ b/src/Files.App/Data/Items/WindowEx.cs @@ -20,8 +20,8 @@ namespace Files.App.Data.Items public unsafe partial class WindowEx : Window, IDisposable { private bool _isInitialized; - private readonly WNDPROC _oldWndProc; - private readonly WNDPROC _newWndProc; + private readonly WndProcDelegate _oldWndProc; + private readonly WndProcDelegate _newWndProc; private readonly ApplicationDataContainer _applicationDataContainer = ApplicationData.Current.LocalSettings; @@ -88,7 +88,7 @@ public unsafe WindowEx(int minWidth = 400, int minHeight = 300) _newWndProc = new(NewWindowProc); var pNewWndProc = Marshal.GetFunctionPointerForDelegate(_newWndProc); var pOldWndProc = PInvoke.SetWindowLongPtr(new(WindowHandle), WINDOW_LONG_PTR_INDEX.GWL_WNDPROC, pNewWndProc); - _oldWndProc = Marshal.GetDelegateForFunctionPointer(pOldWndProc); + _oldWndProc = Marshal.GetDelegateForFunctionPointer(pOldWndProc); Closed += WindowEx_Closed; } @@ -223,7 +223,7 @@ private unsafe List> GetAllMonitorInfo() { List> monitors = []; - MONITORENUMPROC monitorEnumProc = new((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) => + MonitorEnumProcDelegate monitorEnumProc = new((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) => { MONITORINFOEXW info = default; info.monitorInfo.cbSize = (uint)Marshal.SizeOf(); diff --git a/src/Files.App/Extensions/ActionManager.cs b/src/Files.App/Extensions/ActionManager.cs index 8928718ef6c9..6e77ae392afa 100644 --- a/src/Files.App/Extensions/ActionManager.cs +++ b/src/Files.App/Extensions/ActionManager.cs @@ -38,10 +38,10 @@ private ActionManager() Guid classId = Guid.Parse(ActionRuntimeClsidStr); Guid iid = IActionRuntimeIID; - HRESULT hresult = PInvoke.CoCreateInstance(&classId, null, CLSCTX.CLSCTX_LOCAL_SERVER, &iid, (void**)&abiPtr); + HRESULT hresult = PInvoke.CoCreateInstance(&classId, null, CLSCTX.CLSCTX_LOCAL_SERVER, &iid, out var actionRuntimeObj); Marshal.ThrowExceptionForHR((int)hresult); - return MarshalInterface.FromAbi(abiPtr); + return (ActionRuntime)actionRuntimeObj; } catch { diff --git a/src/Files.App/Services/Storage/StorageTrashBinService.cs b/src/Files.App/Services/Storage/StorageTrashBinService.cs index f2feafa3620f..253bf388ea32 100644 --- a/src/Files.App/Services/Storage/StorageTrashBinService.cs +++ b/src/Files.App/Services/Storage/StorageTrashBinService.cs @@ -101,38 +101,39 @@ public async Task RestoreAllTrashesAsync() private unsafe bool RestoreAllTrashesInternal() { // Get IShellItem for Recycle Bin folder - using ComPtr pRecycleBinFolderShellItem = default; - HRESULT hr = PInvoke.SHGetKnownFolderItem(FOLDERID.FOLDERID_RecycleBinFolder, KNOWN_FOLDER_FLAG.KF_FLAG_DEFAULT, HANDLE.Null, IID.IID_IShellItem, (void**)pRecycleBinFolderShellItem.GetAddressOf()); + HRESULT hr = PInvoke.SHGetKnownFolderItem(FOLDERID.FOLDERID_RecycleBinFolder, KNOWN_FOLDER_FLAG.KF_FLAG_DEFAULT, hToken: HANDLE.Null, IID.IID_IShellItem, out var recycleBinFolderObj); + var recycleBinFolder = (IShellItem)recycleBinFolderObj; // Get IEnumShellItems for Recycle Bin folder - using ComPtr pEnumShellItems = default; - hr = pRecycleBinFolderShellItem.Get()->BindToHandler(null, BHID.BHID_EnumItems, IID.IID_IEnumShellItems, (void**)pEnumShellItems.GetAddressOf()); + hr = recycleBinFolder.BindToHandler(null, BHID.BHID_EnumItems, IID.IID_IEnumShellItems, out var enumShellItemsObj); + var enumShellItems = (IEnumShellItems)enumShellItemsObj; // Initialize how to perform the operation - using ComPtr pFileOperation = default; - hr = PInvoke.CoCreateInstance(CLSID.CLSID_FileOperation, null, CLSCTX.CLSCTX_LOCAL_SERVER, IID.IID_IFileOperation, (void**)pFileOperation.GetAddressOf()); - hr = pFileOperation.Get()->SetOperationFlags(FILEOPERATION_FLAGS.FOF_NO_UI); - hr = pFileOperation.Get()->SetOwnerWindow(new(MainWindow.Instance.WindowHandle)); + hr = PInvoke.CoCreateInstance(CLSID.CLSID_FileOperation, null, CLSCTX.CLSCTX_LOCAL_SERVER, IID.IID_IFileOperation, out var fileOperationObj); + var fileOperation = (IFileOperation)fileOperationObj; + hr = fileOperation.SetOperationFlags(FILEOPERATION_FLAGS.FOF_NO_UI); + hr = fileOperation.SetOwnerWindow(new(MainWindow.Instance.WindowHandle)); - using ComPtr pShellItem = default; - while (pEnumShellItems.Get()->Next(1, pShellItem.GetAddressOf()) == HRESULT.S_OK) + var childItemArray = new IShellItem[1]; + while (enumShellItems.Next(1, childItemArray) == HRESULT.S_OK) { + IShellItem childItem = childItemArray[0]; + // Get the original path - using ComPtr pShellItem2 = default; - hr = pShellItem.Get()->QueryInterface(IID.IID_IShellItem2, (void**)pShellItem2.GetAddressOf()); + IShellItem2 childItem2 = (IShellItem2)childItem; hr = PInvoke.PSGetPropertyKeyFromName("System.Recycle.DeletedFrom", out var originalPathPropertyKey); - hr = pShellItem2.Get()->GetString(originalPathPropertyKey, out var szOriginalPath); + hr = childItem2.GetString(originalPathPropertyKey, out var originalPath); // Get IShellItem of the original path - hr = PInvoke.SHCreateItemFromParsingName(szOriginalPath.ToString(), null, typeof(IShellItem).GUID, out var pOriginalPathShellItemPtr); - var pOriginalPathShellItem = (IShellItem*)pOriginalPathShellItemPtr; + hr = PInvoke.SHCreateItemFromParsingName(originalPath.ToString(), null, typeof(IShellItem).GUID, out var originalPathItemObj); + var originalPathItem = (IShellItem)originalPathItemObj; // Define the shell item to restore - hr = pFileOperation.Get()->MoveItem(pShellItem.Get(), pOriginalPathShellItem, default(PCWSTR), null); + hr = fileOperation.MoveItem(childItem, originalPathItem, default, null); } // Perform - hr = pFileOperation.Get()->PerformOperations(); + hr = fileOperation.PerformOperations(); // Reset the icon PInvoke.SHUpdateRecycleBinIcon(); diff --git a/src/Files.App/Services/Windows/WindowsDialogService.cs b/src/Files.App/Services/Windows/WindowsDialogService.cs index 20612523bd0a..0004d1c60743 100644 --- a/src/Files.App/Services/Windows/WindowsDialogService.cs +++ b/src/Files.App/Services/Windows/WindowsDialogService.cs @@ -22,9 +22,9 @@ public unsafe bool Open_FileOpenDialog(nint hWnd, bool pickFoldersOnly, string[] try { - using ComPtr pDialog = default; - HRESULT hr = pDialog.CoCreateInstance(CLSID.CLSID_FileOpenDialog, null, CLSCTX.CLSCTX_INPROC_SERVER); - + HRESULT hr = PInvoke.CoCreateInstance(CLSID.CLSID_FileOpenDialog, null, CLSCTX.CLSCTX_INPROC_SERVER, IID.IID_IFileOpenDialog, out var dialogObj); + var dialog = (IFileOpenDialog)dialogObj; + // Handle COM creation failure gracefully if (hr.Failed) { @@ -48,40 +48,37 @@ public unsafe bool Open_FileOpenDialog(nint hWnd, bool pickFoldersOnly, string[] } // Set the file type using the extension list - pDialog.Get()->SetFileTypes(extensions.ToArray()); + dialog.SetFileTypes(extensions.ToArray()); } // Get the default shell folder (My Computer) - using ComPtr pDefaultFolderShellItem = default; - fixed (char* pszDefaultFolderPath = Environment.GetFolderPath(defaultFolder)) + hr = PInvoke.SHCreateItemFromParsingName( + Environment.GetFolderPath(defaultFolder), + null, + typeof(IShellItem).GUID, + out var defaultFolderShellItemObj); + var defaultFolderShellItem = (IShellItem)defaultFolderShellItemObj; + + // Handle shell item creation failure gracefully + if (hr.Failed) { - hr = PInvoke.SHCreateItemFromParsingName( - pszDefaultFolderPath, - null, - IID.IID_IShellItem, - (void**)pDefaultFolderShellItem.GetAddressOf()); - - // Handle shell item creation failure gracefully - if (hr.Failed) - { - App.Logger.LogWarning("Failed to create shell item for default folder '{0}'. HRESULT: 0x{1:X8}. Dialog will open without default folder.", Environment.GetFolderPath(defaultFolder), hr.Value); - // Continue without setting default folder rather than failing completely - } + App.Logger.LogWarning("Failed to create shell item for default folder '{0}'. HRESULT: 0x{1:X8}. Dialog will open without default folder.", Environment.GetFolderPath(defaultFolder), hr.Value); + // Continue without setting default folder rather than failing completely } // Folder picker if (pickFoldersOnly) - pDialog.Get()->SetOptions(FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS); + dialog.SetOptions(FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS); // Set the default folder to open in the dialog (only if creation succeeded) - if (pDefaultFolderShellItem.Get() is not null) + if (defaultFolderShellItem is not null) { - pDialog.Get()->SetFolder(pDefaultFolderShellItem.Get()); - pDialog.Get()->SetDefaultFolder(pDefaultFolderShellItem.Get()); + dialog.SetFolder(defaultFolderShellItem); + dialog.SetDefaultFolder(defaultFolderShellItem); } // Show the dialog - hr = pDialog.Get()->Show(new HWND(hWnd)); + hr = dialog.Show(new HWND(hWnd)); if (hr.Value == unchecked((int)0x800704C7)) // HRESULT_FROM_WIN32(ERROR_CANCELLED) return false; @@ -93,12 +90,11 @@ public unsafe bool Open_FileOpenDialog(nint hWnd, bool pickFoldersOnly, string[] } // Get the file that user chose - using ComPtr pResultShellItem = default; - pDialog.Get()->GetResult(pResultShellItem.GetAddressOf()); - if (pResultShellItem.Get() is null) + dialog.GetResult(out var resultShellItem); + if (resultShellItem is null) throw new COMException("FileOpenDialog returned invalid shell item."); - pResultShellItem.Get()->GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var lpFilePath); - filePath = lpFilePath.ToString(); + resultShellItem.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var resultFilePath); + filePath = resultFilePath.ToString(); return true; } @@ -121,9 +117,9 @@ public unsafe bool Open_FileSaveDialog(nint hWnd, bool pickFoldersOnly, string[] try { - using ComPtr pDialog = default; - HRESULT hr = pDialog.CoCreateInstance(CLSID.CLSID_FileSaveDialog, null, CLSCTX.CLSCTX_INPROC_SERVER); - + HRESULT hr = PInvoke.CoCreateInstance(CLSID.CLSID_FileSaveDialog, null, CLSCTX.CLSCTX_INPROC_SERVER, IID.IID_IFileSaveDialog, out var dialogObj); + var dialog = (IFileSaveDialog)dialogObj; + // Handle COM creation failure gracefully if (hr.Failed) { @@ -147,40 +143,37 @@ public unsafe bool Open_FileSaveDialog(nint hWnd, bool pickFoldersOnly, string[] } // Set the file type using the extension list - pDialog.Get()->SetFileTypes(extensions.ToArray()); + dialog.SetFileTypes(extensions.ToArray()); } // Get the default shell folder (My Computer) - using ComPtr pDefaultFolderShellItem = default; - fixed (char* pszDefaultFolderPath = Environment.GetFolderPath(defaultFolder)) + hr = PInvoke.SHCreateItemFromParsingName( + Environment.GetFolderPath(defaultFolder), + null, + typeof(IShellItem).GUID, + out var defaultFolderShellItemObj); + var defaultFolderShellItem = (IShellItem)defaultFolderShellItemObj; + + // Handle shell item creation failure gracefully + if (hr.Failed) { - hr = PInvoke.SHCreateItemFromParsingName( - pszDefaultFolderPath, - null, - IID.IID_IShellItem, - (void**)pDefaultFolderShellItem.GetAddressOf()); - - // Handle shell item creation failure gracefully - if (hr.Failed) - { - App.Logger.LogWarning("Failed to create shell item for default folder '{0}'. HRESULT: 0x{1:X8}. Dialog will open without default folder.", Environment.GetFolderPath(defaultFolder), hr.Value); - // Continue without setting default folder rather than failing completely - } + App.Logger.LogWarning("Failed to create shell item for default folder '{0}'. HRESULT: 0x{1:X8}. Dialog will open without default folder.", Environment.GetFolderPath(defaultFolder), hr.Value); + // Continue without setting default folder rather than failing completely } // Folder picker if (pickFoldersOnly) - pDialog.Get()->SetOptions(FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS); + dialog.SetOptions(FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS); // Set the default folder to open in the dialog (only if creation succeeded) - if (pDefaultFolderShellItem.Get() is not null) + if (defaultFolderShellItem is not null) { - pDialog.Get()->SetFolder(pDefaultFolderShellItem.Get()); - pDialog.Get()->SetDefaultFolder(pDefaultFolderShellItem.Get()); + dialog.SetFolder(defaultFolderShellItem); + dialog.SetDefaultFolder(defaultFolderShellItem); } // Show the dialog - hr = pDialog.Get()->Show(new HWND(hWnd)); + hr = dialog.Show(new HWND(hWnd)); if (hr.Value == unchecked((int)0x800704C7)) // HRESULT_FROM_WIN32(ERROR_CANCELLED) return false; @@ -192,12 +185,11 @@ public unsafe bool Open_FileSaveDialog(nint hWnd, bool pickFoldersOnly, string[] } // Get the file that user chose - using ComPtr pResultShellItem = default; - pDialog.Get()->GetResult(pResultShellItem.GetAddressOf()); - if (pResultShellItem.Get() is null) + dialog.GetResult(out var resultShellItem); + if (resultShellItem is null) throw new COMException("FileSaveDialog returned invalid shell item."); - pResultShellItem.Get()->GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var lpFilePath); - filePath = lpFilePath.ToString(); + resultShellItem.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var resultFilePath); + filePath = resultFilePath.ToString(); return true; } diff --git a/src/Files.App/Services/Windows/WindowsRecentItemsService.cs b/src/Files.App/Services/Windows/WindowsRecentItemsService.cs index 7668078bd408..55b86a0ea968 100644 --- a/src/Files.App/Services/Windows/WindowsRecentItemsService.cs +++ b/src/Files.App/Services/Windows/WindowsRecentItemsService.cs @@ -121,10 +121,10 @@ public unsafe bool Remove(RecentItem item) { try { - using ComPtr pContextMenu = default; - HRESULT hr = item.ShellItem.Get()->BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IContextMenu, (void**)pContextMenu.GetAddressOf()); + HRESULT hr = item.ShellItem.BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IContextMenu, out var contextMenuObj); + var contextMenu = (IContextMenu)contextMenuObj; HMENU hMenu = PInvoke.CreatePopupMenu(); - hr = pContextMenu.Get()->QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE); + hr = contextMenu.QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE); // Initialize invocation info CMINVOKECOMMANDINFO cmi = default; @@ -132,19 +132,19 @@ public unsafe bool Remove(RecentItem item) cmi.nShow = (int)SHOW_WINDOW_CMD.SW_HIDE; // Unpin the item - fixed (byte* pVerb1 = Encoding.ASCII.GetBytes("remove"), - pVerb2 = Encoding.ASCII.GetBytes("unpinfromhome"), - pVerb3 = Encoding.ASCII.GetBytes("removefromhome")) + fixed (byte* verb1 = Encoding.ASCII.GetBytes("remove"), + verb2 = Encoding.ASCII.GetBytes("unpinfromhome"), + verb3 = Encoding.ASCII.GetBytes("removefromhome")) { // Try unpin files - cmi.lpVerb = new(pVerb1); - hr = pContextMenu.Get()->InvokeCommand(cmi); + cmi.lpVerb = new(verb1); + hr = contextMenu.InvokeCommand(cmi); if (hr == HRESULT.S_OK) return true; // Try unpin folders - cmi.lpVerb = new(pVerb2); - hr = pContextMenu.Get()->InvokeCommand(cmi); + cmi.lpVerb = new(verb2); + hr = contextMenu.InvokeCommand(cmi); if (hr == HRESULT.S_OK) return true; @@ -152,8 +152,8 @@ public unsafe bool Remove(RecentItem item) // There seems to be an issue with unpinfromhome where some shell folders // won't be removed via unpinfromhome verb. // Try unpin folders again - cmi.lpVerb = new(pVerb3); - hr = pContextMenu.Get()->InvokeCommand(cmi); + cmi.lpVerb = new(verb3); + hr = contextMenu.InvokeCommand(cmi); if (hr == HRESULT.S_OK) return true; } @@ -189,44 +189,45 @@ private unsafe bool UpdateRecentItems(bool isFolder) { HRESULT hr = default; - string szFolderShellPath = + string folderShellPath = isFolder ? "Shell:::{22877A6D-37A1-461A-91B0-DBDA5AAEBC99}" // Recent Places folder (recent folders) : "Shell:::{679F85CB-0220-4080-B29B-5540CC05AAB6}"; // Quick Access folder (recent files) // Get IShellItem of the shell folder - using ComPtr pFolderShellItem = default; - fixed (char* pszFolderShellPath = szFolderShellPath) - hr = PInvoke.SHCreateItemFromParsingName(pszFolderShellPath, null, IID.IID_IShellItem, (void**)pFolderShellItem.GetAddressOf()); + hr = PInvoke.SHCreateItemFromParsingName(folderShellPath, null, typeof(IShellItem).GUID, out var folderShellItemObj); + var folderShellItem = (IShellItem)folderShellItemObj; // Get IEnumShellItems of the quick access shell folder - using ComPtr pEnumShellItems = default; - hr = pFolderShellItem.Get()->BindToHandler(null, BHID.BHID_EnumItems, IID.IID_IEnumShellItems, (void**)pEnumShellItems.GetAddressOf()); + hr = folderShellItem.BindToHandler(null, BHID.BHID_EnumItems, IID.IID_IEnumShellItems, out var enumShellItemsObj); + var enumShellItems = (IEnumShellItems)enumShellItemsObj; // Enumerate recent items and populate the list int index = 0; List recentItems = []; - ComPtr pShellItem = default; // Do not dispose in this method to use later to prepare for its deletion - while (pEnumShellItems.Get()->Next(1, pShellItem.GetAddressOf()) == HRESULT.S_OK) + var shellItemArray = new IShellItem[1]; + while (enumShellItems.Next(1, shellItemArray) == HRESULT.S_OK) { + var shellItem = shellItemArray[0]; + // Get top 20 items if (index is 20) break; // Exclude folders - if (pShellItem.Get()->GetAttributes(SFGAO_FLAGS.SFGAO_FOLDER, out var attribute) == HRESULT.S_OK && + if (shellItem.GetAttributes(SFGAO_FLAGS.SFGAO_FOLDER, out var attribute) == HRESULT.S_OK && (attribute & SFGAO_FLAGS.SFGAO_FOLDER) == SFGAO_FLAGS.SFGAO_FOLDER) continue; // Get the target path - pShellItem.Get()->GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEEDITING, out var szDisplayName); - var targetPath = szDisplayName.ToString(); - PInvoke.CoTaskMemFree(szDisplayName.Value); + shellItem.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEEDITING, out var displayName); + var targetPath = displayName.ToString(); + PInvoke.CoTaskMemFree(displayName.Value); // Get the display name - pShellItem.Get()->GetDisplayName(SIGDN.SIGDN_NORMALDISPLAY, out szDisplayName); - var fileName = szDisplayName.ToString(); - PInvoke.CoTaskMemFree(szDisplayName.Value); + shellItem.GetDisplayName(SIGDN.SIGDN_NORMALDISPLAY, out displayName); + var fileName = displayName.ToString(); + PInvoke.CoTaskMemFree(displayName.Value); // Strip the file extension except when the file name only contains extension (e.g. ".gitignore") if (!FoldersSettingsService.ShowFileExtensions && @@ -234,18 +235,17 @@ private unsafe bool UpdateRecentItems(bool isFolder) fileName = string.IsNullOrEmpty(fileNameWithoutExtension) ? SystemIO.Path.GetFileName(fileName) : fileNameWithoutExtension; // Get the date last modified - using ComPtr pShellItem2 = default; - hr = pShellItem.Get()->QueryInterface(IID.IID_IShellItem2, (void**)pShellItem2.GetAddressOf()); + var shellItem2 = (IShellItem2)shellItem; hr = PInvoke.PSGetPropertyKeyFromName("System.DateModified", out var propertyKey); - hr = pShellItem2.Get()->GetString(propertyKey, out var szPropertyValue); - if (DateTime.TryParse(szPropertyValue.ToString(), out var lastModified)) + hr = shellItem2.GetString(propertyKey, out var propertyValue); + if (DateTime.TryParse(propertyValue.ToString(), out var lastModified)) lastModified = DateTime.MinValue; recentItems.Add(new() { Path = targetPath, Name = fileName, - ShellItem = pShellItem, + ShellItem = shellItem, LastModified = lastModified, }); diff --git a/src/Files.App/Services/Windows/WindowsWallpaperService.cs b/src/Files.App/Services/Windows/WindowsWallpaperService.cs index be2f18069759..4c196d689a9a 100644 --- a/src/Files.App/Services/Windows/WindowsWallpaperService.cs +++ b/src/Files.App/Services/Windows/WindowsWallpaperService.cs @@ -14,62 +14,61 @@ namespace Files.App.Services public sealed class WindowsWallpaperService : IWindowsWallpaperService { /// - public unsafe void SetDesktopWallpaper(string szPath) + public unsafe void SetDesktopWallpaper(string path) { // Instantiate IDesktopWallpaper - using ComPtr pDesktopWallpaper = default; - HRESULT hr = pDesktopWallpaper.CoCreateInstance(CLSID.CLSID_DesktopWallpaper); + HRESULT hr = PInvoke.CoCreateInstance(CLSID.CLSID_DesktopWallpaper, null, Windows.Win32.System.Com.CLSCTX.CLSCTX_ALL, IID.IID_IDesktopWallpaper, out var desktopWallpaperObj); + var desktopWallpaper = (IDesktopWallpaper)desktopWallpaperObj; // Get total count of all available monitors - hr = pDesktopWallpaper.Get()->GetMonitorDevicePathCount(out var dwMonitorCount); + hr = desktopWallpaper.GetMonitorDevicePathCount(out var monitorCount); - fixed (char* pszPath = szPath) + fixed (char* pathPtr = path) { - PWSTR pMonitorId = default; + PWSTR monitorId = default; // Set the selected image file as wallpaper for all available monitors - for (uint dwIndex = 0u; dwIndex < dwMonitorCount; dwIndex++) + for (uint index = 0u; index < monitorCount; index++) { // Set the wallpaper - hr = pDesktopWallpaper.Get()->GetMonitorDevicePathAt(dwIndex, &pMonitorId); - hr = pDesktopWallpaper.Get()->SetWallpaper(pMonitorId, pszPath); + hr = desktopWallpaper.GetMonitorDevicePathAt(index, &monitorId); + hr = desktopWallpaper.SetWallpaper(monitorId, pathPtr); - pMonitorId = default; + monitorId = default; } } } /// - public unsafe void SetDesktopSlideshow(string[] aszPaths) + public unsafe void SetDesktopSlideshow(string[] paths) { // Instantiate IDesktopWallpaper - using ComPtr pDesktopWallpaper = default; - HRESULT hr = pDesktopWallpaper.CoCreateInstance(CLSID.CLSID_DesktopWallpaper); + HRESULT hr = PInvoke.CoCreateInstance(CLSID.CLSID_DesktopWallpaper, null, Windows.Win32.System.Com.CLSCTX.CLSCTX_ALL, IID.IID_IDesktopWallpaper, out var desktopWallpaperObj); + var desktopWallpaper = (IDesktopWallpaper)desktopWallpaperObj; - uint dwCount = (uint)aszPaths.Length; - ITEMIDLIST** ppItemIdList = stackalloc ITEMIDLIST*[aszPaths.Length]; + uint count = (uint)paths.Length; + ITEMIDLIST** itemIdList = stackalloc ITEMIDLIST*[paths.Length]; // Get an array of PIDL from the selected image files - for (uint dwIndex = 0u; dwIndex < dwCount; dwIndex++) - ppItemIdList[dwIndex] = PInvoke.ILCreateFromPath(aszPaths[dwIndex]); + for (uint index = 0u; index < count; index++) + itemIdList[index] = PInvoke.ILCreateFromPath(paths[index]); // Get an IShellItemArray from the array of the PIDL - using ComPtr pShellItemArray = default; - hr = PInvoke.SHCreateShellItemArrayFromIDLists(dwCount, ppItemIdList, pShellItemArray.GetAddressOf()); + hr = PInvoke.SHCreateShellItemArrayFromIDLists(count, itemIdList, out var shellItemArray); // Release the allocated PIDL - for (uint dwIndex = 0u; dwIndex < dwCount; dwIndex++) - PInvoke.CoTaskMemFree((void*)ppItemIdList[dwIndex]); + for (uint index = 0u; index < count; index++) + PInvoke.CoTaskMemFree((void*)itemIdList[index]); // Set the slideshow and its position - hr = pDesktopWallpaper.Get()->SetSlideshow(pShellItemArray.Get()); - hr = pDesktopWallpaper.Get()->SetPosition(DESKTOP_WALLPAPER_POSITION.DWPOS_FILL); + hr = desktopWallpaper.SetSlideshow(shellItemArray); + hr = desktopWallpaper.SetPosition(DESKTOP_WALLPAPER_POSITION.DWPOS_FILL); } /// - public async Task SetLockScreenWallpaper(string szPath) + public async Task SetLockScreenWallpaper(string path) { - IStorageFile sourceFile = await StorageFile.GetFileFromPathAsync(szPath); + IStorageFile sourceFile = await StorageFile.GetFileFromPathAsync(path); await LockScreen.SetImageFileAsync(sourceFile); } } diff --git a/src/Files.App/Utils/Shell/LaunchHelper.cs b/src/Files.App/Utils/Shell/LaunchHelper.cs index 634b326a2f4c..6edbc346e0e9 100644 --- a/src/Files.App/Utils/Shell/LaunchHelper.cs +++ b/src/Files.App/Utils/Shell/LaunchHelper.cs @@ -18,10 +18,10 @@ public static class LaunchHelper { public unsafe static void LaunchSettings(string page) { - using ComPtr pApplicationActivationManager = default; - pApplicationActivationManager.CoCreateInstance(CLSID.CLSID_ApplicationActivationManager); + Windows.Win32.Foundation.HRESULT hr = PInvoke.CoCreateInstance(CLSID.CLSID_ApplicationActivationManager, null, Windows.Win32.System.Com.CLSCTX.CLSCTX_ALL, IID.IID_IApplicationActivationManager, out var pApplicationActivationManagerObj); + var pApplicationActivationManager = (IApplicationActivationManager)pApplicationActivationManagerObj; - pApplicationActivationManager.Get()->ActivateApplication( + pApplicationActivationManager.ActivateApplication( "windows.immersivecontrolpanel_cw5n1h2txyewy!microsoft.windows.immersivecontrolpanel", page, ACTIVATEOPTIONS.AO_NONE, diff --git a/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs b/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs index 042fb8564e1a..62e9646983b3 100644 --- a/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs +++ b/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs @@ -5,45 +5,35 @@ using Windows.Win32; using Windows.Win32.System.Com; using Windows.Win32.System.WinRT; -using WinRT; namespace Files.App.Utils.Storage { internal static class SyncRootHelpers { - private static unsafe (bool Success, ulong Capacity, ulong Used) GetSyncRootQuotaFromSyncRootId(string syncRootId) + private static (bool Success, ulong Capacity, ulong Used) GetSyncRootQuotaFromSyncRootId(string syncRootId) { 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); - ulong ulTotalSize = 0ul, ulUsedSize = 0ul; - using ComPtr pStorageProviderStatusUISourceFactory = default; - using ComPtr pStorageProviderStatusUISource = default; - using ComPtr pStorageProviderStatusUI = default; - using ComPtr pStorageProviderQuotaUI = default; + ulong totalSize = 0ul, usedSize = 0ul; if (PInvoke.CoCreateInstance( - &factoryClsid, + factoryClsid, null, CLSCTX.CLSCTX_LOCAL_SERVER, - IID.IID_IStorageProviderStatusUISourceFactory, - (void**)pStorageProviderStatusUISourceFactory.GetAddressOf()).ThrowIfFailedOnDebug().Failed) + out IStorageProviderStatusUISourceFactory statusUISourceFactory).ThrowIfFailedOnDebug().Failed) return (false, 0, 0); - 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); - } + if (statusUISourceFactory.GetStatusUISource(syncRootId, out var statusUISource).ThrowIfFailedOnDebug().Failed || + statusUISource.GetStatusUI(out var statusUI).ThrowIfFailedOnDebug().Failed || + statusUI.get_QuotaUI(out var quotaUI).ThrowIfFailedOnDebug().Failed || + quotaUI.get_QuotaTotalInBytes(out totalSize).ThrowIfFailedOnDebug().Failed || + quotaUI.get_QuotaUsedInBytes(out usedSize).ThrowIfFailedOnDebug().Failed) + return (false, 0, 0); - return (true, ulTotalSize, ulUsedSize); + return (true, totalSize, usedSize); } public static async Task<(bool Success, ulong Capacity, ulong Used)> GetSyncRootQuotaAsync(string path) diff --git a/src/Files.App/Utils/Taskbar/SystemTrayIconWindow.cs b/src/Files.App/Utils/Taskbar/SystemTrayIconWindow.cs index 532ed33baf5f..0caec4cf75a4 100644 --- a/src/Files.App/Utils/Taskbar/SystemTrayIconWindow.cs +++ b/src/Files.App/Utils/Taskbar/SystemTrayIconWindow.cs @@ -17,7 +17,7 @@ public sealed partial class SystemTrayIconWindow : IDisposable { private SystemTrayIcon _trayIcon; - private readonly WNDPROC _windowProcedure; + private readonly WndProcDelegate _windowProcedure; private HWND _windowHandle; internal HWND WindowHandle diff --git a/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs b/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs index 5c550e0d1c80..9c97bcb104c2 100644 --- a/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs @@ -31,7 +31,7 @@ public sealed partial class ShellPreviewViewModel : BasePreviewModel ContentExternalOutputLink? _contentExternalOutputLink; PreviewHandler? _previewHandler; WNDCLASSEXW _windowClass; - WNDPROC _windProc = null!; + WndProcDelegate _windProc = null!; HWND _hWnd = HWND.Null; bool _isOfficePreview = false; @@ -186,13 +186,10 @@ private unsafe bool ChildWindowToXaml(nint parent, UIElement presenter) ]; HRESULT hr = default; - Guid IID_IDCompositionDevice = typeof(IDCompositionDevice).GUID; - using ComPtr pD3D11Device = default; - using ComPtr pD3D11DeviceContext = default; - using ComPtr pDXGIDevice = default; - using ComPtr pDCompositionDevice = default; - using ComPtr pControlSurface = default; - ComPtr pChildVisual = default; // Don't dispose this one, it's used by the compositor + ID3D11Device d3d11Device = null; + ID3D11DeviceContext d3d11DeviceContext = null; + IDCompositionVisual childVisual = null; // Don't dispose this one, it's used by the compositor + object controlSurface = null; // Create the D3D11 device foreach (var driverType in driverTypes) @@ -201,30 +198,31 @@ private unsafe bool ChildWindowToXaml(nint parent, UIElement presenter) null, driverType, new(nint.Zero), D3D11_CREATE_DEVICE_FLAG.D3D11_CREATE_DEVICE_BGRA_SUPPORT, null, /* FeatureLevels */ 0, /* SDKVersion */ 7, - pD3D11Device.GetAddressOf(), null, - pD3D11DeviceContext.GetAddressOf()); + out d3d11Device, null, + out d3d11DeviceContext); if (hr.Succeeded) break; } - if (pD3D11Device.IsNull) + if (d3d11Device is null) return false; // Create the DComp device - pDXGIDevice.Attach((IDXGIDevice*)pD3D11Device.Get()); + Guid IID_IDCompositionDevice = typeof(IDCompositionDevice).GUID; hr = PInvoke.DCompositionCreateDevice( - pDXGIDevice.Get(), - &IID_IDCompositionDevice, - (void**)pDCompositionDevice.GetAddressOf()); + (IDXGIDevice)d3d11Device, + in IID_IDCompositionDevice, + out var compositionDeviceObj); + var compositionDevice = (IDCompositionDevice)compositionDeviceObj; if (hr.Failed) return false; // Create the visual - hr = pDCompositionDevice.Get()->CreateVisual(pChildVisual.GetAddressOf()); - hr = pDCompositionDevice.Get()->CreateSurfaceFromHwnd(_hWnd, pControlSurface.GetAddressOf()); - hr = pChildVisual.Get()->SetContent(pControlSurface.Get()); - if (pChildVisual.IsNull || pControlSurface.IsNull) + hr = compositionDevice.CreateVisual(out childVisual); + hr = compositionDevice.CreateSurfaceFromHwnd(_hWnd, out controlSurface); + hr = childVisual.SetContent(controlSurface); + if (childVisual is null || controlSurface is null) return false; // Get the compositor and set the visual on it @@ -232,14 +230,14 @@ private unsafe bool ChildWindowToXaml(nint parent, UIElement presenter) _contentExternalOutputLink = ContentExternalOutputLink.Create(compositor); var target = _contentExternalOutputLink.As(); - target.SetRoot((nint)pChildVisual.Get()); + target.SetRoot(Marshal.GetIUnknownForObject(childVisual)); _contentExternalOutputLink.PlacementVisual.Size = new(0, 0); _contentExternalOutputLink.PlacementVisual.Scale = new(1 / (float)presenter.XamlRoot.RasterizationScale); ElementCompositionPreview.SetElementChildVisual(presenter, _contentExternalOutputLink.PlacementVisual); // Commit the all pending DComp commands - pDCompositionDevice.Get()->Commit(); + compositionDevice.Commit(); var dwAttrib = Convert.ToUInt32(true); diff --git a/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs b/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs index 34978feb89f1..35a09d8fc31e 100644 --- a/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs @@ -204,11 +204,11 @@ public override async Task ExecutePinToSidebarCommand(WidgetCardItem? item) return; HRESULT hr = default; - using ComPtr pAgileReference = default; + IAgileReference agileReference; unsafe { - hr = PInvoke.RoGetAgileReference(AgileReferenceOptions.AGILEREFERENCE_DEFAULT, IID.IID_IShellItem, (IUnknown*)folderCardItem.Item.ThisPtr, pAgileReference.GetAddressOf()); + hr = PInvoke.RoGetAgileReference(AgileReferenceOptions.AGILEREFERENCE_DEFAULT, IID.IID_IShellItem, folderCardItem.Item.ThisPtr, out agileReference); } // Pin to Quick Access on Windows @@ -216,9 +216,10 @@ public override async Task ExecutePinToSidebarCommand(WidgetCardItem? item) { unsafe { - IShellItem* pShellItem = null; - hr = pAgileReference.Get()->Resolve(IID.IID_IShellItem, (void**)&pShellItem); - using var windowsFile = new WindowsFile(pShellItem); + hr = agileReference.Resolve(IID.IID_IShellItem, out var itemObj); + var item = (IShellItem)itemObj; + using var windowsFile = new WindowsFile(item); + // NOTE: "pintohome" is an undocumented verb, which calls an undocumented COM class, windows.storage.dll!CPinToFrequentExecute : public IExecuteCommand, ... return windowsFile.TryInvokeContextMenuVerb("pintohome"); } @@ -233,11 +234,11 @@ public override async Task ExecuteUnpinFromSidebarCommand(WidgetCardItem? item) return; HRESULT hr = default; - using ComPtr pAgileReference = default; + IAgileReference agileReference; unsafe { - hr = PInvoke.RoGetAgileReference(AgileReferenceOptions.AGILEREFERENCE_DEFAULT, IID.IID_IShellItem, (IUnknown*)folderCardItem.Item.ThisPtr, pAgileReference.GetAddressOf()); + hr = PInvoke.RoGetAgileReference(AgileReferenceOptions.AGILEREFERENCE_DEFAULT, IID.IID_IShellItem, folderCardItem.Item.ThisPtr, out agileReference); } // Unpin from Quick Access on Windows @@ -245,9 +246,9 @@ public override async Task ExecuteUnpinFromSidebarCommand(WidgetCardItem? item) { unsafe { - IShellItem* pShellItem = null; - hr = pAgileReference.Get()->Resolve(IID.IID_IShellItem, (void**)&pShellItem); - using var windowsFile = new WindowsFile(pShellItem); + hr = agileReference.Resolve(IID.IID_IShellItem, out var itemObj); + var item = (IShellItem)itemObj; + using var windowsFile = new WindowsFile(item); // NOTE: "unpinfromhome" is an undocumented verb, which calls an undocumented COM class, windows.storage.dll!CRemoveFromFrequentPlacesExecute : public IExecuteCommand, ... // NOTE: "remove" is for some shell folders where the "unpinfromhome" may not work diff --git a/src/Files.App/ViewModels/UserControls/Widgets/RecentFilesWidgetViewModel.cs b/src/Files.App/ViewModels/UserControls/Widgets/RecentFilesWidgetViewModel.cs index 4d7b7bc8e2d3..fa91fa94cc51 100644 --- a/src/Files.App/ViewModels/UserControls/Widgets/RecentFilesWidgetViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/Widgets/RecentFilesWidgetViewModel.cs @@ -363,9 +363,6 @@ private void ExecuteOpenPropertiesCommand(RecentItem? item) public void Dispose() { WindowsRecentItemsService.RecentFilesChanged -= Manager_RecentFilesChanged; - - foreach (var item in Items) - item.Dispose(); } } }