From 15f5dc45a65cee694042d579b220276e8d39d9df Mon Sep 17 00:00:00 2001
From: 0x5BFA <62196528+0x5bfa@users.noreply.github.com>
Date: Sat, 4 Jul 2026 00:44:54 +0900
Subject: [PATCH] Init
---
Directory.Packages.props | 2 +-
src/Files.App.CsWin32/ComHelpers.cs | 24 ++
src/Files.App.CsWin32/ComPtr`1.cs | 96 -----
src/Files.App.CsWin32/Extras.cs | 24 +-
.../Files.App.CsWin32.csproj | 1 +
.../HStringStringMarshaller.cs | 122 +++++++
src/Files.App.CsWin32/IDetectionAndSharing.cs | 64 ++--
src/Files.App.CsWin32/IOpenControlPanel.cs | 20 +-
.../IStorageProviderQuotaUI.cs | 44 ++-
.../IStorageProviderStatusUI.cs | 75 +++-
.../IStorageProviderStatusUISource.cs | 38 +-
.../IStorageProviderStatusUISourceFactory.cs | 29 +-
src/Files.App.CsWin32/ManualGuid.cs | 122 +------
src/Files.App.CsWin32/NativeMethods.json | 3 +-
src/Files.App.CsWin32/NativeMethods.txt | 13 +
src/Files.App.Server/Helpers.cs | 8 +-
src/Files.App.Server/Program.cs | 6 +-
.../Helpers/WindowsStorableHelpers.Icon.cs | 25 +-
.../Helpers/WindowsStorableHelpers.Shell.cs | 175 +++++-----
.../Windows/IWindowsFolder.cs | 6 +-
.../Windows/IWindowsStorable.cs | 8 +-
.../Windows/Managers/SystemTrayManager.cs | 1 +
.../Windows/Managers/TaskbarManager.cs | 22 +-
.../Windows/Managers/WindowsDriveManager.cs | 2 +-
.../Managers/WindowsFolderChangeWatcher.cs | 1 +
.../Windows/Managers/WindowsObjectPicker.cs | 50 ++-
.../Windows/WindowsBulkOperations.cs | 38 +-
.../WindowsBulkOperationsSink.Methods.cs | 59 ++--
.../WindowsBulkOperationsSink.VTable.cs | 161 ---------
src/Files.App.Storage/Windows/WindowsFile.cs | 6 +-
.../Windows/WindowsFolder.cs | 29 +-
.../Windows/WindowsStorable.cs | 38 +-
src/Files.App/Data/Items/WidgetRecentItem.cs | 6 +-
src/Files.App/Data/Items/WindowEx.cs | 2 +
.../Storage/StorageTrashBinService.cs | 66 ++--
.../Services/Windows/WindowsDialogService.cs | 102 +++---
.../Windows/WindowsRecentItemsService.cs | 61 ++--
.../Windows/WindowsWallpaperService.cs | 25 +-
.../Utils/Shell/DetectionAndSharingHelper.cs | 24 +-
src/Files.App/Utils/Shell/ItemStreamHelper.cs | 31 +-
src/Files.App/Utils/Shell/LaunchHelper.cs | 8 +-
src/Files.App/Utils/Shell/OpenWithMenu.cs | 66 +---
src/Files.App/Utils/Shell/PreviewHandler.cs | 330 ++++--------------
.../Utils/Storage/Helpers/MtpHelpers.cs | 32 +-
.../Utils/Storage/Helpers/SyncRootHelpers.cs | 33 +-
.../Utils/Taskbar/SystemTrayIconWindow.cs | 1 +
.../Previews/ShellPreviewViewModel.cs | 50 +--
.../Widgets/QuickAccessWidgetViewModel.cs | 54 ++-
.../Generators/VTableFunctionGenerator.cs | 115 ------
.../GeneratedVTableFunctionAttribute.cs | 12 -
50 files changed, 944 insertions(+), 1386 deletions(-)
create mode 100644 src/Files.App.CsWin32/ComHelpers.cs
delete mode 100644 src/Files.App.CsWin32/ComPtr`1.cs
create mode 100644 src/Files.App.CsWin32/HStringStringMarshaller.cs
delete mode 100644 src/Files.App.Storage/Windows/WindowsBulkOperationsSink.VTable.cs
delete mode 100644 src/Files.Core.SourceGenerator/Generators/VTableFunctionGenerator.cs
delete mode 100644 src/Files.Shared/Attributes/GeneratedVTableFunctionAttribute.cs
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 4da5c20e20c9..ddda8e9d3b77 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -43,7 +43,7 @@
-
+
diff --git a/src/Files.App.CsWin32/ComHelpers.cs b/src/Files.App.CsWin32/ComHelpers.cs
new file mode 100644
index 000000000000..6febcaa134ff
--- /dev/null
+++ b/src/Files.App.CsWin32/ComHelpers.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Files Community
+// SPDX-License-Identifier: MPL-2.0
+
+using System;
+using Windows.Win32.Foundation;
+using Windows.Win32.System.Com;
+using Windows.Win32.UI.Shell;
+
+namespace Windows.Win32;
+
+public static class ComHelpers
+{
+ public static HRESULT TryCast(object nativeObject, out TInterface? instance)
+ where TInterface : class
+ {
+ instance = null;
+
+ if (nativeObject is not TInterface casted)
+ return HRESULT.E_NOINTERFACE;
+
+ instance = casted;
+ return HRESULT.S_OK;
+ }
+}
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 67b62cf0e28d..10b91a4afc49 100644
--- a/src/Files.App.CsWin32/Extras.cs
+++ b/src/Files.App.CsWin32/Extras.cs
@@ -1,25 +1,15 @@
-// Copyright (c) Files Community
+// 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.Graphics.DirectComposition;
+using Windows.Win32.Graphics.Gdi;
using Windows.Win32.UI.WindowsAndMessaging;
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);
- }
-
- namespace UI.WindowsAndMessaging
- {
- [UnmanagedFunctionPointer(CallingConvention.Winapi)]
- public delegate LRESULT WNDPROC(HWND hWnd, uint msg, WPARAM wParam, LPARAM lParam);
- }
-
public static partial class PInvoke
{
[LibraryImport("User32", EntryPoint = "SetWindowLongW")]
@@ -46,11 +36,17 @@ public static unsafe nint SetWindowLongPtr(HWND hWnd, WINDOW_LONG_PTR_INDEX nInd
namespace Extras
{
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ public unsafe delegate BOOL ManagedMONITORENUMPROC([In] HMONITOR param0, [In] HDC param1, [In][Out] RECT* param2, [In] LPARAM param3);
+
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ public delegate LRESULT ManagedWNDPROC(HWND hWnd, uint msg, WPARAM wParam, LPARAM lParam);
+
[GeneratedComInterface, Guid("EACDD04C-117E-4E17-88F4-D1B12B0E3D89"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public partial interface IDCompositionTarget
{
[PreserveSig]
- int SetRoot(nint visual);
+ int SetRoot(IDCompositionVisual visual);
}
}
}
diff --git a/src/Files.App.CsWin32/Files.App.CsWin32.csproj b/src/Files.App.CsWin32/Files.App.CsWin32.csproj
index 2b9f3ea2b2f3..8772ede69e39 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
true
diff --git a/src/Files.App.CsWin32/HStringStringMarshaller.cs b/src/Files.App.CsWin32/HStringStringMarshaller.cs
new file mode 100644
index 000000000000..84ece6831d61
--- /dev/null
+++ b/src/Files.App.CsWin32/HStringStringMarshaller.cs
@@ -0,0 +1,122 @@
+// Copyright (c) Files Community
+// SPDX-License-Identifier: MPL-2.0
+
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+using Windows.Win32.Foundation;
+using Windows.Win32.System.WinRT;
+
+namespace Windows.Win32;
+
+[CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedIn, typeof(HStringStringMarshaller.ManagedToUnmanagedIn))]
+[CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedOut, typeof(HStringStringMarshaller.ManagedToUnmanagedOut))]
+[CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedIn, typeof(HStringStringMarshaller.UnmanagedToManagedIn))]
+[CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedOut, typeof(HStringStringMarshaller.UnmanagedToManagedOut))]
+internal static unsafe class HStringStringMarshaller
+{
+ public ref struct ManagedToUnmanagedIn
+ {
+ private nint _hstring;
+
+ public void FromManaged(string? managed)
+ {
+ _hstring = CreateHString(managed);
+ }
+
+ public nint ToUnmanaged()
+ => _hstring;
+
+ public void Free()
+ {
+ DeleteHString(_hstring);
+ }
+ }
+
+ public ref struct UnmanagedToManagedOut
+ {
+ private nint _hstring;
+
+ public void FromManaged(string? managed)
+ {
+ _hstring = CreateHString(managed);
+ }
+
+ public nint ToUnmanaged()
+ => _hstring;
+
+ public void Free()
+ {
+ }
+ }
+
+ public ref struct UnmanagedToManagedIn
+ {
+ private nint _hstring;
+
+ public void FromUnmanaged(nint unmanaged)
+ {
+ _hstring = unmanaged;
+ }
+
+ public string? ToManaged()
+ {
+ return ToManagedString(_hstring);
+ }
+
+ public void Free()
+ {
+ }
+ }
+
+ public ref struct ManagedToUnmanagedOut
+ {
+ private nint _hstring;
+
+ public void FromUnmanaged(nint unmanaged)
+ {
+ _hstring = unmanaged;
+ }
+
+ public string? ToManaged()
+ {
+ return ToManagedString(_hstring);
+ }
+
+ public void Free()
+ {
+ DeleteHString(_hstring);
+ }
+ }
+
+ private static nint CreateHString(string? managed)
+ {
+ if (managed is null)
+ return 0;
+
+ HSTRING hstring;
+ fixed (char* sourceString = managed)
+ {
+ HRESULT hr = PInvoke.WindowsCreateString(new(sourceString), checked((uint)managed.Length), &hstring);
+ if (hr.Failed)
+ Marshal.ThrowExceptionForHR(hr.Value);
+ }
+
+ return hstring;
+ }
+
+ private static string? ToManagedString(nint hstring)
+ {
+ if (hstring == 0)
+ return null;
+
+ uint length;
+ PCWSTR buffer = PInvoke.WindowsGetStringRawBuffer(new HSTRING(hstring), &length);
+ return new string((char*)buffer.Value, 0, checked((int)length));
+ }
+
+ private static void DeleteHString(nint hstring)
+ {
+ if (hstring != 0)
+ PInvoke.WindowsDeleteString(new HSTRING(hstring));
+ }
+}
diff --git a/src/Files.App.CsWin32/IDetectionAndSharing.cs b/src/Files.App.CsWin32/IDetectionAndSharing.cs
index b06562b4815a..ca0f3c0dc4ca 100644
--- a/src/Files.App.CsWin32/IDetectionAndSharing.cs
+++ b/src/Files.App.CsWin32/IDetectionAndSharing.cs
@@ -1,35 +1,45 @@
// Copyright (c) Files Community
// SPDX-License-Identifier: MPL-2.0
-using Files.Shared.Attributes;
using System;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
using Windows.Win32.Foundation;
-namespace Windows.Win32.UI.Shell
+namespace Windows.Win32.UI.Shell;
+
+[GeneratedComInterface, Guid("1FDA955C-61FF-11DA-978C-0008744FAAB7"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+public partial interface IDetectionAndSharing
+{
+ [PreserveSig]
+ HRESULT GetStatus(DTSH_TYPE type, out DTSH_STATE state, out DTSH_ACTION action);
+
+ [PreserveSig]
+ int TurnOn(nint hwnd, DTSH_TYPE type, int value);
+
+ [PreserveSig]
+ int GetCurrentFwProfile(out /*NetFwProfileType2*/ int profile);
+
+ [PreserveSig]
+ int GetStatusForProfile(/*NetFwProfileType2*/ int profile, DTSH_TYPE type, out DTSH_STATE state, out DTSH_ACTION action);
+
+ [PreserveSig]
+ int TurnOnForProfile(nint hwnd, /*NetFwProfileType2*/ int profile, DTSH_TYPE type, int value);
+}
+
+public enum DTSH_TYPE
+{
+ DTSH_NETWORK_DISCOVERY = 0,
+ DTSH_FILE_SHARING = 1,
+}
+
+public enum DTSH_STATE
+{
+ DTSH_OFF = 0,
+ DTSH_ON = 1,
+}
+
+public enum DTSH_ACTION
{
- public unsafe partial struct IDetectionAndSharing : IComIID
- {
- [GeneratedVTableFunction(Index = 3)]
- public partial HRESULT GetStatus(DTSH_TYPE type, DTSH_STATE* state, DTSH_ACTION* action);
-
- [GuidRVAGen.Guid("1FDA955C-61FF-11DA-978C-0008744FAAB7")]
- public static partial ref readonly Guid Guid { get; }
- }
-
- public enum DTSH_TYPE
- {
- DTSH_NETWORK_DISCOVERY = 0,
- DTSH_FILE_SHARING = 1,
- }
-
- public enum DTSH_STATE
- {
- DTSH_OFF = 0,
- DTSH_ON = 1,
- }
-
- public enum DTSH_ACTION
- {
- DTSH_NONE = 0,
- }
+ DTSH_NONE = 0,
}
diff --git a/src/Files.App.CsWin32/IOpenControlPanel.cs b/src/Files.App.CsWin32/IOpenControlPanel.cs
index 45036b1e4a92..72e9e33e7374 100644
--- a/src/Files.App.CsWin32/IOpenControlPanel.cs
+++ b/src/Files.App.CsWin32/IOpenControlPanel.cs
@@ -1,19 +1,19 @@
// Copyright (c) Files Community
// SPDX-License-Identifier: MPL-2.0
-using Files.Shared.Attributes;
using System;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
using Windows.Win32.Foundation;
-using Windows.Win32.System.Com;
-namespace Windows.Win32.UI.Shell
+namespace Windows.Win32.UI.Shell;
+
+[GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16), Guid("D11AD862-66DE-4DF4-BF6C-1F5621996AF1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+public unsafe partial interface IOpenControlPanel
{
- public unsafe partial struct IOpenControlPanel : IComIID
- {
- [GeneratedVTableFunction(Index = 3)]
- public partial HRESULT Open(char* name, char* page, void* site);
+ [PreserveSig]
+ HRESULT Open(PCWSTR name, PCWSTR page, void* site);
- [GuidRVAGen.Guid("D11AD862-66DE-4DF4-BF6C-1F5621996AF1")]
- public static partial ref readonly Guid Guid { get; }
- }
+ [PreserveSig]
+ HRESULT GetPath(string name, nint path, uint pathLength);
}
diff --git a/src/Files.App.CsWin32/IStorageProviderQuotaUI.cs b/src/Files.App.CsWin32/IStorageProviderQuotaUI.cs
index c7cd816b77fc..b620d5123220 100644
--- a/src/Files.App.CsWin32/IStorageProviderQuotaUI.cs
+++ b/src/Files.App.CsWin32/IStorageProviderQuotaUI.cs
@@ -1,21 +1,47 @@
-// Copyright (c) Files Community
+// 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, Guid("BA6295C3-312E-544F-9FD5-1F81B21F3649"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ public partial interface IStorageProviderQuotaUI
{
- [GeneratedVTableFunction(Index = 6)]
- public partial HRESULT GetQuotaTotalInBytes(ulong* value);
+ [PreserveSig]
+ HRESULT GetIids(out uint iidCount, out nint iids);
- [GeneratedVTableFunction(Index = 8)]
- public partial HRESULT GetQuotaUsedInBytes(ulong* value);
+ [PreserveSig]
+ HRESULT GetRuntimeClassName([MarshalUsing(typeof(global::Windows.Win32.HStringStringMarshaller))] out string? className);
- [GuidRVAGen.Guid("BA6295C3-312E-544F-9FD5-1F81B21F3649")]
- public static partial ref readonly Guid Guid { get; }
+ [PreserveSig]
+ HRESULT GetTrustLevel(out TrustLevel trustLevel);
+
+ [PreserveSig]
+ HRESULT GetQuotaTotalInBytes(out ulong value);
+
+ [PreserveSig]
+ HRESULT PutQuotaTotalInBytes(ulong value);
+
+ [PreserveSig]
+ HRESULT GetQuotaUsedInBytes(out ulong value);
+
+ [PreserveSig]
+ HRESULT PutQuotaUsedInBytes(ulong value);
+
+ [PreserveSig]
+ HRESULT GetQuotaUsedLabel([MarshalUsing(typeof(global::Windows.Win32.HStringStringMarshaller))] out string? value);
+
+ [PreserveSig]
+ HRESULT PutQuotaUsedLabel([MarshalUsing(typeof(global::Windows.Win32.HStringStringMarshaller))] string? value);
+
+ [PreserveSig]
+ HRESULT GetQuotaUsedColor(out nint value);
+
+ [PreserveSig]
+ HRESULT PutQuotaUsedColor(nint value);
}
}
diff --git a/src/Files.App.CsWin32/IStorageProviderStatusUI.cs b/src/Files.App.CsWin32/IStorageProviderStatusUI.cs
index 3aa60c4255f9..6e4bc121c63f 100644
--- a/src/Files.App.CsWin32/IStorageProviderStatusUI.cs
+++ b/src/Files.App.CsWin32/IStorageProviderStatusUI.cs
@@ -1,18 +1,71 @@
-// Copyright (c) Files Community
+// 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
+namespace Windows.Win32.System.WinRT;
+
+[GeneratedComInterface, Guid("D6B6A758-198D-5B80-977F-5FF73DA33118"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+public partial interface IStorageProviderStatusUI
{
- public unsafe partial struct IStorageProviderStatusUI : IComIID
- {
- [GeneratedVTableFunction(Index = 14)]
- public partial HRESULT GetQuotaUI(IStorageProviderQuotaUI** result);
-
- [GuidRVAGen.Guid("D6B6A758-198D-5B80-977F-5FF73DA33118")]
- public static partial ref readonly Guid Guid { get; }
- }
+ [PreserveSig]
+ HRESULT GetIids(out uint iidCount, out /* IID** */ nint iids);
+
+ [PreserveSig]
+ HRESULT GetRuntimeClassName([MarshalUsing(typeof(global::Windows.Win32.HStringStringMarshaller))] out string? className);
+
+ [PreserveSig]
+ HRESULT GetTrustLevel(out TrustLevel trustLevel);
+
+ [PreserveSig]
+ HRESULT GetProviderState(out StorageProviderState value);
+
+ [PreserveSig]
+ HRESULT PutProviderState(StorageProviderState value);
+
+ [PreserveSig]
+ HRESULT GetProviderStateLabel([MarshalUsing(typeof(global::Windows.Win32.HStringStringMarshaller))] out string? value);
+
+ [PreserveSig]
+ HRESULT PutProviderStateLabel([MarshalUsing(typeof(global::Windows.Win32.HStringStringMarshaller))] string? value);
+
+ [PreserveSig]
+ HRESULT GetProviderStateIcon(out /* Windows.Foundation.Uri** */ nint value);
+
+ [PreserveSig]
+ HRESULT PutProviderStateIcon(/* Windows.Foundation.Uri* */ nint value);
+
+ [PreserveSig]
+ HRESULT GetSyncStatusCommand(out /* IStorageProviderUICommand** */ nint value);
+
+ [PreserveSig]
+ HRESULT PutSyncStatusCommand(/* IStorageProviderUICommand* */ nint value);
+
+ [PreserveSig]
+ HRESULT GetQuotaUI([MarshalAs(UnmanagedType.Interface)] out IStorageProviderQuotaUI value);
+
+ [PreserveSig]
+ HRESULT PutQuotaUI([MarshalAs(UnmanagedType.Interface)] IStorageProviderQuotaUI value);
+
+ [PreserveSig]
+ HRESULT GetMoreInfoUI(out /* IStorageProviderMoreInfoUI** */ nint value);
+
+ [PreserveSig]
+ HRESULT PutMoreInfoUI(/* IStorageProviderMoreInfoUI* */ nint value);
+
+ [PreserveSig]
+ HRESULT GetProviderPrimaryCommand(out /* IStorageProviderUICommand** */ nint value);
+
+ [PreserveSig]
+ HRESULT PutProviderPrimaryCommand(/* IStorageProviderUICommand* */ nint value);
+
+ [PreserveSig]
+ HRESULT GetProviderSecondaryCommands(out /* IVector** */ nint value);
+
+ [PreserveSig]
+ HRESULT PutProviderSecondaryCommands(/* IVector* */ nint value);
}
diff --git a/src/Files.App.CsWin32/IStorageProviderStatusUISource.cs b/src/Files.App.CsWin32/IStorageProviderStatusUISource.cs
index 9f4ede28194f..6af1b6677679 100644
--- a/src/Files.App.CsWin32/IStorageProviderStatusUISource.cs
+++ b/src/Files.App.CsWin32/IStorageProviderStatusUISource.cs
@@ -1,18 +1,34 @@
-// Copyright (c) Files Community
+// 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;
+using WinRT;
-namespace Windows.Win32.System.WinRT
+namespace Windows.Win32.System.WinRT;
+
+[GeneratedComInterface, Guid("A306C249-3D66-5E70-9007-E43DF96051FF"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+public partial interface IStorageProviderStatusUISource
{
- public unsafe partial struct IStorageProviderStatusUISource : IComIID
- {
- [GeneratedVTableFunction(Index = 6)]
- public partial HRESULT GetStatusUI(IStorageProviderStatusUI** result);
-
- [GuidRVAGen.Guid("A306C249-3D66-5E70-9007-E43DF96051FF")]
- public static partial ref readonly Guid Guid { get; }
- }
+ [PreserveSig]
+ HRESULT GetIids(out uint iidCount, out /* IID** */ nint iids);
+
+ [PreserveSig]
+ HRESULT GetRuntimeClassName([MarshalUsing(typeof(global::Windows.Win32.HStringStringMarshaller))] out string? className);
+
+ [PreserveSig]
+ HRESULT GetTrustLevel(out TrustLevel trustLevel);
+
+ [PreserveSig]
+ HRESULT GetStatusUI([MarshalAs(UnmanagedType.Interface)] out IStorageProviderStatusUI result);
+
+ [PreserveSig]
+ HRESULT AddStatusUIChanged(
+ /* TypedEventHandler* */ nint handler,
+ out EventRegistrationToken token);
+
+ [PreserveSig]
+ HRESULT RemoveStatusUIChanged(EventRegistrationToken token);
}
diff --git a/src/Files.App.CsWin32/IStorageProviderStatusUISourceFactory.cs b/src/Files.App.CsWin32/IStorageProviderStatusUISourceFactory.cs
index 4065c1800c10..6d7a1e1a5513 100644
--- a/src/Files.App.CsWin32/IStorageProviderStatusUISourceFactory.cs
+++ b/src/Files.App.CsWin32/IStorageProviderStatusUISourceFactory.cs
@@ -1,18 +1,27 @@
-// Copyright (c) Files Community
+// 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
+namespace Windows.Win32.System.WinRT;
+
+[GeneratedComInterface, Guid("12E46B74-4E5A-58D1-A62F-0376E8EE7DD8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+public partial interface IStorageProviderStatusUISourceFactory
{
- public unsafe partial struct IStorageProviderStatusUISourceFactory : IComIID
- {
- [GeneratedVTableFunction(Index = 6)]
- public partial HRESULT GetStatusUISource(nint syncRootId, IStorageProviderStatusUISource** result);
+ [PreserveSig]
+ HRESULT GetIids(out uint iidCount, out /* IID** */ nint iids);
+
+ [PreserveSig]
+ HRESULT GetRuntimeClassName([MarshalUsing(typeof(global::Windows.Win32.HStringStringMarshaller))] out string? className);
+
+ [PreserveSig]
+ HRESULT GetTrustLevel(out TrustLevel trustLevel);
- [GuidRVAGen.Guid("12E46B74-4E5A-58D1-A62F-0376E8EE7DD8")]
- public static partial ref readonly Guid Guid { get; }
- }
+ [PreserveSig]
+ HRESULT GetStatusUISource(
+ [MarshalUsing(typeof(global::Windows.Win32.HStringStringMarshaller))] 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 721d5e0ca2d7..0927ba553eee 100644
--- a/src/Files.App.CsWin32/ManualGuid.cs
+++ b/src/Files.App.CsWin32/ManualGuid.cs
@@ -2,125 +2,23 @@
// SPDX-License-Identifier: MPL-2.0
using System;
-using System.Runtime.CompilerServices;
using Windows.Win32.System.WinRT;
namespace Windows.Win32
{
- public static unsafe partial class IID
+ public static partial class CLSID
{
- 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; }
-
- [GuidRVAGen.Guid("70629033-E363-4A28-A567-0DB78006E6D7")]
- public static partial Guid* IID_IEnumShellItems { get; }
-
- [GuidRVAGen.Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")]
- public static partial Guid* IID_IShellItem { get; }
-
- [GuidRVAGen.Guid("7E9FB0D3-919F-4307-AB2E-9B1860310C93")]
- public static partial Guid* IID_IShellItem2 { get; }
-
- [GuidRVAGen.Guid("947AAB5F-0A5C-4C13-B4D6-4BF7836FC9F8")]
- public static partial Guid* IID_IFileOperation { get; }
-
- [GuidRVAGen.Guid("D57C7288-D4AD-4768-BE02-9D969532D960")]
- public static partial Guid* IID_IFileOpenDialog { get; }
-
- [GuidRVAGen.Guid("84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB")]
- public static partial Guid* IID_IFileSaveDialog { get; }
-
- [GuidRVAGen.Guid("B92B56A9-8B55-4E14-9A89-0199BBB6F93B")]
- public static partial Guid* IID_IDesktopWallpaper { get; }
-
- [GuidRVAGen.Guid("2E941141-7F97-4756-BA1D-9DECDE894A3D")]
- public static partial Guid* IID_IApplicationActivationManager { get; }
-
- [GuidRVAGen.Guid("00021500-0000-0000-C000-000000000046")]
- public static partial Guid* IID_IQueryInfo { get; }
-
- [GuidRVAGen.Guid("BCC18B79-BA16-442F-80C4-8A59C30C463B")]
- public static partial Guid* IID_IShellItemImageFactory { get; }
-
- [GuidRVAGen.Guid("000214F9-0000-0000-C000-000000000046")]
- public static partial Guid* IID_IShellLinkW { get; }
-
- [GuidRVAGen.Guid("B63EA76D-1F85-456F-A19C-48159EFA858B")]
- public static partial Guid* IID_IShellItemArray { get; }
-
- [GuidRVAGen.Guid("7F9185B0-CB92-43C5-80A9-92277A4F7B54")]
- public static partial Guid* IID_IExecuteCommand { get; }
-
- [GuidRVAGen.Guid("1C9CD5BB-98E9-4491-A60F-31AACC72B83C")]
- public static partial Guid* IID_IObjectWithSelection { get; }
-
- [GuidRVAGen.Guid("000214E8-0000-0000-C000-000000000046")]
- public static partial Guid* IID_IShellExtInit { get; }
-
- [GuidRVAGen.Guid("000214F4-0000-0000-C000-000000000046")]
- public static partial Guid* IID_IContextMenu2 { get; }
-
- [GuidRVAGen.Guid("0000010E-0000-0000-C000-000000000046")]
- public static partial Guid* IID_IDataObject { get; }
+ public static Guid CLSID_PinToFrequentExecute { get; } = new(0xB455F46Eu, 0xE4AF, 0x4035, 0xB0, 0xA4, 0xCF, 0x18, 0xD2, 0xF6, 0xF2, 0x8E);
+ public static Guid CLSID_UnPinFromFrequentExecute { get; } = new(0xEE20EEBAu, 0xDF64, 0x4A4E, 0xB7, 0xBB, 0x2D, 0x1C, 0x6B, 0x2D, 0xFC, 0xC1);
+ public static Guid CLSID_NewMenu { get; } = new(0xD969A300u, 0xE7FF, 0x11D0, 0xA9, 0x3B, 0x00, 0xA0, 0xC9, 0x0F, 0x27, 0x19);
+ public static Guid CLSID_OpenWithMenu { get; } = new(0x09799AFBu, 0xAD67, 0x11D1, 0xAB, 0xCD, 0x00, 0xC0, 0x4F, 0xC3, 0x09, 0x36);
+ public static Guid CLSID_DetectionAndSharing { get; } = new(0x1FDA955Bu, 0x61FF, 0x11DA, 0x97, 0x8C, 0x00, 0x08, 0x74, 0x4F, 0xAA, 0xB7);
+ public static Guid CLSID_OpenControlPanel { get; } = new(0x06622D85u, 0x6856, 0x4460, 0x8D, 0xE1, 0xA8, 0x19, 0x21, 0xB4, 0x1C, 0x4B);
}
- public static unsafe partial class CLSID
+ public static partial class FOLDERID
{
- [GuidRVAGen.Guid("3AD05575-8857-4850-9277-11B85BDB8E09")]
- public static partial Guid* CLSID_FileOperation { get; }
-
- [GuidRVAGen.Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")]
- public static partial Guid* CLSID_FileOpenDialog { get; }
-
- [GuidRVAGen.Guid("C0B4E2F3-BA21-4773-8DBA-335EC946EB8B")]
- public static partial Guid* CLSID_FileSaveDialog { get; }
-
- [GuidRVAGen.Guid("C2CF3110-460E-4FC1-B9D0-8A1C0C9CC4BD")]
- public static partial Guid* CLSID_DesktopWallpaper { get; }
-
- [GuidRVAGen.Guid("45BA127D-10A8-46EA-8AB7-56EA9078943C")]
- public static partial Guid* CLSID_ApplicationActivationManager { get; }
-
- [GuidRVAGen.Guid("B455F46E-E4AF-4035-B0A4-CF18D2F6F28E")]
- public static partial Guid* CLSID_PinToFrequentExecute { get; }
-
- [GuidRVAGen.Guid("EE20EEBA-DF64-4A4E-B7BB-2D1C6B2DFCC1")]
- public static partial Guid* CLSID_UnPinFromFrequentExecute { get; }
-
- [GuidRVAGen.Guid("D969A300-E7FF-11d0-A93B-00A0C90F2719")]
- public static partial Guid* CLSID_NewMenu { get; }
-
- [GuidRVAGen.Guid("09799AFB-AD67-11D1-ABCD-00C04FC30936")]
- public static partial Guid* CLSID_OpenWithMenu { get; }
-
- [GuidRVAGen.Guid("1FDA955B-61FF-11DA-978C-0008744FAAB7")]
- public static partial Guid* CLSID_DetectionAndSharing { get; }
-
- [GuidRVAGen.Guid("06622D85-6856-4460-8DE1-A81921B41C4B")]
- public static partial Guid* CLSID_OpenControlPanel { get; }
- }
-
- public static unsafe partial class BHID
- {
- [GuidRVAGen.Guid("3981E225-F559-11D3-8E3A-00C04F6837D5")]
- public static partial Guid* BHID_SFUIObject { get; }
-
- [GuidRVAGen.Guid("94F60519-2850-4924-AA5A-D15E84868039")]
- public static partial Guid* BHID_EnumItems { get; }
-
- [GuidRVAGen.Guid("B8C0BD9F-ED24-455C-83E6-D5390C4FE8C4")]
- public static partial Guid* BHID_DataObject { get; }
- }
-
- public static unsafe partial class FOLDERID
- {
- [GuidRVAGen.Guid("B7534046-3ECB-4C18-BE4E-64CD4CB7D6AC")]
- public static partial Guid* FOLDERID_RecycleBinFolder { get; }
-
- [GuidRVAGen.Guid("0AC0837C-BBF8-452A-850D-79D08E667CA7")]
- public static partial Guid* FOLDERID_ComputerFolder { get; }
+ public static Guid FOLDERID_RecycleBinFolder { get; } = new(0xB7534046u, 0x3ECB, 0x4C18, 0xBE, 0x4E, 0x64, 0xCD, 0x4C, 0xB7, 0xD6, 0xAC);
+ public static Guid FOLDERID_ComputerFolder { get; } = new(0x0AC0837Cu, 0xBBF8, 0x452A, 0x85, 0x0D, 0x79, 0xD0, 0x8E, 0x66, 0x7C, 0xA7);
}
}
diff --git a/src/Files.App.CsWin32/NativeMethods.json b/src/Files.App.CsWin32/NativeMethods.json
index 2e32fa443533..ac009d621b98 100644
--- a/src/Files.App.CsWin32/NativeMethods.json
+++ b/src/Files.App.CsWin32/NativeMethods.json
@@ -1,8 +1,9 @@
{
"$schema": "https://aka.ms/CsWin32.schema.json",
- "allowMarshaling": false,
+ "allowMarshaling": true,
"public": true,
"comInterop": {
+ "useComSourceGenerators": true,
"preserveSigMethods": [
"*"
]
diff --git a/src/Files.App.CsWin32/NativeMethods.txt b/src/Files.App.CsWin32/NativeMethods.txt
index d67b29b50ee0..c8fef8c36c9f 100644
--- a/src/Files.App.CsWin32/NativeMethods.txt
+++ b/src/Files.App.CsWin32/NativeMethods.txt
@@ -324,3 +324,16 @@ SafeArrayUnaccessData
SafeArrayGetDim
SafeArrayGetLBound
SafeArrayGetUBound
+IObjectWithSite
+IPreviewHandlerVisuals
+IPreviewHandlerFrame
+IInitializeWithStream
+IInitializeWithFile
+IInitializeWithItem
+WindowsGetStringRawBuffer
+BHID_*
+FileOperation
+FileOpenDialog
+FileSaveDialog
+DesktopWallpaper
+ApplicationActivationManager
diff --git a/src/Files.App.Server/Helpers.cs b/src/Files.App.Server/Helpers.cs
index 8ab3253540d5..86f58f9e04bb 100644
--- a/src/Files.App.Server/Helpers.cs
+++ b/src/Files.App.Server/Helpers.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// Licensed under the MIT License.
using System.Runtime.CompilerServices;
@@ -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)
@@ -30,4 +30,4 @@ public static HRESULT GetActivationFactory(HSTRING activatableClassId, IActivati
return (HRESULT)ExceptionHelpers.GetHRForException(e);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Files.App.Server/Program.cs b/src/Files.App.Server/Program.cs
index b00061eaba85..b31c542a3340 100644
--- a/src/Files.App.Server/Program.cs
+++ b/src/Files.App.Server/Program.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// Licensed under the MIT License.
using Files.Shared.Helpers;
@@ -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 8963423d924f..4c7f06879748 100644
--- a/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Icon.cs
+++ b/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Icon.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// SPDX-License-Identifier: MPL-2.0
using System.Collections.Concurrent;
@@ -44,14 +44,12 @@ 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)
+ if (storable.ThisPtr is not IShellItemImageFactory pShellItemImageFactory)
return HRESULT.E_NOINTERFACE;
// Get HBITMAP
HBITMAP hBitmap = default;
- HRESULT hr = pShellItemImageFactory.Get()->GetImage(new(size, size), options, &hBitmap);
+ HRESULT hr = pShellItemImageFactory.GetImage(new(size, size), options, &hBitmap);
if (hr.ThrowIfFailedOnDebug().Failed)
{
if (!hBitmap.IsNull) PInvoke.DeleteObject(hBitmap);
@@ -168,22 +166,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 IStream pStream);
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, pStream, &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 = pStream.Stat(out stat, STATFLAG.STATFLAG_NONAME);
if (hr.ThrowIfFailedOnDebug().Failed)
{
if (gpBitmap is not null) PInvoke.GdipDisposeImage((GpImage*)gpBitmap);
@@ -193,8 +190,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);
+ pStream.Seek(0L, System.IO.SeekOrigin.Begin);
+ hr = pStream.Read(RawThumbnailData, (uint)statSize);
if (hr.ThrowIfFailedOnDebug().Failed)
{
if (gpBitmap is not null) PInvoke.GdipDisposeImage((GpImage*)gpBitmap);
@@ -266,14 +263,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, PInvoke.BHID_SFUIObject, out IShellLinkW? pShellLink);
if (hr.ThrowIfFailedOnDebug().Failed)
return hr;
fixed (char* pszIconFilePath = iconFilePath)
- hr = pShellLink.Get()->SetIconLocation(iconFilePath, index);
+ hr = pShellLink!.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 56755fcd59f2..e667b5024590 100644
--- a/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Shell.cs
+++ b/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Shell.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// SPDX-License-Identifier: MPL-2.0
using System.Runtime.CompilerServices;
@@ -19,26 +19,32 @@ 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());
+ if (storable.ThisPtr is not IShellItem2 pShellItem2)
+ {
+ value = default!;
+ return HRESULT.E_NOINTERFACE;
+ }
- PROPERTYKEY propertyKey = default;
- fixed (char* pszPropertyKey = propKey)
- hr = PInvoke.PSGetPropertyKeyFromName(pszPropertyKey, &propertyKey);
+ HRESULT hr = PInvoke.PSGetPropertyKeyFromName(propKey, out PROPERTYKEY propertyKey);
+ if (hr.ThrowIfFailedOnDebug().Failed)
+ {
+ value = default!;
+ return hr;
+ }
if (typeof(TValue) == typeof(string))
{
- ComHeapPtr szPropertyValue = default;
- hr = pShellItem2.Get()->GetString(&propertyKey, szPropertyValue.Get());
- value = (TValue)(object)szPropertyValue.Get()->ToString();
+ hr = pShellItem2.GetString(propertyKey, out PWSTR szPropertyValue);
+ value = (TValue)(object)szPropertyValue.ToString();
+ PInvoke.CoTaskMemFree(szPropertyValue);
return hr;
}
if (typeof(TValue) == typeof(bool))
{
- bool fPropertyValue = false;
- hr = pShellItem2.Get()->GetBool(&propertyKey, (BOOL*)&fPropertyValue);
- value = Unsafe.As(ref fPropertyValue);
+ hr = pShellItem2.GetBool(propertyKey, out BOOL fPropertyValue);
+ bool propertyValue = fPropertyValue;
+ value = Unsafe.As(ref propertyValue);
return hr;
}
@@ -51,27 +57,30 @@ 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());
-
- return hr.ThrowIfFailedOnDebug().Succeeded
- ? new string((char*)pszName.Get()) // this is safe as it gets memcpy'd internally
+ HRESULT hr = storable.ThisPtr.GetDisplayName(options, out PWSTR pszName);
+ string name = hr.ThrowIfFailedOnDebug().Succeeded
+ ? pszName.ToString()
: string.Empty;
+ PInvoke.CoTaskMemFree(pszName);
+
+ return name;
}
public static HRESULT TryInvokeContextMenuVerb(this IWindowsStorable storable, string verbName)
{
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, PInvoke.BHID_SFUIObject, out IContextMenu? pContextMenu);
+ if (hr.ThrowIfFailedOnDebug().Failed || pContextMenu is null)
+ return hr;
+
HMENU hMenu = PInvoke.CreatePopupMenu();
- hr = pContextMenu.Get()->QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE);
+ hr = pContextMenu.QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE);
CMINVOKECOMMANDINFO cmici = default;
cmici.cbSize = (uint)sizeof(CMINVOKECOMMANDINFO);
@@ -80,7 +89,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 = pContextMenu.InvokeCommand(cmici);
if (!PInvoke.DestroyMenu(hMenu))
return HRESULT.E_FAIL;
@@ -93,43 +102,52 @@ 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, PInvoke.BHID_SFUIObject, out IContextMenu? pContextMenu);
+ if (hr.ThrowIfFailedOnDebug().Failed || pContextMenu is null)
+ return hr;
+
HMENU hMenu = PInvoke.CreatePopupMenu();
- hr = pContextMenu.Get()->QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE);
+ HRESULT result = HRESULT.S_OK;
+ try
+ {
+ hr = pContextMenu.QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE);
+ result = hr;
- CMINVOKECOMMANDINFO cmici = default;
- cmici.cbSize = (uint)sizeof(CMINVOKECOMMANDINFO);
- cmici.nShow = (int)SHOW_WINDOW_CMD.SW_HIDE;
+ CMINVOKECOMMANDINFO cmici = default;
+ cmici.cbSize = (uint)sizeof(CMINVOKECOMMANDINFO);
+ cmici.nShow = (int)SHOW_WINDOW_CMD.SW_HIDE;
- foreach (var verbName in verbNames)
- {
- fixed (byte* pszVerbName = Encoding.ASCII.GetBytes(verbName))
+ foreach (var verbName in verbNames)
{
- cmici.lpVerb = new(pszVerbName);
- hr = pContextMenu.Get()->InvokeCommand(cmici);
-
- if (!PInvoke.DestroyMenu(hMenu))
- return HRESULT.E_FAIL;
+ fixed (byte* pszVerbName = Encoding.ASCII.GetBytes(verbName))
+ {
+ cmici.lpVerb = new(pszVerbName);
+ hr = pContextMenu.InvokeCommand(cmici);
+ result = hr;
- if (hr.Succeeded && earlyReturnOnSuccess)
- return hr;
+ if (hr.Succeeded && earlyReturnOnSuccess)
+ break;
+ }
}
}
+ finally
+ {
+ if (!PInvoke.DestroyMenu(hMenu))
+ result = HRESULT.E_FAIL;
+ }
- return hr;
+ return result;
}
public static HRESULT TryGetShellTooltip(this IWindowsStorable storable, out string? tooltip)
{
tooltip = null;
- using ComPtr pQueryInfo = default;
- HRESULT hr = storable.ThisPtr->BindToHandler(null, BHID.BHID_SFUIObject, IID.IID_IQueryInfo, (void**)pQueryInfo.GetAddressOf());
- if (hr.ThrowIfFailedOnDebug().Failed)
+ HRESULT hr = storable.ThisPtr.BindToHandler(null, PInvoke.BHID_SFUIObject, out IQueryInfo? pQueryInfo);
+ if (hr.ThrowIfFailedOnDebug().Failed || pQueryInfo is null)
return hr;
- pQueryInfo.Get()->GetInfoTip((uint)QITIPF_FLAGS.QITIPF_DEFAULT, out var pszTip);
+ hr = pQueryInfo.GetInfoTip(QITIPF_FLAGS.QITIPF_DEFAULT, out var pszTip);
if (hr.ThrowIfFailedOnDebug().Failed)
return hr;
@@ -143,27 +161,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());
- if (hr.ThrowIfFailedOnDebug().Failed)
+ hr = PInvoke.CoCreateInstance(CLSID.CLSID_PinToFrequentExecute, null, CLSCTX.CLSCTX_INPROC_SERVER, out IExecuteCommand? pExecuteCommand);
+ if (hr.ThrowIfFailedOnDebug().Failed || pExecuteCommand is null)
return hr;
- using ComPtr pShellItemArray = default;
- hr = PInvoke.SHCreateShellItemArrayFromShellItem(@this.ThisPtr, IID.IID_IShellItemArray, (void**)pShellItemArray.GetAddressOf());
+ hr = PInvoke.SHCreateShellItemArrayFromShellItem(@this.ThisPtr, out IShellItemArray pShellItemArray);
if (hr.ThrowIfFailedOnDebug().Failed)
return hr;
- hr = pExecuteCommand.Get()->QueryInterface(IID.IID_IObjectWithSelection, (void**)pObjectWithSelection.GetAddressOf());
- if (hr.ThrowIfFailedOnDebug().Failed)
- return hr;
+ if (pExecuteCommand is not IObjectWithSelection pObjectWithSelection)
+ return HRESULT.E_NOINTERFACE;
- hr = pObjectWithSelection.Get()->SetSelection(pShellItemArray.Get());
+ hr = pObjectWithSelection.SetSelection(pShellItemArray);
if (hr.ThrowIfFailedOnDebug().Failed)
return hr;
- hr = pExecuteCommand.Get()->Execute();
+ hr = pExecuteCommand.Execute();
if (hr.ThrowIfFailedOnDebug().Failed)
return hr;
@@ -174,27 +187,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());
- if (hr.ThrowIfFailedOnDebug().Failed)
+ hr = PInvoke.CoCreateInstance(CLSID.CLSID_UnPinFromFrequentExecute, null, CLSCTX.CLSCTX_INPROC_SERVER, out IExecuteCommand? pExecuteCommand);
+ if (hr.ThrowIfFailedOnDebug().Failed || pExecuteCommand is null)
return hr;
- using ComPtr pShellItemArray = default;
- hr = PInvoke.SHCreateShellItemArrayFromShellItem(@this.ThisPtr, IID.IID_IShellItemArray, (void**)pShellItemArray.GetAddressOf());
+ hr = PInvoke.SHCreateShellItemArrayFromShellItem(@this.ThisPtr, out IShellItemArray pShellItemArray);
if (hr.ThrowIfFailedOnDebug().Failed)
return hr;
- hr = pExecuteCommand.Get()->QueryInterface(IID.IID_IObjectWithSelection, (void**)pObjectWithSelection.GetAddressOf());
- if (hr.ThrowIfFailedOnDebug().Failed)
- return hr;
+ if (pExecuteCommand is not IObjectWithSelection pObjectWithSelection)
+ return HRESULT.E_NOINTERFACE;
- hr = pObjectWithSelection.Get()->SetSelection(pShellItemArray.Get());
+ hr = pObjectWithSelection.SetSelection(pShellItemArray);
if (hr.ThrowIfFailedOnDebug().Failed)
return hr;
- hr = pExecuteCommand.Get()->Execute();
+ hr = pExecuteCommand.Execute();
if (hr.ThrowIfFailedOnDebug().Failed)
return hr;
@@ -205,42 +213,33 @@ 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);
- if (hr.ThrowIfFailedOnDebug().Failed)
- return [];
-
- hr = pNewMenu->QueryInterface(IID.IID_IContextMenu2, (void**)pContextMenu2.GetAddressOf());
- if (hr.ThrowIfFailedOnDebug().Failed)
+ hr = PInvoke.CoCreateInstance(CLSID.CLSID_NewMenu, null, CLSCTX.CLSCTX_INPROC_SERVER, out IContextMenu? pNewMenu);
+ if (hr.ThrowIfFailedOnDebug().Failed || pNewMenu is null)
return [];
- hr = pNewMenu->QueryInterface(IID.IID_IShellExtInit, (void**)pShellExtInit.GetAddressOf());
- if (hr.ThrowIfFailedOnDebug().Failed)
+ if (pNewMenu is not IContextMenu2 pContextMenu2 ||
+ pNewMenu is not IShellExtInit pShellExtInit)
return [];
@this.ShellNewMenu = pNewMenu;
- ITEMIDLIST* pFolderPidl = default;
- hr = PInvoke.SHGetIDListFromObject((IUnknown*)@this.ThisPtr, &pFolderPidl);
+ hr = PInvoke.SHGetIDListFromObject(@this.ThisPtr, out ITEMIDLIST* pFolderPidl);
if (hr.ThrowIfFailedOnDebug().Failed)
return [];
- hr = pShellExtInit.Get()->Initialize(pFolderPidl, null, default);
+ hr = pShellExtInit.Initialize(pFolderPidl, null!, default);
if (hr.ThrowIfFailedOnDebug().Failed)
return [];
// Inserts "New (&W)"
HMENU hMenu = PInvoke.CreatePopupMenu();
- hr = pNewMenu->QueryContextMenu(hMenu, 0, 1, 256, 0);
+ hr = pNewMenu.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 = pContextMenu2.HandleMenuMsg(PInvoke.WM_INITMENUPOPUP, (WPARAM)(nuint)hSubMenu.Value, 0);
if (hr.ThrowIfFailedOnDebug().Failed)
return [];
@@ -280,10 +279,8 @@ 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);
- if (hr.ThrowIfFailedOnDebug().Failed)
+ hr = PInvoke.CoCreateInstance(CLSID.CLSID_NewMenu, null, CLSCTX.CLSCTX_INPROC_SERVER, out IContextMenu? pNewMenu);
+ if (hr.ThrowIfFailedOnDebug().Failed || pNewMenu is null)
return false;
@this.ShellNewMenu = pNewMenu;
@@ -294,7 +291,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 b01e1df69b15..99116eb9da47 100644
--- a/src/Files.App.Storage/Windows/IWindowsFolder.cs
+++ b/src/Files.App.Storage/Windows/IWindowsFolder.cs
@@ -1,15 +1,15 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// SPDX-License-Identifier: MPL-2.0
using Windows.Win32.UI.Shell;
namespace Files.App.Storage
{
- public unsafe interface IWindowsFolder : IWindowsStorable, IChildFolder
+ public 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 218e3fdce2c0..de5396473e60 100644
--- a/src/Files.App.Storage/Windows/IWindowsStorable.cs
+++ b/src/Files.App.Storage/Windows/IWindowsStorable.cs
@@ -1,14 +1,14 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// SPDX-License-Identifier: MPL-2.0
using Windows.Win32.UI.Shell;
namespace Files.App.Storage
{
- public unsafe interface IWindowsStorable : IStorableChild, IEquatable, IDisposable
+ public 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 42cc69d9a4a7..75dcf74ed543 100644
--- a/src/Files.App.Storage/Windows/Managers/SystemTrayManager.cs
+++ b/src/Files.App.Storage/Windows/Managers/SystemTrayManager.cs
@@ -6,6 +6,7 @@
using Windows.Win32.Foundation;
using Windows.Win32.UI.Shell;
using Windows.Win32.UI.WindowsAndMessaging;
+using WNDPROC = Windows.Win32.Extras.ManagedWNDPROC;
namespace Files.App.Storage
{
diff --git a/src/Files.App.Storage/Windows/Managers/TaskbarManager.cs b/src/Files.App.Storage/Windows/Managers/TaskbarManager.cs
index e0d519f07250..e97f8b8785c6 100644
--- a/src/Files.App.Storage/Windows/Managers/TaskbarManager.cs
+++ b/src/Files.App.Storage/Windows/Managers/TaskbarManager.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// SPDX-License-Identifier: MPL-2.0
using Windows.Win32;
@@ -10,7 +10,7 @@ namespace Files.App.Storage
{
public unsafe class TaskbarManager : IDisposable
{
- private ComPtr pTaskbarList = default;
+ private ITaskbarList3? taskbarList;
private static TaskbarManager? _Default = null;
public static TaskbarManager Default { get; } = _Default ??= new TaskbarManager();
@@ -18,31 +18,27 @@ public unsafe class TaskbarManager : IDisposable
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());
+ HRESULT hr = PInvoke.CoCreateInstance(CLSID_TaskbarList, null, CLSCTX.CLSCTX_INPROC_SERVER, out ITaskbarList3? pTaskbarList);
if (hr.ThrowIfFailedOnDebug().Succeeded)
- hr = pTaskbarList.Get()->HrInit().ThrowIfFailedOnDebug();
+ hr = pTaskbarList!.HrInit().ThrowIfFailedOnDebug();
+
+ taskbarList = pTaskbarList;
}
public HRESULT SetProgressValue(HWND hwnd, ulong ullCompleted, ulong ullTotal)
{
- return pTaskbarList.Get()->SetProgressValue(hwnd, ullCompleted, ullTotal);
+ return taskbarList?.SetProgressValue(hwnd, ullCompleted, ullTotal) ?? HRESULT.E_FAIL;
}
public HRESULT SetProgressState(HWND hwnd, TBPFLAG tbpFlags)
{
- return pTaskbarList.Get()->SetProgressState(hwnd, tbpFlags);
+ return taskbarList?.SetProgressState(hwnd, tbpFlags) ?? HRESULT.E_FAIL;
}
public void Dispose()
{
- pTaskbarList.Dispose();
+ taskbarList = null;
}
}
}
diff --git a/src/Files.App.Storage/Windows/Managers/WindowsDriveManager.cs b/src/Files.App.Storage/Windows/Managers/WindowsDriveManager.cs
index 216aa197ffe0..0a5083ed164f 100644
--- a/src/Files.App.Storage/Windows/Managers/WindowsDriveManager.cs
+++ b/src/Files.App.Storage/Windows/Managers/WindowsDriveManager.cs
@@ -20,7 +20,7 @@ public unsafe sealed class WindowsDriveManager : IDisposable
private WindowsDriveManager()
{
- Guid computerFolderId = *FOLDERID.FOLDERID_ComputerFolder;
+ Guid computerFolderId = FOLDERID.FOLDERID_ComputerFolder;
_folderChangeWatcher = new(
computerFolderId,
SHCNE_ID.SHCNE_DRIVEADD | SHCNE_ID.SHCNE_DRIVEREMOVED | SHCNE_ID.SHCNE_MEDIAINSERTED | SHCNE_ID.SHCNE_MEDIAREMOVED,
diff --git a/src/Files.App.Storage/Windows/Managers/WindowsFolderChangeWatcher.cs b/src/Files.App.Storage/Windows/Managers/WindowsFolderChangeWatcher.cs
index 0a6cabf011e8..87c6dd40a350 100644
--- a/src/Files.App.Storage/Windows/Managers/WindowsFolderChangeWatcher.cs
+++ b/src/Files.App.Storage/Windows/Managers/WindowsFolderChangeWatcher.cs
@@ -7,6 +7,7 @@
using Windows.Win32.UI.Shell;
using Windows.Win32.UI.Shell.Common;
using Windows.Win32.UI.WindowsAndMessaging;
+using WNDPROC = Windows.Win32.Extras.ManagedWNDPROC;
namespace Files.App.Storage
{
diff --git a/src/Files.App.Storage/Windows/Managers/WindowsObjectPicker.cs b/src/Files.App.Storage/Windows/Managers/WindowsObjectPicker.cs
index a18625d3baf9..baf480000ba1 100644
--- a/src/Files.App.Storage/Windows/Managers/WindowsObjectPicker.cs
+++ b/src/Files.App.Storage/Windows/Managers/WindowsObjectPicker.cs
@@ -2,6 +2,8 @@
// SPDX-License-Identifier: MPL-2.0
using Microsoft.Extensions.Logging;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
using System.Security.Principal;
using Windows.Win32;
using Windows.Win32.Foundation;
@@ -22,9 +24,8 @@ public static unsafe class WindowsObjectPicker
{
Guid CLSID_DsObjectPicker = PInvoke.CLSID_DsObjectPicker;
- using ComPtr pObjectPicker = default;
- HRESULT hr = pObjectPicker.CoCreateInstance(&CLSID_DsObjectPicker, null, CLSCTX.CLSCTX_INPROC_SERVER);
- if (hr.ThrowIfFailedOnDebug().Failed)
+ HRESULT hr = PInvoke.CoCreateInstance(CLSID_DsObjectPicker, null, CLSCTX.CLSCTX_INPROC_SERVER, out IDsObjectPicker? pObjectPicker);
+ if (hr.ThrowIfFailedOnDebug().Failed || pObjectPicker is null)
return null;
DSOP_SCOPE_INIT_INFO* scopeInitInfos = stackalloc DSOP_SCOPE_INIT_INFO[2];
@@ -53,17 +54,16 @@ public static unsafe class WindowsObjectPicker
initInfo.cAttributesToFetch = 1;
initInfo.apwzAttributeNames = attributeNames;
- hr = pObjectPicker.Get()->Initialize(&initInfo);
+ hr = pObjectPicker.Initialize(ref initInfo);
if (hr.ThrowIfFailedOnDebug().Failed)
return null;
}
- using ComPtr pSelections = default;
- hr = pObjectPicker.Get()->InvokeDialog(ownerHWnd, pSelections.GetAddressOf());
- if (hr == HRESULT.S_FALSE || hr.ThrowIfFailedOnDebug().Failed || pSelections.IsNull)
+ hr = pObjectPicker.InvokeDialog(ownerHWnd, out IDataObject pSelections);
+ if (hr == HRESULT.S_FALSE || hr.ThrowIfFailedOnDebug().Failed)
return null;
- return GetSelectedSid(pSelections.Get());
+ return GetSelectedSid(pSelections);
}
private static DSOP_SCOPE_INIT_INFO CreateScopeInitInfo(uint scopeType, bool startingScope)
@@ -106,11 +106,9 @@ private static DSOP_SCOPE_INIT_INFO CreateScopeInitInfo(uint scopeType, bool sta
return info;
}
- private static string? GetSelectedSid(IDataObject* pSelections)
+ private static string? GetSelectedSid(IDataObject pSelections)
{
- uint clipboardFormat;
- fixed (char* pszSelectionListFormatName = PInvoke.CFSTR_DSOP_DS_SELECTION_LIST)
- clipboardFormat = PInvoke.RegisterClipboardFormat(pszSelectionListFormatName);
+ uint clipboardFormat = PInvoke.RegisterClipboardFormat(PInvoke.CFSTR_DSOP_DS_SELECTION_LIST);
if (clipboardFormat is 0 || clipboardFormat > ushort.MaxValue)
return null;
@@ -124,14 +122,14 @@ private static DSOP_SCOPE_INIT_INFO CreateScopeInitInfo(uint scopeType, bool sta
STGMEDIUM medium = default;
medium.tymed = TYMED.TYMED_HGLOBAL;
- HRESULT hr = pSelections->GetData(&format, &medium);
+ HRESULT hr = pSelections.GetData(format, out medium);
if (hr.ThrowIfFailedOnDebug().Failed)
return null;
void* pvSelectionList = PInvoke.GlobalLock(medium.u.hGlobal);
if (pvSelectionList is null)
{
- PInvoke.ReleaseStgMedium(&medium);
+ PInvoke.ReleaseStgMedium(ref medium);
return null;
}
@@ -142,7 +140,7 @@ private static DSOP_SCOPE_INIT_INFO CreateScopeInitInfo(uint scopeType, bool sta
return null;
var selectionsAsSpan = pSelectionList->aDsSelection.AsSpan((int)pSelectionList->cItems);
- fixed (DS_SELECTION* pSelection = selectionsAsSpan)
+ fixed (DS_SELECTION_unmanaged* pSelection = selectionsAsSpan)
{
if (pSelection->pvarFetchedAttributes is null)
return null;
@@ -153,31 +151,31 @@ private static DSOP_SCOPE_INIT_INFO CreateScopeInitInfo(uint scopeType, bool sta
finally
{
PInvoke.GlobalUnlock(medium.u.hGlobal);
- PInvoke.ReleaseStgMedium(&medium);
+ PInvoke.ReleaseStgMedium(ref medium);
}
}
- private static string? GetSidString(VARIANT* objectSidVariant)
+ private static string? GetSidString(ComVariant* objectSidVariant)
{
- VARENUM variantType = objectSidVariant->Anonymous.Anonymous.vt;
- if ((variantType & VARENUM.VT_ARRAY) is 0 || (variantType & VARENUM.VT_TYPEMASK) is not VARENUM.VT_UI1)
+ VarEnum variantType = objectSidVariant->VarType;
+ if ((variantType & VarEnum.VT_ARRAY) is 0 || (variantType & (VarEnum)0x0FFF) is not VarEnum.VT_UI1)
return null;
- SAFEARRAY* pSafeArray = (variantType & VARENUM.VT_BYREF) is not 0
- ? *objectSidVariant->Anonymous.Anonymous.Anonymous.pparray
- : objectSidVariant->Anonymous.Anonymous.Anonymous.parray;
+ ref nint rawValue = ref objectSidVariant->GetRawDataRef();
+ SAFEARRAY* pSafeArray = (variantType & VarEnum.VT_BYREF) is not 0
+ ? *(SAFEARRAY**)rawValue
+ : (SAFEARRAY*)rawValue;
if (pSafeArray is null || PInvoke.SafeArrayGetDim(pSafeArray) is not 1)
return null;
int lowerBound = 0, upperBound = 0;
- if (PInvoke.SafeArrayGetLBound(pSafeArray, 1, &lowerBound).ThrowIfFailedOnDebug().Failed ||
- PInvoke.SafeArrayGetUBound(pSafeArray, 1, &upperBound).ThrowIfFailedOnDebug().Failed ||
+ if (PInvoke.SafeArrayGetLBound(pSafeArray, 1, out lowerBound).ThrowIfFailedOnDebug().Failed ||
+ PInvoke.SafeArrayGetUBound(pSafeArray, 1, out upperBound).ThrowIfFailedOnDebug().Failed ||
upperBound < lowerBound)
return null;
- void* pSidBytes;
- if (PInvoke.SafeArrayAccessData(pSafeArray, &pSidBytes).ThrowIfFailedOnDebug().Failed || pSidBytes is null)
+ if (PInvoke.SafeArrayAccessData(pSafeArray, out void* pSidBytes).ThrowIfFailedOnDebug().Failed || pSidBytes is null)
return null;
try
diff --git a/src/Files.App.Storage/Windows/WindowsBulkOperations.cs b/src/Files.App.Storage/Windows/WindowsBulkOperations.cs
index 7e0f18b30b48..b3bff9141461 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 _progressSink;
private readonly uint _progressSinkCookie;
// Events
@@ -68,22 +68,20 @@ public unsafe partial class WindowsBulkOperations : IDisposable
///
/// Specifies the window handle that will own the file operation dialogs.
/// 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)
+ public 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(typeof(FileOperation).GUID, null, CLSCTX.CLSCTX_LOCAL_SERVER, out IFileOperation? fileOperation);
hr.ThrowIfFailedOnDebug();
- _pFileOperation = pFileOperation;
+ _fileOperation = fileOperation!;
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();
+ _progressSink = new WindowsBulkOperationsSink(this);
+ hr = _fileOperation.Advise(_progressSink, 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, _progressSink);
}
///
@@ -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, _progressSink);
}
///
@@ -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, _progressSink);
}
///
@@ -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, _progressSink);
}
///
@@ -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
@@ -163,11 +161,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
index 542200369ecc..da105ecaf068 100644
--- a/src/Files.App.Storage/Windows/WindowsBulkOperationsSink.Methods.cs
+++ b/src/Files.App.Storage/Windows/WindowsBulkOperationsSink.Methods.cs
@@ -1,18 +1,27 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// SPDX-License-Identifier: MPL-2.0
using Windows.Win32.Foundation;
using Windows.Win32.UI.Shell;
+using System.Runtime.InteropServices.Marshalling;
namespace Files.App.Storage
{
public sealed partial class WindowsBulkOperations : IDisposable
{
- private unsafe partial struct WindowsBulkOperationsSink : IFileOperationProgressSink.Interface
+ [GeneratedComClass]
+ private sealed partial class WindowsBulkOperationsSink : IFileOperationProgressSink
{
+ private readonly WeakReference _operationsReference;
+
+ public WindowsBulkOperationsSink(WindowsBulkOperations operations)
+ {
+ _operationsReference = new(operations);
+ }
+
public HRESULT StartOperations()
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var operations))
{
operations.OperationsStarted?.Invoke(operations, EventArgs.Empty);
return HRESULT.S_OK;
@@ -23,7 +32,7 @@ public HRESULT StartOperations()
public HRESULT FinishOperations(HRESULT hrResult)
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var operations))
{
operations.OperationsFinished?.Invoke(operations, new(result: hrResult));
return HRESULT.S_OK;
@@ -32,9 +41,9 @@ public HRESULT FinishOperations(HRESULT hrResult)
return HRESULT.E_FAIL;
}
- public unsafe HRESULT PreRenameItem(uint dwFlags, IShellItem* pSource, PCWSTR pszNewName)
+ public HRESULT PreRenameItem(uint dwFlags, IShellItem pSource, PCWSTR pszNewName)
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var operations))
{
operations.ItemRenaming?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(pSource), null, null, pszNewName.ToString(), null, default));
return HRESULT.S_OK;
@@ -43,9 +52,9 @@ public unsafe HRESULT PreRenameItem(uint dwFlags, IShellItem* pSource, PCWSTR ps
return HRESULT.E_FAIL;
}
- public unsafe HRESULT PostRenameItem(uint dwFlags, IShellItem* pSource, PCWSTR pszNewName, HRESULT hrRename, IShellItem* psiNewlyCreated)
+ public HRESULT PostRenameItem(uint dwFlags, IShellItem pSource, PCWSTR pszNewName, HRESULT hrRename, IShellItem psiNewlyCreated)
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var 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;
@@ -54,9 +63,9 @@ public unsafe HRESULT PostRenameItem(uint dwFlags, IShellItem* pSource, PCWSTR p
return HRESULT.E_FAIL;
}
- public unsafe HRESULT PreMoveItem(uint dwFlags, IShellItem* pSource, IShellItem* psiDestinationFolder, PCWSTR pszNewName)
+ public HRESULT PreMoveItem(uint dwFlags, IShellItem pSource, IShellItem psiDestinationFolder, PCWSTR pszNewName)
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var 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;
@@ -65,9 +74,9 @@ public unsafe HRESULT PreMoveItem(uint dwFlags, IShellItem* pSource, IShellItem*
return HRESULT.E_FAIL;
}
- public unsafe HRESULT PostMoveItem(uint dwFlags, IShellItem* pSource, IShellItem* psiDestinationFolder, PCWSTR pszNewName, HRESULT hrMove, IShellItem* psiNewlyCreated)
+ public HRESULT PostMoveItem(uint dwFlags, IShellItem pSource, IShellItem psiDestinationFolder, PCWSTR pszNewName, HRESULT hrMove, IShellItem psiNewlyCreated)
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var 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;
@@ -76,9 +85,9 @@ public unsafe HRESULT PostMoveItem(uint dwFlags, IShellItem* pSource, IShellItem
return HRESULT.E_FAIL;
}
- public unsafe HRESULT PreCopyItem(uint dwFlags, IShellItem* pSource, IShellItem* psiDestinationFolder, PCWSTR pszNewName)
+ public HRESULT PreCopyItem(uint dwFlags, IShellItem pSource, IShellItem psiDestinationFolder, PCWSTR pszNewName)
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var 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;
@@ -87,9 +96,9 @@ public unsafe HRESULT PreCopyItem(uint dwFlags, IShellItem* pSource, IShellItem*
return HRESULT.E_FAIL;
}
- public unsafe HRESULT PostCopyItem(uint dwFlags, IShellItem* pSource, IShellItem* psiDestinationFolder, PCWSTR pszNewName, HRESULT hrCopy, IShellItem* psiNewlyCreated)
+ public HRESULT PostCopyItem(uint dwFlags, IShellItem pSource, IShellItem psiDestinationFolder, PCWSTR pszNewName, HRESULT hrCopy, IShellItem psiNewlyCreated)
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var 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;
@@ -98,9 +107,9 @@ public unsafe HRESULT PostCopyItem(uint dwFlags, IShellItem* pSource, IShellItem
return HRESULT.E_FAIL;
}
- public unsafe HRESULT PreDeleteItem(uint dwFlags, IShellItem* pSource)
+ public HRESULT PreDeleteItem(uint dwFlags, IShellItem pSource)
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var operations))
{
operations.ItemDeleting?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(pSource), null, null, null, null, default));
return HRESULT.S_OK;
@@ -109,9 +118,9 @@ public unsafe HRESULT PreDeleteItem(uint dwFlags, IShellItem* pSource)
return HRESULT.E_FAIL;
}
- public unsafe HRESULT PostDeleteItem(uint dwFlags, IShellItem* pSource, HRESULT hrDelete, IShellItem* psiNewlyCreated)
+ public HRESULT PostDeleteItem(uint dwFlags, IShellItem pSource, HRESULT hrDelete, IShellItem psiNewlyCreated)
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var operations))
{
operations.ItemDeleted?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, WindowsStorable.TryParse(pSource), null, WindowsStorable.TryParse(psiNewlyCreated), null, null, hrDelete));
return HRESULT.S_OK;
@@ -120,9 +129,9 @@ public unsafe HRESULT PostDeleteItem(uint dwFlags, IShellItem* pSource, HRESULT
return HRESULT.E_FAIL;
}
- public unsafe HRESULT PreNewItem(uint dwFlags, IShellItem* psiDestinationFolder, PCWSTR pszNewName)
+ public HRESULT PreNewItem(uint dwFlags, IShellItem psiDestinationFolder, PCWSTR pszNewName)
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var operations))
{
operations.ItemCreating?.Invoke(operations, new((_TRANSFER_SOURCE_FLAGS)dwFlags, null, new WindowsFolder(psiDestinationFolder), null, pszNewName.ToString(), null, default));
return HRESULT.S_OK;
@@ -131,9 +140,9 @@ public unsafe HRESULT PreNewItem(uint dwFlags, IShellItem* psiDestinationFolder,
return HRESULT.E_FAIL;
}
- public unsafe HRESULT PostNewItem(uint dwFlags, IShellItem* psiDestinationFolder, PCWSTR pszNewName, PCWSTR pszTemplateName, uint dwFileAttributes, HRESULT hrNew, IShellItem* psiNewItem)
+ public HRESULT PostNewItem(uint dwFlags, IShellItem psiDestinationFolder, PCWSTR pszNewName, PCWSTR pszTemplateName, uint dwFileAttributes, HRESULT hrNew, IShellItem psiNewItem)
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var 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;
@@ -144,7 +153,7 @@ public unsafe HRESULT PostNewItem(uint dwFlags, IShellItem* psiDestinationFolder
public HRESULT UpdateProgress(uint iWorkTotal, uint iWorkSoFar)
{
- if (_operationsHandle.Target is WindowsBulkOperations operations)
+ if (_operationsReference.TryGetTarget(out var operations))
{
var percentage = iWorkTotal is 0 ? 0 : iWorkSoFar * 100.0 / iWorkTotal;
operations.ProgressUpdated?.Invoke(operations, new((int)percentage, null));
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 6a0c19647551..000000000000
--- a/src/Files.App.Storage/Windows/WindowsBulkOperationsSink.VTable.cs
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright (c) Files Community
-// SPDX-License-Identifier: MPL-2.0
-
-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/WindowsFile.cs b/src/Files.App.Storage/Windows/WindowsFile.cs
index c8d6fb5bb52e..f78618db4728 100644
--- a/src/Files.App.Storage/Windows/WindowsFile.cs
+++ b/src/Files.App.Storage/Windows/WindowsFile.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// SPDX-License-Identifier: MPL-2.0
using System.IO;
@@ -7,9 +7,9 @@
namespace Files.App.Storage
{
[DebuggerDisplay("{" + nameof(ToString) + "()}")]
- public unsafe class WindowsFile : WindowsStorable, IWindowsFile
+ public class WindowsFile : WindowsStorable, IWindowsFile
{
- public WindowsFile(IShellItem* ptr)
+ public WindowsFile(IShellItem ptr)
{
ThisPtr = ptr;
}
diff --git a/src/Files.App.Storage/Windows/WindowsFolder.cs b/src/Files.App.Storage/Windows/WindowsFolder.cs
index a54bd73e64e0..d587473715f3 100644
--- a/src/Files.App.Storage/Windows/WindowsFolder.cs
+++ b/src/Files.App.Storage/Windows/WindowsFolder.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// SPDX-License-Identifier: MPL-2.0
using System.Runtime.CompilerServices;
@@ -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,42 +22,38 @@ public IContextMenu* ShellNewMenu
set;
}
- public WindowsFolder(IShellItem* ptr)
+ public WindowsFolder(IShellItem ptr)
{
ThisPtr = ptr;
}
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, null, out IShellItem shellItem);
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, out shellItem);
// 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, PInvoke.BHID_EnumItems, out IEnumShellItems? pEnumShellItems);
if (hr.ThrowIfFailedOnDebug().Failed)
return Enumerable.Empty().ToAsyncEnumerable();
List childItems = [];
+ IShellItem[] pChildShellItems = new IShellItem[1];
- IShellItem* pChildShellItem = null;
- while ((hr = pEnumShellItems.Get()->Next(1, &pChildShellItem)) == HRESULT.S_OK)
+ while ((hr = pEnumShellItems!.Next(1, pChildShellItems, null)) == HRESULT.S_OK)
{
- bool isFolder = pChildShellItem->GetAttributes(SFGAO_FLAGS.SFGAO_FOLDER, out var dwAttributes).Succeeded && dwAttributes is SFGAO_FLAGS.SFGAO_FOLDER;
+ IShellItem pChildShellItem = pChildShellItems[0];
+ bool isFolder = pChildShellItem.GetAttributes(SFGAO_FLAGS.SFGAO_FOLDER, out var dwAttributes).Succeeded && dwAttributes is SFGAO_FLAGS.SFGAO_FOLDER;
if (type.HasFlag(StorableType.File) && !isFolder)
{
@@ -78,8 +74,7 @@ public IAsyncEnumerable GetItemsAsync(StorableType type = Storab
public override void Dispose()
{
base.Dispose();
-
- if (ShellNewMenu is not null) ShellNewMenu->Release();
+ ShellNewMenu = null;
}
}
}
diff --git a/src/Files.App.Storage/Windows/WindowsStorable.cs b/src/Files.App.Storage/Windows/WindowsStorable.cs
index d7ed69cc2f31..f2df4d2dc78f 100644
--- a/src/Files.App.Storage/Windows/WindowsStorable.cs
+++ b/src/Files.App.Storage/Windows/WindowsStorable.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// Licensed under the MIT License.
using System.Runtime.CompilerServices;
@@ -9,20 +9,20 @@
namespace Files.App.Storage
{
- public unsafe abstract class WindowsStorable : IWindowsStorable
+ public abstract class WindowsStorable : IWindowsStorable
{
///
- public IShellItem* ThisPtr
+ public IShellItem ThisPtr
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set;
- }
+ } = null!;
///
- public IContextMenu* ContextMenu
+ public IContextMenu? ContextMenu
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
@@ -39,32 +39,29 @@ public IContextMenu* ContextMenu
public static WindowsStorable? TryParse(string szPath)
{
- 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(szPath, null, out IShellItem pShellItem);
+ if (hr.ThrowIfFailedOnDebug().Failed)
return null;
return TryParse(pShellItem);
}
- public static WindowsStorable? TryParse(IShellItem* pShellItem)
+ public static WindowsStorable? TryParse(IShellItem? pShellItem)
{
- bool isFolder = pShellItem->GetAttributes(SFGAO_FLAGS.SFGAO_FOLDER, out var returnedAttributes).Succeeded && returnedAttributes is SFGAO_FLAGS.SFGAO_FOLDER;
+ if (pShellItem is null)
+ return null;
+
+ bool isFolder = pShellItem.GetAttributes(SFGAO_FLAGS.SFGAO_FOLDER, out var returnedAttributes).Succeeded && returnedAttributes is SFGAO_FLAGS.SFGAO_FOLDER;
return isFolder ? new WindowsFolder(pShellItem) : new WindowsFile(pShellItem);
}
///
- public unsafe Task GetParentAsync(CancellationToken cancellationToken = default)
+ public Task GetParentAsync(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
- IShellItem* pParentFolder = default;
- HRESULT hr = ThisPtr->GetParent(&pParentFolder);
+ HRESULT hr = ThisPtr.GetParent(out var pParentFolder);
if (hr.ThrowIfFailedOnDebug().Failed)
return Task.FromResult(null);
@@ -86,8 +83,7 @@ public override int GetHashCode()
///
public virtual void Dispose()
{
- if (ThisPtr is not null) ThisPtr->Release();
- if (ContextMenu is not null) ContextMenu->Release();
+ ContextMenu = null;
}
///
@@ -97,12 +93,12 @@ public override string ToString()
}
///
- public unsafe bool Equals(IWindowsStorable? other)
+ public 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..e5ae7dee93eb 100644
--- a/src/Files.App/Data/Items/WidgetRecentItem.cs
+++ b/src/Files.App/Data/Items/WidgetRecentItem.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT License.
using Microsoft.UI.Xaml.Media.Imaging;
-using Windows.Win32;
using Windows.Win32.UI.Shell;
namespace Files.App.Data.Items
@@ -38,7 +37,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.
@@ -57,9 +56,8 @@ public async Task LoadRecentItemIconAsync()
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()
+ public void Dispose()
{
- ShellItem.Dispose();
}
}
}
diff --git a/src/Files.App/Data/Items/WindowEx.cs b/src/Files.App/Data/Items/WindowEx.cs
index 6ff6709a8248..f17ad3a9cab0 100644
--- a/src/Files.App/Data/Items/WindowEx.cs
+++ b/src/Files.App/Data/Items/WindowEx.cs
@@ -11,6 +11,8 @@
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Gdi;
using Windows.Win32.UI.WindowsAndMessaging;
+using MONITORENUMPROC = Windows.Win32.Extras.ManagedMONITORENUMPROC;
+using WNDPROC = Windows.Win32.Extras.ManagedWNDPROC;
namespace Files.App.Data.Items
{
diff --git a/src/Files.App/Services/Storage/StorageTrashBinService.cs b/src/Files.App/Services/Storage/StorageTrashBinService.cs
index cfbbc32e19b4..978ea9a4b7d5 100644
--- a/src/Files.App/Services/Storage/StorageTrashBinService.cs
+++ b/src/Files.App/Services/Storage/StorageTrashBinService.cs
@@ -130,38 +130,64 @@ 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, null, out IShellItem pRecycleBinFolderShellItem);
+ if (hr.ThrowIfFailedOnDebug().Failed)
+ return false;
// 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 = pRecycleBinFolderShellItem.BindToHandler(null, PInvoke.BHID_EnumItems, out IEnumShellItems? pEnumShellItems);
+ if (hr.ThrowIfFailedOnDebug().Failed || pEnumShellItems is null)
+ return false;
// 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(typeof(FileOperation).GUID, null, CLSCTX.CLSCTX_LOCAL_SERVER, out IFileOperation? pFileOperation);
+ if (hr.ThrowIfFailedOnDebug().Failed || pFileOperation is null)
+ return false;
+
+ hr = pFileOperation.SetOperationFlags(FILEOPERATION_FLAGS.FOF_NO_UI);
+ if (hr.ThrowIfFailedOnDebug().Failed)
+ return false;
- using ComPtr pShellItem = default;
- while (pEnumShellItems.Get()->Next(1, pShellItem.GetAddressOf()) == HRESULT.S_OK)
+ hr = pFileOperation.SetOwnerWindow(new(MainWindow.Instance.WindowHandle));
+ if (hr.ThrowIfFailedOnDebug().Failed)
+ return false;
+
+ IShellItem[] shellItems = new IShellItem[1];
+ while (pEnumShellItems.Next(1, shellItems, null) == HRESULT.S_OK)
{
- // Get the original path
- using ComPtr pShellItem2 = default;
- hr = pShellItem.Get()->QueryInterface(IID.IID_IShellItem2, (void**)pShellItem2.GetAddressOf());
+ IShellItem shellItem = shellItems[0];
+
+ if (shellItem is not IShellItem2 shellItem2)
+ continue;
+
hr = PInvoke.PSGetPropertyKeyFromName("System.Recycle.DeletedFrom", out var originalPathPropertyKey);
- hr = pShellItem2.Get()->GetString(originalPathPropertyKey, out var szOriginalPath);
+ if (hr.Failed)
+ continue;
+
+ hr = shellItem2.GetString(originalPathPropertyKey, out var szOriginalPath);
+ if (hr.Failed)
+ continue;
- // Get IShellItem of the original path
- hr = PInvoke.SHCreateItemFromParsingName(szOriginalPath.ToString(), null, typeof(IShellItem).GUID, out var pOriginalPathShellItemPtr);
- var pOriginalPathShellItem = (IShellItem*)pOriginalPathShellItemPtr;
+ try
+ {
+ // Get IShellItem of the original path
+ hr = PInvoke.SHCreateItemFromParsingName(szOriginalPath.ToString(), null, out IShellItem originalPathShellItem);
+ if (hr.Failed)
+ continue;
- // Define the shell item to restore
- hr = pFileOperation.Get()->MoveItem(pShellItem.Get(), pOriginalPathShellItem, default(PCWSTR), null);
+ // Define the shell item to restore
+ hr = pFileOperation.MoveItem(shellItem, originalPathShellItem, null!, null!);
+ }
+ finally
+ {
+ PInvoke.CoTaskMemFree(szOriginalPath);
+ }
}
// Perform
- hr = pFileOperation.Get()->PerformOperations();
+ hr = pFileOperation.PerformOperations();
+ if (hr.ThrowIfFailedOnDebug().Failed)
+ return false;
// 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..93a406aa52f6 100644
--- a/src/Files.App/Services/Windows/WindowsDialogService.cs
+++ b/src/Files.App/Services/Windows/WindowsDialogService.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// Licensed under the MIT License.
using Microsoft.Extensions.Logging;
@@ -22,11 +22,10 @@ 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(typeof(FileOpenDialog).GUID, null, CLSCTX.CLSCTX_INPROC_SERVER, out IFileOpenDialog? pDialog);
// Handle COM creation failure gracefully
- if (hr.Failed)
+ if (hr.Failed || pDialog is null)
{
App.Logger.LogError("Failed to create IFileOpenDialog COM object. HRESULT: 0x{0:X8}", hr.Value);
return false;
@@ -48,40 +47,37 @@ public unsafe bool Open_FileOpenDialog(nint hWnd, bool pickFoldersOnly, string[]
}
// Set the file type using the extension list
- pDialog.Get()->SetFileTypes(extensions.ToArray());
+ pDialog.SetFileTypes(extensions.ToArray());
}
// Get the default shell folder (My Computer)
- using ComPtr pDefaultFolderShellItem = default;
- fixed (char* pszDefaultFolderPath = Environment.GetFolderPath(defaultFolder))
+ IShellItem? pDefaultFolderShellItem = null;
+ hr = PInvoke.SHCreateItemFromParsingName(Environment.GetFolderPath(defaultFolder), null, out IShellItem defaultFolderShellItem);
+
+ // 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
+ }
+ else
+ {
+ pDefaultFolderShellItem = defaultFolderShellItem;
}
// Folder picker
if (pickFoldersOnly)
- pDialog.Get()->SetOptions(FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS);
+ pDialog.SetOptions(FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS);
// Set the default folder to open in the dialog (only if creation succeeded)
- if (pDefaultFolderShellItem.Get() is not null)
+ if (pDefaultFolderShellItem is not null)
{
- pDialog.Get()->SetFolder(pDefaultFolderShellItem.Get());
- pDialog.Get()->SetDefaultFolder(pDefaultFolderShellItem.Get());
+ pDialog.SetFolder(pDefaultFolderShellItem);
+ pDialog.SetDefaultFolder(pDefaultFolderShellItem);
}
// Show the dialog
- hr = pDialog.Get()->Show(new HWND(hWnd));
+ hr = pDialog.Show(new HWND(hWnd));
if (hr.Value == unchecked((int)0x800704C7)) // HRESULT_FROM_WIN32(ERROR_CANCELLED)
return false;
@@ -93,12 +89,12 @@ 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)
+ pDialog.GetResult(out IShellItem pResultShellItem);
+ if (pResultShellItem is null)
throw new COMException("FileOpenDialog returned invalid shell item.");
- pResultShellItem.Get()->GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var lpFilePath);
+ pResultShellItem.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var lpFilePath);
filePath = lpFilePath.ToString();
+ PInvoke.CoTaskMemFree(lpFilePath);
return true;
}
@@ -121,11 +117,10 @@ 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(typeof(FileSaveDialog).GUID, null, CLSCTX.CLSCTX_INPROC_SERVER, out IFileSaveDialog? pDialog);
// Handle COM creation failure gracefully
- if (hr.Failed)
+ if (hr.Failed || pDialog is null)
{
App.Logger.LogError("Failed to create IFileSaveDialog COM object. HRESULT: 0x{0:X8}", hr.Value);
return false;
@@ -147,40 +142,37 @@ public unsafe bool Open_FileSaveDialog(nint hWnd, bool pickFoldersOnly, string[]
}
// Set the file type using the extension list
- pDialog.Get()->SetFileTypes(extensions.ToArray());
+ pDialog.SetFileTypes(extensions.ToArray());
}
// Get the default shell folder (My Computer)
- using ComPtr pDefaultFolderShellItem = default;
- fixed (char* pszDefaultFolderPath = Environment.GetFolderPath(defaultFolder))
- {
- hr = PInvoke.SHCreateItemFromParsingName(
- pszDefaultFolderPath,
- null,
- IID.IID_IShellItem,
- (void**)pDefaultFolderShellItem.GetAddressOf());
+ IShellItem? pDefaultFolderShellItem = null;
+ hr = PInvoke.SHCreateItemFromParsingName(Environment.GetFolderPath(defaultFolder), null, out IShellItem defaultFolderShellItem);
- // 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
- }
+ // 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
+ }
+ else
+ {
+ pDefaultFolderShellItem = defaultFolderShellItem;
}
// Folder picker
if (pickFoldersOnly)
- pDialog.Get()->SetOptions(FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS);
+ pDialog.SetOptions(FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS);
// Set the default folder to open in the dialog (only if creation succeeded)
- if (pDefaultFolderShellItem.Get() is not null)
+ if (pDefaultFolderShellItem is not null)
{
- pDialog.Get()->SetFolder(pDefaultFolderShellItem.Get());
- pDialog.Get()->SetDefaultFolder(pDefaultFolderShellItem.Get());
+ pDialog.SetFolder(pDefaultFolderShellItem);
+ pDialog.SetDefaultFolder(pDefaultFolderShellItem);
}
// Show the dialog
- hr = pDialog.Get()->Show(new HWND(hWnd));
+ hr = pDialog.Show(new HWND(hWnd));
if (hr.Value == unchecked((int)0x800704C7)) // HRESULT_FROM_WIN32(ERROR_CANCELLED)
return false;
@@ -192,12 +184,12 @@ 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)
+ pDialog.GetResult(out IShellItem pResultShellItem);
+ if (pResultShellItem is null)
throw new COMException("FileSaveDialog returned invalid shell item.");
- pResultShellItem.Get()->GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var lpFilePath);
+ pResultShellItem.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var lpFilePath);
filePath = lpFilePath.ToString();
+ PInvoke.CoTaskMemFree(lpFilePath);
return true;
}
diff --git a/src/Files.App/Services/Windows/WindowsRecentItemsService.cs b/src/Files.App/Services/Windows/WindowsRecentItemsService.cs
index 9024d8a0770c..7fd74ed04cc6 100644
--- a/src/Files.App/Services/Windows/WindowsRecentItemsService.cs
+++ b/src/Files.App/Services/Windows/WindowsRecentItemsService.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// Licensed under the MIT License.
using Microsoft.Extensions.Logging;
@@ -121,10 +121,12 @@ 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, PInvoke.BHID_SFUIObject, out IContextMenu? pContextMenu);
+ if (hr.Failed || pContextMenu is null)
+ return false;
+
HMENU hMenu = PInvoke.CreatePopupMenu();
- hr = pContextMenu.Get()->QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE);
+ hr = pContextMenu.QueryContextMenu(hMenu, 0, 1, 0x7FFF, PInvoke.CMF_OPTIMIZEFORINVOKE);
// Initialize invocation info
CMINVOKECOMMANDINFO cmi = default;
@@ -138,13 +140,13 @@ public unsafe bool Remove(RecentItem item)
{
// Try unpin files
cmi.lpVerb = new(pVerb1);
- hr = pContextMenu.Get()->InvokeCommand(cmi);
+ hr = pContextMenu.InvokeCommand(cmi);
if (hr == HRESULT.S_OK)
return true;
// Try unpin folders
cmi.lpVerb = new(pVerb2);
- hr = pContextMenu.Get()->InvokeCommand(cmi);
+ hr = pContextMenu.InvokeCommand(cmi);
if (hr == HRESULT.S_OK)
return true;
@@ -153,7 +155,7 @@ public unsafe bool Remove(RecentItem item)
// won't be removed via unpinfromhome verb.
// Try unpin folders again
cmi.lpVerb = new(pVerb3);
- hr = pContextMenu.Get()->InvokeCommand(cmi);
+ hr = pContextMenu.InvokeCommand(cmi);
if (hr == HRESULT.S_OK)
return true;
}
@@ -195,37 +197,40 @@ private unsafe bool UpdateRecentItems(bool isFolder)
: "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(szFolderShellPath, null, out IShellItem pFolderShellItem);
+ if (hr.Failed)
+ return false;
// 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 = pFolderShellItem.BindToHandler(null, PInvoke.BHID_EnumItems, out IEnumShellItems? pEnumShellItems);
+ if (hr.Failed || pEnumShellItems is null)
+ return false;
// 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)
+ IShellItem[] pShellItems = new IShellItem[1];
+ while (pEnumShellItems.Next(1, pShellItems, null) == HRESULT.S_OK)
{
+ IShellItem shellItem = pShellItems[0];
+
// Get top 20 items
if (index is 20)
break;
// Exclude folders, but keep archives (ZIP/7z/RAR) which the shell reports as both folder and stream.
- if (pShellItem.Get()->GetAttributes(SFGAO_FLAGS.SFGAO_FOLDER | SFGAO_FLAGS.SFGAO_STREAM, out var attribute).Succeeded &&
+ if (shellItem.GetAttributes(SFGAO_FLAGS.SFGAO_FOLDER | SFGAO_FLAGS.SFGAO_STREAM, out var attribute).Succeeded &&
(attribute & SFGAO_FLAGS.SFGAO_FOLDER) == SFGAO_FLAGS.SFGAO_FOLDER &&
(attribute & SFGAO_FLAGS.SFGAO_STREAM) == 0)
continue;
// Get the target path
- pShellItem.Get()->GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEEDITING, out var szDisplayName);
+ shellItem.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEEDITING, out var szDisplayName);
var targetPath = szDisplayName.ToString();
PInvoke.CoTaskMemFree(szDisplayName.Value);
// Get the display name
- pShellItem.Get()->GetDisplayName(SIGDN.SIGDN_NORMALDISPLAY, out szDisplayName);
+ shellItem.GetDisplayName(SIGDN.SIGDN_NORMALDISPLAY, out szDisplayName);
var fileName = szDisplayName.ToString();
PInvoke.CoTaskMemFree(szDisplayName.Value);
@@ -235,18 +240,26 @@ 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());
- hr = PInvoke.PSGetPropertyKeyFromName("System.DateModified", out var propertyKey);
- hr = pShellItem2.Get()->GetString(propertyKey, out var szPropertyValue);
- if (DateTime.TryParse(szPropertyValue.ToString(), out var lastModified))
- lastModified = DateTime.MinValue;
+ DateTime lastModified = DateTime.MinValue;
+
+ if (shellItem is IShellItem2 shellItem2 &&
+ PInvoke.PSGetPropertyKeyFromName("System.DateModified", out var propertyKey).Succeeded)
+ {
+ hr = shellItem2.GetString(propertyKey, out var szPropertyValue);
+ if (hr.Succeeded)
+ {
+ if (!DateTime.TryParse(szPropertyValue.ToString(), out lastModified))
+ lastModified = DateTime.MinValue;
+
+ PInvoke.CoTaskMemFree(szPropertyValue);
+ }
+ }
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..bd5be966e96e 100644
--- a/src/Files.App/Services/Windows/WindowsWallpaperService.cs
+++ b/src/Files.App/Services/Windows/WindowsWallpaperService.cs
@@ -5,6 +5,7 @@
using Windows.System.UserProfile;
using Windows.Win32;
using Windows.Win32.Foundation;
+using Windows.Win32.System.Com;
using Windows.Win32.UI.Shell;
using Windows.Win32.UI.Shell.Common;
@@ -17,11 +18,12 @@ public sealed class WindowsWallpaperService : IWindowsWallpaperService
public unsafe void SetDesktopWallpaper(string szPath)
{
// Instantiate IDesktopWallpaper
- using ComPtr pDesktopWallpaper = default;
- HRESULT hr = pDesktopWallpaper.CoCreateInstance(CLSID.CLSID_DesktopWallpaper);
+ HRESULT hr = PInvoke.CoCreateInstance(typeof(DesktopWallpaper).GUID, null, CLSCTX.CLSCTX_LOCAL_SERVER, out IDesktopWallpaper? pDesktopWallpaper);
+ if (hr.Failed || pDesktopWallpaper is null)
+ return;
// Get total count of all available monitors
- hr = pDesktopWallpaper.Get()->GetMonitorDevicePathCount(out var dwMonitorCount);
+ hr = pDesktopWallpaper.GetMonitorDevicePathCount(out var dwMonitorCount);
fixed (char* pszPath = szPath)
{
@@ -31,8 +33,9 @@ public unsafe void SetDesktopWallpaper(string szPath)
for (uint dwIndex = 0u; dwIndex < dwMonitorCount; dwIndex++)
{
// Set the wallpaper
- hr = pDesktopWallpaper.Get()->GetMonitorDevicePathAt(dwIndex, &pMonitorId);
- hr = pDesktopWallpaper.Get()->SetWallpaper(pMonitorId, pszPath);
+ hr = pDesktopWallpaper.GetMonitorDevicePathAt(dwIndex, out pMonitorId);
+ hr = pDesktopWallpaper.SetWallpaper(pMonitorId.ToString(), szPath);
+ PInvoke.CoTaskMemFree(pMonitorId);
pMonitorId = default;
}
@@ -43,8 +46,9 @@ public unsafe void SetDesktopWallpaper(string szPath)
public unsafe void SetDesktopSlideshow(string[] aszPaths)
{
// Instantiate IDesktopWallpaper
- using ComPtr pDesktopWallpaper = default;
- HRESULT hr = pDesktopWallpaper.CoCreateInstance(CLSID.CLSID_DesktopWallpaper);
+ HRESULT hr = PInvoke.CoCreateInstance(typeof(DesktopWallpaper).GUID, null, CLSCTX.CLSCTX_LOCAL_SERVER, out IDesktopWallpaper? pDesktopWallpaper);
+ if (hr.Failed || pDesktopWallpaper is null)
+ return;
uint dwCount = (uint)aszPaths.Length;
ITEMIDLIST** ppItemIdList = stackalloc ITEMIDLIST*[aszPaths.Length];
@@ -54,16 +58,15 @@ public unsafe void SetDesktopSlideshow(string[] aszPaths)
ppItemIdList[dwIndex] = PInvoke.ILCreateFromPath(aszPaths[dwIndex]);
// Get an IShellItemArray from the array of the PIDL
- using ComPtr pShellItemArray = default;
- hr = PInvoke.SHCreateShellItemArrayFromIDLists(dwCount, ppItemIdList, pShellItemArray.GetAddressOf());
+ hr = PInvoke.SHCreateShellItemArrayFromIDLists(dwCount, ppItemIdList, out IShellItemArray pShellItemArray);
// Release the allocated PIDL
for (uint dwIndex = 0u; dwIndex < dwCount; dwIndex++)
PInvoke.CoTaskMemFree((void*)ppItemIdList[dwIndex]);
// Set the slideshow and its position
- hr = pDesktopWallpaper.Get()->SetSlideshow(pShellItemArray.Get());
- hr = pDesktopWallpaper.Get()->SetPosition(DESKTOP_WALLPAPER_POSITION.DWPOS_FILL);
+ hr = pDesktopWallpaper.SetSlideshow(pShellItemArray);
+ hr = pDesktopWallpaper.SetPosition(DESKTOP_WALLPAPER_POSITION.DWPOS_FILL);
}
///
diff --git a/src/Files.App/Utils/Shell/DetectionAndSharingHelper.cs b/src/Files.App/Utils/Shell/DetectionAndSharingHelper.cs
index c58e6f34d633..5c99a315946f 100644
--- a/src/Files.App/Utils/Shell/DetectionAndSharingHelper.cs
+++ b/src/Files.App/Utils/Shell/DetectionAndSharingHelper.cs
@@ -13,13 +13,13 @@ internal static class DetectionAndSharingHelper
{
public static unsafe NetworkAvailability GetNetworkAvailability()
{
- using ComPtr dtsh = CreateDetectionAndSharing();
+ IDetectionAndSharing dtsh = CreateDetectionAndSharing();
var availability = NetworkAvailability.None;
- if (IsEnabled(dtsh.Get(), DTSH_TYPE.DTSH_NETWORK_DISCOVERY))
+ if (IsEnabled(dtsh, DTSH_TYPE.DTSH_NETWORK_DISCOVERY))
availability |= NetworkAvailability.Discovery;
- if (IsEnabled(dtsh.Get(), DTSH_TYPE.DTSH_FILE_SHARING))
+ if (IsEnabled(dtsh, DTSH_TYPE.DTSH_FILE_SHARING))
availability |= NetworkAvailability.Sharing;
return availability;
@@ -27,32 +27,28 @@ public static unsafe NetworkAvailability GetNetworkAvailability()
public static unsafe void OpenNetworkSharingSettings()
{
- using ComPtr controlPanel = default;
- HRESULT hr = controlPanel.CoCreateInstance(CLSID.CLSID_OpenControlPanel, null, CLSCTX.CLSCTX_INPROC_SERVER);
+ HRESULT hr = PInvoke.CoCreateInstance(CLSID.CLSID_OpenControlPanel, null, CLSCTX.CLSCTX_INPROC_SERVER, out IOpenControlPanel? controlPanel);
ThrowIfFailed(hr, "Failed to create open control panel object.");
fixed (char* name = "Microsoft.NetworkAndSharingCenter")
fixed (char* page = "Advanced")
{
- hr = controlPanel.Get()->Open(name, page, null);
+ hr = controlPanel!.Open(name, page, null);
ThrowIfFailed(hr, "Failed to open advanced sharing settings.");
}
}
- private static unsafe ComPtr CreateDetectionAndSharing()
+ private static unsafe IDetectionAndSharing CreateDetectionAndSharing()
{
- ComPtr dtsh = default;
- HRESULT hr = dtsh.CoCreateInstance(CLSID.CLSID_DetectionAndSharing, null, CLSCTX.CLSCTX_INPROC_SERVER);
+ HRESULT hr = PInvoke.CoCreateInstance(CLSID.CLSID_DetectionAndSharing, null, CLSCTX.CLSCTX_INPROC_SERVER, out IDetectionAndSharing? dtsh);
ThrowIfFailed(hr, "Failed to create detection and sharing object.");
- return dtsh;
+ return dtsh!;
}
- private static unsafe bool IsEnabled(IDetectionAndSharing* dtsh, DTSH_TYPE type)
+ private static unsafe bool IsEnabled(IDetectionAndSharing dtsh, DTSH_TYPE type)
{
- DTSH_STATE state;
- DTSH_ACTION action;
- HRESULT hr = dtsh->GetStatus(type, &state, &action);
+ HRESULT hr = dtsh.GetStatus(type, out DTSH_STATE state, out _);
ThrowIfFailed(hr, $"Failed to get {type} status.");
return state is DTSH_STATE.DTSH_ON;
diff --git a/src/Files.App/Utils/Shell/ItemStreamHelper.cs b/src/Files.App/Utils/Shell/ItemStreamHelper.cs
index 61b3c816b579..065b892bd0c1 100644
--- a/src/Files.App/Utils/Shell/ItemStreamHelper.cs
+++ b/src/Files.App/Utils/Shell/ItemStreamHelper.cs
@@ -1,46 +1,31 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// Licensed under the MIT License.
-using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.System.Com;
+using Windows.Win32.UI.Shell;
namespace Files.App.Utils.Shell
{
public static class ItemStreamHelper
{
- static readonly Guid IShellItemIid = Guid.ParseExact("43826d1e-e718-42ee-bc55-a1e261c37bfe", "d");
-
- public static unsafe IntPtr IShellItemFromPath(string path)
+ public static IShellItem? IShellItemFromPath(string path)
{
- void* psi;
- Guid iid = IShellItemIid;
- var hr = PInvoke.SHCreateItemFromParsingName(path, null, ref iid, out psi);
- if ((int)hr < 0)
- return IntPtr.Zero;
- return (IntPtr)psi;
+ var hr = PInvoke.SHCreateItemFromParsingName(path, null!, out IShellItem psi);
+ return hr.Failed ? null : psi;
}
- public static unsafe IntPtr IStreamFromPath(string path)
+ public static IStream? IStreamFromPath(string path)
{
- IStream* pstm;
var hr = PInvoke.SHCreateStreamOnFileEx(
path,
(uint)(STGM.STGM_READ | STGM.STGM_FAILIFTHERE | STGM.STGM_SHARE_DENY_NONE),
0,
false,
null,
- &pstm);
-
- if ((int)hr < 0)
- return IntPtr.Zero;
+ out IStream pstm);
- return (IntPtr)pstm;
- }
-
- public static void ReleaseObject(IntPtr obj)
- {
- Marshal.Release(obj);
+ return hr.Failed ? null : pstm;
}
}
}
diff --git a/src/Files.App/Utils/Shell/LaunchHelper.cs b/src/Files.App/Utils/Shell/LaunchHelper.cs
index 1ca4da412470..3c59b9b0e776 100644
--- a/src/Files.App/Utils/Shell/LaunchHelper.cs
+++ b/src/Files.App/Utils/Shell/LaunchHelper.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// Licensed under the MIT License.
using Files.Shared.Helpers;
@@ -7,6 +7,7 @@
using Vanara.PInvoke;
using Vanara.Windows.Shell;
using Windows.Win32;
+using Windows.Win32.System.Com;
using Windows.Win32.UI.Shell;
namespace Files.App.Utils.Shell
@@ -18,10 +19,9 @@ public static class LaunchHelper
{
public unsafe static void LaunchSettings(string page)
{
- using ComPtr pApplicationActivationManager = default;
- pApplicationActivationManager.CoCreateInstance(CLSID.CLSID_ApplicationActivationManager);
+ PInvoke.CoCreateInstance(typeof(ApplicationActivationManager).GUID, null, CLSCTX.CLSCTX_LOCAL_SERVER, out IApplicationActivationManager? pApplicationActivationManager);
- pApplicationActivationManager.Get()->ActivateApplication(
+ pApplicationActivationManager!.ActivateApplication(
"windows.immersivecontrolpanel_cw5n1h2txyewy!microsoft.windows.immersivecontrolpanel",
page,
ACTIVATEOPTIONS.AO_NONE,
diff --git a/src/Files.App/Utils/Shell/OpenWithMenu.cs b/src/Files.App/Utils/Shell/OpenWithMenu.cs
index 0cd4b34db816..c4b5350c5427 100644
--- a/src/Files.App/Utils/Shell/OpenWithMenu.cs
+++ b/src/Files.App/Utils/Shell/OpenWithMenu.cs
@@ -19,11 +19,11 @@ internal sealed class OpenWithMenu : IDisposable
private static readonly ImageConverter IconConverter = new();
private readonly ThreadWithMessageQueue owningThread;
- private unsafe IContextMenu* contextMenu;
+ private IContextMenu? contextMenu;
private HMENU menu;
private bool disposedValue;
- private unsafe OpenWithMenu(IContextMenu* contextMenu, HMENU menu, ThreadWithMessageQueue owningThread)
+ private OpenWithMenu(IContextMenu contextMenu, HMENU menu, ThreadWithMessageQueue owningThread)
{
this.contextMenu = contextMenu;
this.menu = menu;
@@ -51,21 +51,15 @@ private unsafe OpenWithMenu(IContextMenu* contextMenu, HMENU menu, ThreadWithMes
public async Task InvokeItem(int itemId)
{
- unsafe
- {
- if (itemId < 0 || contextMenu is null)
- return false;
- }
+ if (itemId < 0 || contextMenu is null)
+ return false;
try
{
var currentWindows = Win32Helper.GetDesktopWindows();
var hr = await owningThread.PostMethod(() =>
{
- unsafe
- {
- return InvokeItemCore(itemId);
- }
+ return InvokeItemCore(itemId);
});
if (hr.Failed)
return false;
@@ -94,50 +88,38 @@ private unsafe HRESULT InvokeItemCore(int itemId)
nShow = (int)SHOW_WINDOW_CMD.SW_SHOWNORMAL,
};
- return contextMenu->InvokeCommand(&commandInfo);
+ return contextMenu.InvokeCommand(commandInfo);
}
private static unsafe OpenWithMenu? Create(string path, ThreadWithMessageQueue owningThread)
{
- IContextMenu* openWithContextMenu = default;
+ IContextMenu? openWithContextMenu = null;
HMENU hMenu = default;
try
{
- using ComPtr openWithContextMenu2 = default;
- using ComPtr shellExtInit = default;
- using ComPtr shellItem = default;
- using ComPtr dataObject = default;
-
- HRESULT hr = PInvoke.CoCreateInstance(CLSID.CLSID_OpenWithMenu, null, CLSCTX.CLSCTX_INPROC_SERVER, IID.IID_IContextMenu, (void**)&openWithContextMenu);
- if (hr.ThrowIfFailedOnDebug().Failed)
+ HRESULT hr = PInvoke.CoCreateInstance(CLSID.CLSID_OpenWithMenu, null, CLSCTX.CLSCTX_INPROC_SERVER, out openWithContextMenu);
+ if (hr.ThrowIfFailedOnDebug().Failed || openWithContextMenu is null)
return null;
- hr = openWithContextMenu->QueryInterface(IID.IID_IContextMenu2, (void**)openWithContextMenu2.GetAddressOf());
- if (hr.ThrowIfFailedOnDebug().Failed)
+ if (openWithContextMenu is not IContextMenu2 openWithContextMenu2 ||
+ openWithContextMenu is not IShellExtInit shellExtInit)
return null;
- hr = openWithContextMenu->QueryInterface(IID.IID_IShellExtInit, (void**)shellExtInit.GetAddressOf());
+ hr = PInvoke.SHCreateItemFromParsingName(path, null, out IShellItem shellItem);
if (hr.ThrowIfFailedOnDebug().Failed)
return null;
- fixed (char* pathPtr = path)
- {
- hr = PInvoke.SHCreateItemFromParsingName(pathPtr, null, IID.IID_IShellItem, (void**)shellItem.GetAddressOf());
- }
- if (hr.ThrowIfFailedOnDebug().Failed)
+ hr = shellItem.BindToHandler(null, PInvoke.BHID_DataObject, out IDataObject? dataObject);
+ if (hr.ThrowIfFailedOnDebug().Failed || dataObject is null)
return null;
- hr = shellItem.Get()->BindToHandler(null, BHID.BHID_DataObject, IID.IID_IDataObject, (void**)dataObject.GetAddressOf());
- if (hr.ThrowIfFailedOnDebug().Failed)
- return null;
-
- hr = shellExtInit.Get()->Initialize(null, dataObject.Get(), default);
+ hr = shellExtInit.Initialize(null, dataObject, null);
if (hr.ThrowIfFailedOnDebug().Failed)
return null;
hMenu = PInvoke.CreatePopupMenu();
- hr = openWithContextMenu->QueryContextMenu(hMenu, 0, 1, 256, 0);
+ hr = openWithContextMenu.QueryContextMenu(hMenu, 0, 1, 256, 0);
if (hr.ThrowIfFailedOnDebug().Failed)
return null;
@@ -145,12 +127,12 @@ private unsafe HRESULT InvokeItemCore(int itemId)
if (hSubMenu.IsNull)
return null;
- hr = openWithContextMenu2.Get()->HandleMenuMsg(PInvoke.WM_INITMENUPOPUP, (WPARAM)(nuint)hSubMenu.Value, 0);
+ hr = openWithContextMenu2.HandleMenuMsg(PInvoke.WM_INITMENUPOPUP, (WPARAM)(nuint)hSubMenu.Value, 0);
if (hr.ThrowIfFailedOnDebug().Failed)
return null;
var openWithMenu = new OpenWithMenu(openWithContextMenu, hMenu, owningThread);
- openWithContextMenu = default;
+ openWithContextMenu = null;
hMenu = default;
openWithMenu.EnumMenuItems(hSubMenu);
@@ -165,9 +147,6 @@ private unsafe HRESULT InvokeItemCore(int itemId)
{
if (!hMenu.IsNull)
PInvoke.DestroyMenu(hMenu);
-
- if (openWithContextMenu is not null)
- openWithContextMenu->Release();
}
}
@@ -277,14 +256,7 @@ public void Dispose()
menu = default;
}
- unsafe
- {
- if (contextMenu is not null)
- {
- contextMenu->Release();
- contextMenu = null;
- }
- }
+ contextMenu = null;
owningThread.Dispose();
disposedValue = true;
diff --git a/src/Files.App/Utils/Shell/PreviewHandler.cs b/src/Files.App/Utils/Shell/PreviewHandler.cs
index f153dd76ed49..12d70b0ab1fd 100644
--- a/src/Files.App/Utils/Shell/PreviewHandler.cs
+++ b/src/Files.App/Utils/Shell/PreviewHandler.cs
@@ -1,9 +1,14 @@
-using System.Runtime.InteropServices;
+using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using Windows.UI;
using Windows.Win32;
using Windows.Win32.Foundation;
+using Windows.Win32.Graphics.Gdi;
using Windows.Win32.System.Com;
+using Windows.Win32.System.Ole;
+using Windows.Win32.UI.Shell;
+using Windows.Win32.UI.Shell.PropertiesSystem;
+using Windows.Win32.UI.WindowsAndMessaging;
namespace Files.App.Utils.Shell
{
@@ -12,129 +17,43 @@ namespace Files.App.Utils.Shell
///
public sealed partial class PreviewHandler : IDisposable
{
- const int S_OK = 0;
- const int S_FALSE = 1;
- const int E_FAIL = unchecked((int)0x80004005);
- const int E_SERVER_EXEC_FAILURE = unchecked((int)0x80080005);
-
- [StructLayout(LayoutKind.Sequential)]
- public struct RECT(int left, int top, int right, int bottom)
- {
- public int Left = left;
- public int Top = top;
- public int Right = right;
- public int Bottom = bottom;
- }
-
- #region IPreviewHandlerFrame support
-
- [StructLayout(LayoutKind.Sequential)]
- public struct PreviewHandlerFrameInfo
- {
- public IntPtr AcceleratorTableHandle;
- public uint AcceleratorEntryCount;
- }
-
- [GeneratedComInterface, Guid("fec87aaf-35f9-447a-adb7-20234491401a"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- public partial interface IPreviewHandlerFrame
- {
- [PreserveSig]
- int GetWindowContext(out PreviewHandlerFrameInfo pinfo);
- [PreserveSig]
- int TranslateAccelerator(nint pmsg);
- }
-
[GeneratedComClass]
- public sealed partial class PreviewHandlerFrame : IPreviewHandlerFrame, IDisposable
+ public sealed partial class PreviewHandlerFrame : IPreviewHandlerFrame
{
- bool disposed;
nint hwnd;
public PreviewHandlerFrame(nint frame)
{
- disposed = true;
- disposed = false;
hwnd = frame;
}
- public void Dispose()
+ [return: MarshalAs(UnmanagedType.Error)]
+ public unsafe HRESULT GetWindowContext(PREVIEWHANDLERFRAMEINFO* pinfo)
{
- disposed = true;
+ pinfo->haccel = HACCEL.Null;
+ pinfo->cAccelEntries = 0;
+ return HRESULT.S_OK;
}
- public int GetWindowContext(out PreviewHandlerFrameInfo pinfo)
+ [return: MarshalAs(UnmanagedType.Error)]
+ public unsafe HRESULT TranslateAccelerator(MSG* pmsg)
{
- pinfo.AcceleratorTableHandle = IntPtr.Zero;
- pinfo.AcceleratorEntryCount = 0;
- if (disposed)
- return E_FAIL;
- return S_OK;
+ return HRESULT.S_FALSE;
}
-
- public int TranslateAccelerator(nint pmsg)
- {
- if (disposed)
- return E_FAIL;
- return S_FALSE;
- }
- }
-
- #endregion IPreviewHandlerFrame support
-
- #region IPreviewHandler major interfaces
-
- [GeneratedComInterface, Guid("8895b1c6-b41f-4c1c-a562-0d564250836f"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- internal partial interface IPreviewHandler
- {
- [PreserveSig]
- int SetWindow(nint hwnd, in RECT prc);
- [PreserveSig]
- int SetRect(in RECT prc);
- [PreserveSig]
- int DoPreview();
- [PreserveSig]
- int Unload();
- [PreserveSig]
- int SetFocus();
- [PreserveSig]
- int QueryFocus(out nint phwnd);
- // TranslateAccelerator is not used here.
- }
-
- [GeneratedComInterface, Guid("196bf9a5-b346-4ef0-aa1e-5dcdb76768b1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- internal partial interface IPreviewHandlerVisuals
- {
- [PreserveSig]
- int SetBackgroundColor(uint color);
- [PreserveSig]
- int SetFont(nint plf);
- [PreserveSig]
- int SetTextColor(uint color);
- }
-
- static uint ColorRefFromColor(Color color)
- {
- return (((uint)color.B) << 16) | (((uint)color.G) << 8) | ((uint)color.R);
}
- [GeneratedComInterface, Guid("fc4801a3-2ba9-11cf-a229-00aa003d7352"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- internal partial interface IObjectWithSite
+ static COLORREF ColorRefFromColor(Color color)
{
- [PreserveSig]
- int SetSite(nint pUnkSite);
- // GetSite is not used.
+ return new COLORREF((((uint)color.B) << 16) | (((uint)color.G) << 8) | color.R);
}
- #endregion IPreviewHandler major interfaces
-
bool disposed;
bool init;
bool shown;
PreviewHandlerFrame? comSite;
- nint hwnd;
+ HWND hwnd;
IPreviewHandler? previewHandler;
IPreviewHandlerVisuals? visuals;
- readonly ComWrappers comWrappers = new StrategyBasedComWrappers();
public PreviewHandler(Guid clsid, nint frame)
{
@@ -142,7 +61,7 @@ public PreviewHandler(Guid clsid, nint frame)
init = false;
shown = false;
comSite = new PreviewHandlerFrame(frame);
- hwnd = frame;
+ hwnd = (HWND)frame;
try
{
SetupHandler(clsid);
@@ -151,110 +70,40 @@ public PreviewHandler(Guid clsid, nint frame)
catch
{
previewHandler = null;
- comSite.Dispose();
comSite = null;
throw;
}
}
- static readonly Guid IPreviewHandlerIid = Guid.ParseExact("8895b1c6-b41f-4c1c-a562-0d564250836f", "d");
-
- unsafe void SetupHandler(Guid clsid)
+ void SetupHandler(Guid clsid)
{
- void* pphRaw;
- var iid = IPreviewHandlerIid;
var cannotCreate = "Cannot create class " + clsid.ToString() + " as IPreviewHandler.";
var cannotCast = "Cannot cast class " + clsid.ToString() + " as IObjectWithSite.";
var cannotSetSite = "Cannot set site to the preview handler object.";
- // Important: manully calling CoCreateInstance is necessary.
- // If we use Activator.CreateInstance(Type.GetTypeFromCLSID(...)),
- // CLR will allow in-process server, which defeats isolation and
- // creates strange bugs.
- HRESULT hr = PInvoke.CoCreateInstance(&clsid, null, CLSCTX.CLSCTX_LOCAL_SERVER, &iid, &pphRaw);
- IntPtr pph = (IntPtr)pphRaw;
+
+ HRESULT hr = PInvoke.CoCreateInstance(clsid, null, CLSCTX.CLSCTX_LOCAL_SERVER, out previewHandler);
+
// See https://blogs.msdn.microsoft.com/adioltean/2005/06/24/when-cocreateinstance-returns-0x80080005-co_e_server_exec_failure/
// CO_E_SERVER_EXEC_FAILURE also tends to happen when debugging in Visual Studio.
// Moreover, to create the instance in a server at low integrity level, we need
// to use another thread with low mandatory label. We keep it simple by creating
// a same-integrity object.
- if (hr.Value == E_SERVER_EXEC_FAILURE)
- {
- hr = PInvoke.CoCreateInstance(&clsid, null, CLSCTX.CLSCTX_LOCAL_SERVER, &iid, &pphRaw);
- pph = (IntPtr)pphRaw;
- }
+ //if (hr.Value == E_SERVER_EXEC_FAILURE)
+ // hr = PInvoke.CoCreateInstance(clsid, null, CLSCTX.CLSCTX_LOCAL_SERVER, out previewHandlerObject);
+
if (hr.Failed)
throw new COMException(cannotCreate, hr.Value);
- var previewHandlerObject = comWrappers.GetOrCreateObjectForComInstance(pph, CreateObjectFlags.UniqueInstance);
- previewHandler = previewHandlerObject as IPreviewHandler;
-
- if (previewHandler == null)
- {
- throw new COMException(cannotCreate);
- }
- var objectWithSite = previewHandlerObject as IObjectWithSite;
- if (objectWithSite == null)
- throw new COMException(cannotCast);
- int setSiteHr = objectWithSite.SetSite(comWrappers.GetOrCreateComInterfaceForObject(comSite, CreateComInterfaceFlags.None));
- if (setSiteHr < 0)
- throw new COMException(cannotSetSite, setSiteHr);
- visuals = previewHandlerObject as IPreviewHandlerVisuals;
- }
-
- #region Initialization interfaces
- [GeneratedComInterface, Guid("0000000c-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- public partial interface IStream
- {
- // ISequentialStream portion
- void Read([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), Out] byte[] pv, int cb, nint pcbRead);
- void Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, nint pcbWritten);
-
- // IStream portion
- void Seek(long dlibMove, int dwOrigin, nint plibNewPosition);
- void SetSize(long libNewSize);
- void CopyTo(IStream pstm, long cb, nint pcbRead, nint pcbWritten);
- void Commit(int grfCommitFlags);
- void Revert();
- void LockRegion(long libOffset, long cb, int dwLockType);
- void UnlockRegion(long libOffset, long cb, int dwLockType);
- }
-
- [GeneratedComInterface, Guid("b824b49d-22ac-4161-ac8a-9916e8fa3f7f"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- internal partial interface IInitializeWithStream
- {
- [PreserveSig]
- int Initialize(IStream psi, STGM grfMode);
- }
-
- [GeneratedComInterface, Guid("b824b49d-22ac-4161-ac8a-9916e8fa3f7f"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- internal partial interface IInitializeWithStreamNative
- {
- [PreserveSig]
- int Initialize(IntPtr psi, STGM grfMode);
- }
-
- static readonly Guid IInitializeWithStreamIid = Guid.ParseExact("b824b49d-22ac-4161-ac8a-9916e8fa3f7f", "d");
-
- [GeneratedComInterface, Guid("b7d14566-0509-4cce-a71f-0a554233bd9b"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- internal partial interface IInitializeWithFile
- {
- [PreserveSig]
- int Initialize([MarshalAs(UnmanagedType.LPWStr)] string pszFilePath, STGM grfMode);
- }
+ if (previewHandler is not IObjectWithSite objectWithSite)
+ throw new COMException(cannotCast, HRESULT.E_NOINTERFACE.Value);
- static readonly Guid IInitializeWithFileIid = Guid.ParseExact("b7d14566-0509-4cce-a71f-0a554233bd9b", "d");
+ hr = objectWithSite.SetSite(comSite!);
+ if (hr.Failed)
+ throw new COMException(cannotSetSite, hr.Value);
- [GeneratedComInterface, Guid("7f73be3f-fb79-493c-a6c7-7ee14e245841"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- internal partial interface IInitializeWithItem
- {
- [PreserveSig]
- int Initialize(IntPtr psi, STGM grfMode);
+ visuals = previewHandler as IPreviewHandlerVisuals;
}
- static readonly Guid IInitializeWithItemIid = Guid.ParseExact("7f73be3f-fb79-493c-a6c7-7ee14e245841", "d");
-
- #endregion
-
///
/// Tries to initialize the preview handler with an IStream.
///
@@ -267,41 +116,18 @@ public bool InitWithStream(IStream stream, STGM mode)
{
if (mode != STGM.STGM_READ && mode != STGM.STGM_READWRITE)
throw new ArgumentOutOfRangeException("mode", mode, "The argument mode must be Read or ReadWrite.");
- var iws = previewHandler as IInitializeWithStream;
- if (iws == null)
- return false;
- var hr = iws.Initialize(stream, mode);
- if (hr == (int)HRESULT.E_NOTIMPL)
- return false;
- if (hr < 0)
- throw new COMException("IInitializeWithStream.Initialize failed.", hr);
- init = true;
- return true;
- }
- ///
- /// Same as InitWithStream(IStream, STGM).
- ///
- /// See InitWithStream(IStream, STGM).
- /// See InitWithStream(IStream, STGM).
- /// The native pointer to the IStream interface.
- /// The storage mode.
- /// True or false, see InitWithStream(IStream, STGM).
- public bool InitWithStream(IntPtr pStream, STGM mode)
- {
- EnsureNotDisposed();
- EnsureNotInitialized();
- if (mode != STGM.STGM_READ && mode != STGM.STGM_READWRITE)
- throw new ArgumentOutOfRangeException("mode", mode, "The argument mode must be Read or ReadWrite.");
- var iws = previewHandler as IInitializeWithStreamNative;
- if (iws == null)
+ if (previewHandler is not IInitializeWithStream initializeWithStream)
return false;
- var hr = iws.Initialize(pStream, mode);
- if (hr == (int)HRESULT.E_NOTIMPL)
+
+ HRESULT hr = initializeWithStream.Initialize(stream, (uint)mode);
+ if (hr == HRESULT.E_NOTIMPL)
return false;
- if (hr < 0)
- throw new COMException("IInitializeWithStream.Initialize failed.", hr);
+ if (hr.Failed)
+ throw new COMException("IInitializeWithStream.Initialize failed.", hr.Value);
+
init = true;
+
return true;
}
@@ -310,24 +136,28 @@ public bool InitWithStream(IntPtr pStream, STGM mode)
///
/// See InitWithStream(IStream, STGM).
/// See InitWithStream(IStream, STGM).
- /// The native pointer to the IShellItem interface.
+ /// The IShellItem interface used to initialize the preview handler.
/// The storage mode.
/// True or false, see InitWithStream(IStream, STGM).
- public bool InitWithItem(IntPtr psi, STGM mode)
+ public bool InitWithItem(IShellItem psi, STGM mode)
{
EnsureNotDisposed();
EnsureNotInitialized();
+
if (mode != STGM.STGM_READ && mode != STGM.STGM_READWRITE)
throw new ArgumentOutOfRangeException("mode", mode, "The argument mode must be Read or ReadWrite.");
- var iwi = previewHandler as IInitializeWithItem;
- if (iwi == null)
+
+ if (previewHandler is not IInitializeWithItem initializeWithItem)
return false;
- var hr = iwi.Initialize(psi, mode);
- if (hr == (int)HRESULT.E_NOTIMPL)
+
+ HRESULT hr = initializeWithItem.Initialize(psi, (uint)mode);
+ if (hr == HRESULT.E_NOTIMPL)
return false;
- if (hr < 0)
- throw new COMException("IInitializeWithItem.Initialize failed.", hr);
+ if (hr.Failed)
+ throw new COMException("IInitializeWithItem.Initialize failed.", hr.Value);
+
init = true;
+
return true;
}
@@ -343,17 +173,21 @@ public bool InitWithFile(string path, STGM mode)
{
EnsureNotDisposed();
EnsureNotInitialized();
+
if (mode != STGM.STGM_READ && mode != STGM.STGM_READWRITE)
throw new ArgumentOutOfRangeException("mode", mode, "The argument mode must be Read or ReadWrite.");
- var iwf = previewHandler as IInitializeWithFile;
- if (iwf == null)
+
+ if (previewHandler is not IInitializeWithFile initializeWithFile)
return false;
- var hr = iwf.Initialize(path, mode);
- if (hr == (int)HRESULT.E_NOTIMPL)
+
+ HRESULT hr = initializeWithFile.Initialize(path, (uint)mode);
+ if (hr == HRESULT.E_NOTIMPL)
return false;
- if (hr < 0)
- throw new COMException("IInitializeWithFile.Initialize failed.", hr);
+ if (hr.Failed)
+ throw new COMException("IInitializeWithFile.Initialize failed.", hr.Value);
+
init = true;
+
return true;
}
@@ -365,7 +199,6 @@ public bool InitWithFile(string path, STGM mode)
public bool InitWithFileWithEveryWay(string path)
{
var exceptions = new List();
- var pobj = IntPtr.Zero;
// Why should we try IStream first?
// Because that gives us the best security.
// If we initialize with string or IShellItem,
@@ -374,21 +207,15 @@ public bool InitWithFileWithEveryWay(string path)
// file for read/write exclusively.
try
{
- pobj = ItemStreamHelper.IStreamFromPath(path);
- if (pobj != IntPtr.Zero
- && InitWithStream(pobj, STGM.STGM_READ))
+ var stream = ItemStreamHelper.IStreamFromPath(path);
+ if (stream is not null && InitWithStream(stream, STGM.STGM_READ))
return true;
}
catch (Exception ex)
{
exceptions.Add(ex);
}
- finally
- {
- if (pobj != IntPtr.Zero)
- ItemStreamHelper.ReleaseObject(pobj);
- pobj = IntPtr.Zero;
- }
+
// Next try file because that could save us some P/Invokes.
try
{
@@ -401,9 +228,8 @@ public bool InitWithFileWithEveryWay(string path)
}
try
{
- pobj = ItemStreamHelper.IShellItemFromPath(path);
- if (pobj != IntPtr.Zero
- && InitWithItem(pobj, STGM.STGM_READ))
+ var shellItem = ItemStreamHelper.IShellItemFromPath(path);
+ if (shellItem is not null && InitWithItem(shellItem, STGM.STGM_READ))
return true;
if (exceptions.Count == 0)
throw new NotSupportedException("The object cannot be initialized at all.");
@@ -412,12 +238,7 @@ public bool InitWithFileWithEveryWay(string path)
{
exceptions.Add(ex);
}
- finally
- {
- if (pobj != IntPtr.Zero)
- ItemStreamHelper.ReleaseObject(pobj);
- pobj = IntPtr.Zero;
- }
+
throw new AggregateException(exceptions);
}
@@ -430,7 +251,7 @@ public bool ResetWindow()
//EnsureInitialized();
if (!init)
return false;
- var hr = previewHandler.SetWindow(hwnd, new());
+ var hr = previewHandler.SetWindow(hwnd, new RECT());
return hr >= 0;
}
@@ -474,9 +295,9 @@ public bool SetForeground(Color color)
///
/// The LogFontW reference.
/// Whether the call succeeds.
- public bool SetFont(nint font)
+ public unsafe bool SetFont(nint font)
{
- var hr = visuals?.SetFont(font);
+ var hr = visuals?.SetFont(*(LOGFONTW*)font);
return hr.HasValue && hr.Value >= 0;
}
@@ -519,11 +340,12 @@ public nint QueryFocus()
if (!init)
return IntPtr.Zero;
EnsureShown();
- nint result;
- var hr = previewHandler.QueryFocus(out result);
+
+ var hr = previewHandler.QueryFocus(out var result);
if (hr < 0)
return IntPtr.Zero;
- return result;
+
+ return (nint)result;
}
void EnsureNotDisposed()
@@ -571,7 +393,7 @@ public void Dispose()
init = false;
previewHandler?.Unload();
- comSite?.Dispose();
+ comSite = null;
GC.SuppressFinalize(this);
}
diff --git a/src/Files.App/Utils/Storage/Helpers/MtpHelpers.cs b/src/Files.App/Utils/Storage/Helpers/MtpHelpers.cs
index 955b58797f79..7bb901b506ab 100644
--- a/src/Files.App/Utils/Storage/Helpers/MtpHelpers.cs
+++ b/src/Files.App/Utils/Storage/Helpers/MtpHelpers.cs
@@ -17,14 +17,19 @@ public static class MtpHelpers
/// Resolves a \\?\DeviceName\path to a shell Portable Devices namespace path
/// so that shell APIs like work correctly.
///
- public unsafe static string? ResolveMtpShellPath(string mtpPath)
+ public static string? ResolveMtpShellPath(string mtpPath)
{
var withoutPrefix = mtpPath.AsSpan(4);
var sep = withoutPrefix.IndexOf('\\');
var deviceName = (sep >= 0 ? withoutPrefix[..sep] : withoutPrefix).ToString();
if (!_deviceParsingNames.TryGetValue(deviceName, out var parsingName))
- _deviceParsingNames[deviceName] = parsingName = FindDeviceParsingName(deviceName);
+ {
+ unsafe
+ {
+ _deviceParsingNames[deviceName] = parsingName = FindDeviceParsingName(deviceName);
+ }
+ }
return parsingName is null ? null
: sep >= 0 ? Path.Combine(parsingName, withoutPrefix[(sep + 1)..].ToString())
@@ -33,33 +38,30 @@ public static class MtpHelpers
private unsafe static string? FindDeviceParsingName(string deviceName)
{
- using ComPtr pComputer = default;
- Guid folderId = new("0AC0837C-BBF8-452A-850D-79D08E667CA7");
- PInvoke.SHGetKnownFolderItem(&folderId, KNOWN_FOLDER_FLAG.KF_FLAG_DEFAULT, HANDLE.Null, IID.IID_IShellItem, (void**)pComputer.GetAddressOf());
-
- if (pComputer.IsNull)
+ HRESULT hr = PInvoke.SHGetKnownFolderItem(FOLDERID.FOLDERID_ComputerFolder, KNOWN_FOLDER_FLAG.KF_FLAG_DEFAULT, null, out IShellItem computerFolderItem);
+ if (hr.ThrowIfFailedOnDebug().Failed)
return null;
- using ComPtr pEnum = default;
- pComputer.Get()->BindToHandler(null, BHID.BHID_EnumItems, IID.IID_IEnumShellItems, (void**)pEnum.GetAddressOf());
-
- if (pEnum.IsNull)
+ hr = computerFolderItem.BindToHandler(null, PInvoke.BHID_EnumItems, out IEnumShellItems? pEnum);
+ if (hr.ThrowIfFailedOnDebug().Failed || pEnum is null)
return null;
+ IShellItem[] children = new IShellItem[1];
while (true)
{
- using ComPtr pChild = default;
- if (pEnum.Get()->Next(1, pChild.GetAddressOf()) != HRESULT.S_OK)
+ if (pEnum.Next(children) != HRESULT.S_OK)
break;
- pChild.Get()->GetDisplayName(SIGDN.SIGDN_NORMALDISPLAY, out var szName);
+ IShellItem pChild = children[0];
+
+ pChild.GetDisplayName(SIGDN.SIGDN_NORMALDISPLAY, out var szName);
var name = szName.ToString();
PInvoke.CoTaskMemFree(szName.Value);
if (!deviceName.StartsWith(name, StringComparison.OrdinalIgnoreCase))
continue;
- pChild.Get()->GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEPARSING, out var szParsing);
+ pChild.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEPARSING, out var szParsing);
var result = szParsing.ToString();
PInvoke.CoTaskMemFree(szParsing.Value);
return result;
diff --git a/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs b/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs
index 042fb8564e1a..3f58d9be282e 100644
--- a/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs
+++ b/src/Files.App/Utils/Storage/Helpers/SyncRootHelpers.cs
@@ -1,17 +1,16 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// Licensed under the MIT License.
using Microsoft.Win32;
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 ||
@@ -19,29 +18,17 @@ private static unsafe (bool Success, ulong Capacity, ulong Used) GetSyncRootQuot
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;
- if (PInvoke.CoCreateInstance(
- &factoryClsid,
- null,
- CLSCTX.CLSCTX_LOCAL_SERVER,
- IID.IID_IStorageProviderStatusUISourceFactory,
- (void**)pStorageProviderStatusUISourceFactory.GetAddressOf()).ThrowIfFailedOnDebug().Failed)
+ if (PInvoke.CoCreateInstance(factoryClsid, null, CLSCTX.CLSCTX_LOCAL_SERVER, out IStorageProviderStatusUISourceFactory? pStorageProviderStatusUISourceFactory).ThrowIfFailedOnDebug().Failed ||
+ pStorageProviderStatusUISourceFactory is null)
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 (pStorageProviderStatusUISourceFactory.GetStatusUISource(syncRootId, out IStorageProviderStatusUISource pStorageProviderStatusUISource).ThrowIfFailedOnDebug().Failed ||
+ pStorageProviderStatusUISource.GetStatusUI(out IStorageProviderStatusUI pStorageProviderStatusUI).ThrowIfFailedOnDebug().Failed ||
+ pStorageProviderStatusUI.GetQuotaUI(out IStorageProviderQuotaUI pStorageProviderQuotaUI).ThrowIfFailedOnDebug().Failed ||
+ pStorageProviderQuotaUI.GetQuotaTotalInBytes(out ulTotalSize).ThrowIfFailedOnDebug().Failed ||
+ pStorageProviderQuotaUI.GetQuotaUsedInBytes(out ulUsedSize).ThrowIfFailedOnDebug().Failed)
+ return (false, 0, 0);
return (true, ulTotalSize, ulUsedSize);
}
diff --git a/src/Files.App/Utils/Taskbar/SystemTrayIconWindow.cs b/src/Files.App/Utils/Taskbar/SystemTrayIconWindow.cs
index 532ed33baf5f..a8256c52dacd 100644
--- a/src/Files.App/Utils/Taskbar/SystemTrayIconWindow.cs
+++ b/src/Files.App/Utils/Taskbar/SystemTrayIconWindow.cs
@@ -5,6 +5,7 @@
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
+using WNDPROC = Windows.Win32.Extras.ManagedWNDPROC;
namespace Files.App.Utils.Taskbar
{
diff --git a/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs b/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs
index d7dbab8ae08f..f105eaee105e 100644
--- a/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs
+++ b/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// Licensed under the MIT License.
using Files.App.Helpers;
@@ -19,6 +19,7 @@
using Windows.Win32.UI.Shell;
using Windows.Win32.UI.WindowsAndMessaging;
using WinRT;
+using WNDPROC = Windows.Win32.Extras.ManagedWNDPROC;
#pragma warning disable CS8305 // Type is for evaluation purposes only and is subject to change or removal in future updates.
@@ -186,45 +187,46 @@ 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? pD3D11Device = null;
+ ID3D11DeviceContext? pD3D11DeviceContext = null;
+ IDXGIDevice? pDXGIDevice = null;
+ object? pControlSurface = null;
+ IDCompositionVisual? pChildVisual = null;
// Create the D3D11 device
foreach (var driverType in driverTypes)
{
hr = PInvoke.D3D11CreateDevice(
- null, driverType, new(nint.Zero),
+ null!, driverType, new(nint.Zero),
D3D11_CREATE_DEVICE_FLAG.D3D11_CREATE_DEVICE_BGRA_SUPPORT,
- null, /* FeatureLevels */ 0, /* SDKVersion */ 7,
- pD3D11Device.GetAddressOf(), null,
- pD3D11DeviceContext.GetAddressOf());
+ ReadOnlySpan.Empty, /* SDKVersion */ 7,
+ out pD3D11Device,
+ out pD3D11DeviceContext);
if (hr.Succeeded)
break;
}
- if (pD3D11Device.IsNull)
+ if (pD3D11Device is null)
return false;
// Create the DComp device
- pDXGIDevice.Attach((IDXGIDevice*)pD3D11Device.Get());
- hr = PInvoke.DCompositionCreateDevice(
- pDXGIDevice.Get(),
- &IID_IDCompositionDevice,
- (void**)pDCompositionDevice.GetAddressOf());
+ pDXGIDevice = (IDXGIDevice)pD3D11Device;
+ hr = PInvoke.DCompositionCreateDevice(pDXGIDevice, out IDCompositionDevice pDCompositionDevice);
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 = pDCompositionDevice.CreateVisual(out pChildVisual);
+ if (hr.Failed)
+ return false;
+
+ hr = pDCompositionDevice.CreateSurfaceFromHwnd(_hWnd, out pControlSurface);
+ if (hr.Failed)
+ return false;
+
+ hr = pChildVisual.SetContent(pControlSurface);
+ if (hr.Failed || pChildVisual is null || pControlSurface is null)
return false;
// Get the compositor and set the visual on it
@@ -232,14 +234,14 @@ private unsafe bool ChildWindowToXaml(nint parent, UIElement presenter)
_contentExternalOutputLink = ContentExternalOutputLink.Create(compositor);
var target = _contentExternalOutputLink.As();
- target.SetRoot((nint)pChildVisual.Get());
+ target.SetRoot(pChildVisual);
_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();
+ pDCompositionDevice.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 1771114901a9..bf91920ce406 100644
--- a/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs
+++ b/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Files Community
+// Copyright (c) Files Community
// Licensed under the MIT License.
using Microsoft.UI.Input;
@@ -230,25 +230,20 @@ public override async Task ExecutePinToSidebarCommand(WidgetCardItem? item)
if (currentPinnedItemIndex is -1)
return;
- HRESULT hr = default;
- using ComPtr pAgileReference = default;
-
- unsafe
- {
- hr = PInvoke.RoGetAgileReference(AgileReferenceOptions.AGILEREFERENCE_DEFAULT, IID.IID_IShellItem, (IUnknown*)folderCardItem.Item.ThisPtr, pAgileReference.GetAddressOf());
- }
+ HRESULT hr = PInvoke.RoGetAgileReference(AgileReferenceOptions.AGILEREFERENCE_DEFAULT, typeof(IShellItem).GUID, folderCardItem.Item.ThisPtr, out IAgileReference pAgileReference);
+ if (hr.ThrowIfFailedOnDebug().Failed)
+ return;
// Pin to Quick Access on Windows
hr = await STATask.Run(() =>
{
- unsafe
- {
- IShellItem* pShellItem = null;
- hr = pAgileReference.Get()->Resolve(IID.IID_IShellItem, (void**)&pShellItem);
- using var windowsFile = new WindowsFile(pShellItem);
- // NOTE: "pintohome" is an undocumented verb, which calls an undocumented COM class, windows.storage.dll!CPinToFrequentExecute : public IExecuteCommand, ...
- return windowsFile.TryInvokeContextMenuVerb("pintohome");
- }
+ hr = pAgileReference.Resolve(out IShellItem pShellItem);
+ if (hr.ThrowIfFailedOnDebug().Failed)
+ return hr;
+
+ using var windowsFile = new WindowsFile(pShellItem);
+ // NOTE: "pintohome" is an undocumented verb, which calls an undocumented COM class, windows.storage.dll!CPinToFrequentExecute : public IExecuteCommand, ...
+ return windowsFile.TryInvokeContextMenuVerb("pintohome");
}, App.Logger);
// The file watcher will update the collection automatically
@@ -259,27 +254,22 @@ public override async Task ExecuteUnpinFromSidebarCommand(WidgetCardItem? item)
if (item is not WidgetFolderCardItem folderCardItem || folderCardItem.Path is null)
return;
- HRESULT hr = default;
- using ComPtr pAgileReference = default;
-
- unsafe
- {
- hr = PInvoke.RoGetAgileReference(AgileReferenceOptions.AGILEREFERENCE_DEFAULT, IID.IID_IShellItem, (IUnknown*)folderCardItem.Item.ThisPtr, pAgileReference.GetAddressOf());
- }
+ HRESULT hr = PInvoke.RoGetAgileReference(AgileReferenceOptions.AGILEREFERENCE_DEFAULT, typeof(IShellItem).GUID, folderCardItem.Item.ThisPtr, out IAgileReference pAgileReference);
+ if (hr.ThrowIfFailedOnDebug().Failed)
+ return;
// Unpin from Quick Access on Windows
hr = await STATask.Run(() =>
{
- unsafe
- {
- IShellItem* pShellItem = null;
- hr = pAgileReference.Get()->Resolve(IID.IID_IShellItem, (void**)&pShellItem);
- using var windowsFile = new WindowsFile(pShellItem);
+ hr = pAgileReference.Resolve(out IShellItem pShellItem);
+ if (hr.ThrowIfFailedOnDebug().Failed)
+ return hr;
- // 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
- return windowsFile.TryInvokeContextMenuVerbs(["unpinfromhome", "remove"], true);
- }
+ using var windowsFile = new WindowsFile(pShellItem);
+
+ // 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
+ return windowsFile.TryInvokeContextMenuVerbs(["unpinfromhome", "remove"], true);
}, App.Logger);
if (hr.ThrowIfFailedOnDebug().Failed)
diff --git a/src/Files.Core.SourceGenerator/Generators/VTableFunctionGenerator.cs b/src/Files.Core.SourceGenerator/Generators/VTableFunctionGenerator.cs
deleted file mode 100644
index 1c852cb5f2cf..000000000000
--- a/src/Files.Core.SourceGenerator/Generators/VTableFunctionGenerator.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) Files Community
-// SPDX-License-Identifier: MPL-2.0
-
-namespace Files.Core.SourceGenerator.Generators
-{
- [Generator(LanguageNames.CSharp)]
- internal class VTableFunctionGenerator : IIncrementalGenerator
- {
- public void Initialize(IncrementalGeneratorInitializationContext context)
- {
- var sources = context.SyntaxProvider.ForAttributeWithMetadataName(
- "Files.Shared.Attributes.GeneratedVTableFunctionAttribute",
- static (node, token) =>
- {
- token.ThrowIfCancellationRequested();
-
- // Check if the method has partial modifier and is public or internal (and not static)
- if (node is not MethodDeclarationSyntax { AttributeLists.Count: > 0 } method ||
- !method.Modifiers.Any(SyntaxKind.PartialKeyword) ||
- !(method.Modifiers.Any(SyntaxKind.PublicKeyword) || method.Modifiers.Any(SyntaxKind.InternalKeyword)) ||
- method.Modifiers.Any(SyntaxKind.StaticKeyword))
- return false;
-
- // Check if the type containing the method has partial modifier and is a struct
- if (node.Parent is not TypeDeclarationSyntax { Keyword.RawKind: (int)SyntaxKind.StructKeyword, Modifiers: { } modifiers } ||
- !modifiers.Any(SyntaxKind.PartialKeyword))
- return false;
-
- return true;
- },
- static (context, token) =>
- {
- token.ThrowIfCancellationRequested();
-
- var fullyQualifiedParentTypeName = context.TargetSymbol.ContainingType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
- var structNamespace = context.TargetSymbol.ContainingType.ContainingNamespace.ToString();
- var structName = context.TargetSymbol.ContainingType.Name;
- var methodSymbol = (IMethodSymbol)context.TargetSymbol;
- var isReturnTypeVoid = methodSymbol.ReturnsVoid;
- var functionName = methodSymbol.Name;
- var returnTypeName = methodSymbol.ReturnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
- var parameters = methodSymbol.Parameters.Select(x => new ParameterTypeNamePair(x.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), x.Name));
- var index = (int)context.Attributes[0].NamedArguments.FirstOrDefault(x => x.Key.Equals("Index")).Value.Value!;
-
- return new VTableFunctionInfo(fullyQualifiedParentTypeName, structNamespace, structName, isReturnTypeVoid, functionName, returnTypeName, index, new(parameters.ToImmutableArray()));
- })
- .Where(static item => item is not null)
- .Collect()
- .Select((items, token) =>
- {
- token.ThrowIfCancellationRequested();
-
- return items.GroupBy(source => source.FullyQualifiedParentTypeName, StringComparer.OrdinalIgnoreCase).ToImmutableArray();
- });
-
-
- context.RegisterSourceOutput(sources, (context, sources) =>
- {
- foreach (var source in sources)
- {
- var fileName = $"{source.ToImmutableArray().ElementAt(0).ParentTypeNamespace}.{source.ToImmutableArray().ElementAt(0).ParentTypeName}_VTableFunctions.g.cs";
- var generatedCSharpCode = GenerateVtableFunctionsForStruct(source.ToImmutableArray());
-
- context.AddSource(fileName, generatedCSharpCode);
- }
- });
- }
-
- private string GenerateVtableFunctionsForStruct(ImmutableArray sources)
- {
- StringBuilder builder = new();
-
- builder.AppendLine($"// ");
- builder.AppendLine();
- builder.AppendLine($"using global::System.Runtime.CompilerServices;");
- builder.AppendLine();
- builder.AppendLine($"#pragma warning disable");
- builder.AppendLine();
-
- builder.AppendLine($"namespace {sources.ElementAt(0).ParentTypeNamespace};");
- builder.AppendLine();
-
- builder.AppendLine($"public unsafe partial struct {sources.ElementAt(0).ParentTypeName}");
- builder.AppendLine($"{{");
-
- builder.AppendLine($" private void** lpVtbl;");
- builder.AppendLine();
-
- var sourceIndex = 0;
- var sourceCount = sources.Count();
-
- foreach (var source in sources)
- {
- var returnTypeName = source.IsReturnTypeVoid ? "void" : "int";
-
- builder.AppendLine($" [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]");
-
- builder.AppendLine($" public partial {source.ReturnTypeName} {source.Name}({string.Join(", ", source.Parameters.Select(x => $"{x.FullyQualifiedTypeName} {x.ValueName}"))})");
- builder.AppendLine($" {{");
- builder.AppendLine($" return ({source.ReturnTypeName})((delegate* unmanaged[MemberFunction]<{sources.ElementAt(0).FullyQualifiedParentTypeName}*, {string.Join(", ", source.Parameters.Select(x => $"{x.FullyQualifiedTypeName}"))}, {returnTypeName}>)(lpVtbl[{source.Index}]))");
- builder.AppendLine($" (({sources.ElementAt(0).FullyQualifiedParentTypeName}*)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref this), {string.Join(", ", source.Parameters.Select(x => $"{x.ValueName}"))});");
- builder.AppendLine($" }}");
-
- if (sourceIndex < sourceCount - 1)
- builder.AppendLine();
-
- sourceIndex++;
- }
-
- builder.AppendLine($"}}");
-
- return builder.ToString();
- }
- }
-}
diff --git a/src/Files.Shared/Attributes/GeneratedVTableFunctionAttribute.cs b/src/Files.Shared/Attributes/GeneratedVTableFunctionAttribute.cs
deleted file mode 100644
index d957a05c3e5f..000000000000
--- a/src/Files.Shared/Attributes/GeneratedVTableFunctionAttribute.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) Files Community
-// SPDX-License-Identifier: MPL-2.0
-
-using System;
-
-namespace Files.Shared.Attributes;
-
-[AttributeUsage(AttributeTargets.Method, Inherited = false)]
-public sealed class GeneratedVTableFunctionAttribute : Attribute
-{
- public required int Index { get; init; }
-}