diff --git a/src/Files.App.CsWin32/NativeMethods.txt b/src/Files.App.CsWin32/NativeMethods.txt index 74d962bd87a1..3b611b024af5 100644 --- a/src/Files.App.CsWin32/NativeMethods.txt +++ b/src/Files.App.CsWin32/NativeMethods.txt @@ -135,6 +135,12 @@ PSGetPropertyKeyFromName ShellExecuteEx CoTaskMemFree QueryDosDevice +FindFirstFileEx +FindNextFile +CreateFile +GetFileSizeEx +WIN32_FIND_DATAW +FILE_ACCESS_RIGHTS SHAddToRecentDocs SHARD BHID_EnumItems diff --git a/src/Files.App/Data/Items/ShellLibraryItem.cs b/src/Files.App/Data/Items/ShellLibraryItem.cs index a3db0bc5e145..bc65b2602477 100644 --- a/src/Files.App/Data/Items/ShellLibraryItem.cs +++ b/src/Files.App/Data/Items/ShellLibraryItem.cs @@ -1,15 +1,13 @@ // Copyright (c) 2024 Files Community // Licensed under the MIT License. See the LICENSE. -using System.IO; - namespace Files.App.Data.Items { public sealed class ShellLibraryItem { public const string EXTENSION = ".library-ms"; - public static readonly string LibrariesPath = Win32PInvoke.GetFolderFromKnownFolderGUID(new Guid("1B3EA5DC-B587-4786-B4EF-BD1DC332AEAE")); + public static readonly string LibrariesPath = Win32Helper.GetFolderFromKnownFolderGUID(new Guid("1B3EA5DC-B587-4786-B4EF-BD1DC332AEAE")); /// /// Full path of library file.
diff --git a/src/Files.App/Helpers/Win32/Win32Helper.Shell.cs b/src/Files.App/Helpers/Win32/Win32Helper.Shell.cs index a307f6041ec8..c5892a8a1953 100644 --- a/src/Files.App/Helpers/Win32/Win32Helper.Shell.cs +++ b/src/Files.App/Helpers/Win32/Win32Helper.Shell.cs @@ -79,5 +79,15 @@ public static partial class Win32Helper return (folder, flc); }); } + + public static string GetFolderFromKnownFolderGUID(Guid guid) + { + nint pszPath; + Win32PInvoke.SHGetKnownFolderPath(guid, 0, nint.Zero, out pszPath); + string path = Marshal.PtrToStringUni(pszPath); + Marshal.FreeCoTaskMem(pszPath); + + return path; + } } } diff --git a/src/Files.App/Helpers/Win32/Win32Helper.WindowManagement.cs b/src/Files.App/Helpers/Win32/Win32Helper.WindowManagement.cs index 1b28a1f8717e..ff57f45abc32 100644 --- a/src/Files.App/Helpers/Win32/Win32Helper.WindowManagement.cs +++ b/src/Files.App/Helpers/Win32/Win32Helper.WindowManagement.cs @@ -4,10 +4,8 @@ using Microsoft.UI.Input; using Microsoft.UI.Xaml; using System.Reflection; -using Vanara.PInvoke; using Windows.Win32; using Windows.Win32.UI.WindowsAndMessaging; -using static Vanara.PInvoke.User32; namespace Files.App.Helpers { @@ -60,20 +58,5 @@ public static void ChangeCursor(this UIElement uiElement, InputCursor cursor) [cursor] ); } - - /// - /// Changes an attribute of the specified window. - /// - /// A handle to the window and, indirectly, the class to which the window belongs. - /// The zero-based offset to the value to be set. - /// The replacement value. - /// If the function succeeds, the return value is the previous value of the specified offset. - public static IntPtr SetWindowLong(HWND hWnd, WindowLongFlags nIndex, IntPtr dwNewLong) - { - return - IntPtr.Size == 4 - ? Win32PInvoke.SetWindowLongPtr32(hWnd, nIndex, dwNewLong) - : Win32PInvoke.SetWindowLongPtr64(hWnd, nIndex, dwNewLong); - } } } diff --git a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs index 092e07a69af4..e6f07783d534 100644 --- a/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs +++ b/src/Files.App/Helpers/Win32/Win32PInvoke.Methods.cs @@ -5,8 +5,8 @@ using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Text; -using Vanara.PInvoke; -using static Vanara.PInvoke.User32; +using Windows.Win32.Foundation; +using Windows.Win32.System.Com; namespace Files.App.Helpers { @@ -90,20 +90,6 @@ public static extern uint CoWaitForMultipleObjects( out uint dwIndex ); - [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLong")] - public static extern int SetWindowLongPtr32( - HWND hWnd, - WindowLongFlags nIndex, - IntPtr dwNewLong - ); - - [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLongPtr")] - public static extern IntPtr SetWindowLongPtr64( - HWND hWnd, - WindowLongFlags nIndex, - IntPtr dwNewLong - ); - [DllImport("shell32.dll")] public static extern IntPtr SHBrowseForFolder( ref BROWSEINFO lpbi @@ -498,7 +484,7 @@ int dwFlags ); [DllImport("shell32.dll")] - static extern int SHGetKnownFolderPath( + public static extern int SHGetKnownFolderPath( [MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, @@ -507,14 +493,5 @@ out IntPtr pszPath [DllImport("shell32.dll", EntryPoint = "SHUpdateRecycleBinIcon", CharSet = CharSet.Unicode, SetLastError = true)] public static extern void SHUpdateRecycleBinIcon(); - - public static string GetFolderFromKnownFolderGUID(Guid guid) - { - IntPtr pPath; - SHGetKnownFolderPath(guid, 0, IntPtr.Zero, out pPath); - string path = Marshal.PtrToStringUni(pPath); - System.Runtime.InteropServices.Marshal.FreeCoTaskMem(pPath); - return path; - } } } diff --git a/src/Files.App/Utils/Shell/ItemStreamHelper.cs b/src/Files.App/Utils/Shell/ItemStreamHelper.cs index 523845e21d8c..94eb9edb6df1 100644 --- a/src/Files.App/Utils/Shell/ItemStreamHelper.cs +++ b/src/Files.App/Utils/Shell/ItemStreamHelper.cs @@ -1,6 +1,8 @@ -using System; +// Copyright (c) 2024 Files Community +// Licensed under the MIT License. See the LICENSE. + using System.Runtime.InteropServices; -using Vanara.PInvoke; +using Windows.Win32.System.Com; namespace Files.App.Utils.Shell { @@ -20,12 +22,15 @@ public static IntPtr IShellItemFromPath(string path) public static IntPtr IStreamFromPath(string path) { - IntPtr pstm; - var hr = Win32PInvoke.SHCreateStreamOnFileEx(path, + var hr = Win32PInvoke.SHCreateStreamOnFileEx( + path, STGM.STGM_READ | STGM.STGM_FAILIFTHERE | STGM.STGM_SHARE_DENY_NONE, - 0, 0, IntPtr.Zero, out pstm); + 0, 0, + IntPtr.Zero, out var pstm); + if ((int)hr < 0) return IntPtr.Zero; + return pstm; } diff --git a/src/Files.App/Utils/Shell/PreviewHandler.cs b/src/Files.App/Utils/Shell/PreviewHandler.cs index 6cb5f4001798..e6b2a5fbf142 100644 --- a/src/Files.App/Utils/Shell/PreviewHandler.cs +++ b/src/Files.App/Utils/Shell/PreviewHandler.cs @@ -160,7 +160,8 @@ void SetupHandler(Guid clsid) // If we use Activator.CreateInstance(Type.GetTypeFromCLSID(...)), // CLR will allow in-process server, which defeats isolation and // creates strange bugs. - HRESULT hr = Win32PInvoke.CoCreateInstance(ref clsid, IntPtr.Zero, Win32PInvoke.ClassContext.LocalServer, ref iid, out pph); + Windows.Win32.Foundation.HRESULT hr2 = Win32PInvoke.CoCreateInstance(ref clsid, IntPtr.Zero, Win32PInvoke.ClassContext.LocalServer, ref iid, out pph); + HRESULT hr = new(hr2.Value); // 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 diff --git a/src/Files.App/Utils/Storage/Operations/FileSizeCalculator.cs b/src/Files.App/Utils/Storage/Operations/FileSizeCalculator.cs index 5a0e058550f2..cb5cb2f10d71 100644 --- a/src/Files.App/Utils/Storage/Operations/FileSizeCalculator.cs +++ b/src/Files.App/Utils/Storage/Operations/FileSizeCalculator.cs @@ -1,7 +1,10 @@ -using System.Collections.Concurrent; +// Copyright (c) 2024 Files Community +// Licensed under the MIT License. See the LICENSE. + +using System.Collections.Concurrent; using System.IO; -using Vanara.PInvoke; -using static Vanara.PInvoke.Kernel32; +using Windows.Win32; +using Windows.Win32.Storage.FileSystem; namespace Files.App.Utils.Storage.Operations { @@ -22,7 +25,18 @@ public FileSizeCalculator(params string[] paths) public async Task ComputeSizeAsync(CancellationToken cancellationToken = default) { - await Parallel.ForEachAsync(_paths, cancellationToken, async (path, token) => await Task.Factory.StartNew(() => + await Parallel.ForEachAsync( + _paths, + cancellationToken, + async (path, token) => await Task.Factory.StartNew(() => + { + ComputeSizeRecursively(path, token); + }, + token, + TaskCreationOptions.LongRunning, + TaskScheduler.Default)); + + unsafe void ComputeSizeRecursively(string path, CancellationToken token) { var queue = new Queue(); if (!Win32Helper.HasFileAttribute(path, FileAttributes.Directory)) @@ -35,66 +49,70 @@ await Parallel.ForEachAsync(_paths, cancellationToken, async (path, token) => aw while (queue.TryDequeue(out var directory)) { - using var hFile = FindFirstFileEx( - directory + "\\*.*", - FINDEX_INFO_LEVELS.FindExInfoBasic, - out WIN32_FIND_DATA findData, - FINDEX_SEARCH_OPS.FindExSearchNameMatch, - IntPtr.Zero, - FIND_FIRST.FIND_FIRST_EX_LARGE_FETCH); - - if (!hFile.IsInvalid) + WIN32_FIND_DATAW findData = default; + + fixed (char* pszFilePath = directory + "\\*.*") { - do + var hFile = PInvoke.FindFirstFileEx( + pszFilePath, + FINDEX_INFO_LEVELS.FindExInfoBasic, + &findData, + FINDEX_SEARCH_OPS.FindExSearchNameMatch, + null, + FIND_FIRST_EX_FLAGS.FIND_FIRST_EX_LARGE_FETCH); + + if (!hFile.IsNull) { - if ((findData.dwFileAttributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint) - // Skip symbolic links and junctions - continue; + do + { + FILE_FLAGS_AND_ATTRIBUTES attributes = (FILE_FLAGS_AND_ATTRIBUTES)findData.dwFileAttributes; - var itemPath = Path.Combine(directory, findData.cFileName); + if (attributes.HasFlag(FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_REPARSE_POINT)) + // Skip symbolic links and junctions + continue; - if ((findData.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory) - { - ComputeFileSize(itemPath); - } - else if (findData.cFileName != "." && findData.cFileName != "..") - { - queue.Enqueue(itemPath); - } + var itemPath = Path.Combine(directory, findData.cFileName.ToString()); + + if (attributes.HasFlag(FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_DIRECTORY)) + { + ComputeFileSize(itemPath); + } + else if (findData.cFileName.ToString() is string fileName && + fileName.Equals(".", StringComparison.OrdinalIgnoreCase) && + fileName.Equals("..", StringComparison.OrdinalIgnoreCase)) + { + queue.Enqueue(itemPath); + } - if (token.IsCancellationRequested) - break; + if (token.IsCancellationRequested) + break; + } + while (PInvoke.FindNextFile(hFile, &findData)); } - while (FindNextFile(hFile, out findData)); + + PInvoke.CloseHandle(hFile); } } } - }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default)); + } } private long ComputeFileSize(string path) { if (_computedFiles.TryGetValue(path, out var size)) - { return size; - } - using var hFile = CreateFile( + using var hFile = PInvoke.CreateFile( path, - Kernel32.FileAccess.FILE_READ_ATTRIBUTES, - FileShare.Read, + (uint)FILE_ACCESS_RIGHTS.FILE_READ_ATTRIBUTES, + FILE_SHARE_MODE.FILE_SHARE_READ, null, - FileMode.Open, + FILE_CREATION_DISPOSITION.OPEN_EXISTING, 0, null); - if (!hFile.IsInvalid) - { - if (GetFileSizeEx(hFile, out size) && _computedFiles.TryAdd(path, size)) - { - Interlocked.Add(ref _size, size); - } - } + if (!hFile.IsInvalid && PInvoke.GetFileSizeEx(hFile, out size) && _computedFiles.TryAdd(path, size)) + Interlocked.Add(ref _size, size); return size; } @@ -102,9 +120,7 @@ private long ComputeFileSize(string path) public void ForceComputeFileSize(string path) { if (!Win32Helper.HasFileAttribute(path, FileAttributes.Directory)) - { ComputeFileSize(path); - } } public bool TryGetComputedFileSize(string path, out long size) diff --git a/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs b/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs index 1dd27cb8ad03..243971dcf247 100644 --- a/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs @@ -15,6 +15,7 @@ using Windows.Win32.Graphics.DirectComposition; using Windows.Win32.Graphics.Dwm; using Windows.Win32.Graphics.Dxgi; +using Windows.Win32.UI.WindowsAndMessaging; using WinRT; using static Vanara.PInvoke.ShlwApi; using static Vanara.PInvoke.User32; @@ -245,14 +246,11 @@ public unsafe void PointerEntered(bool onPreview) (uint)Marshal.SizeOf(dwAttrib)); if (isOfficePreview) - Win32Helper.SetWindowLong(hwnd, WindowLongFlags.GWL_EXSTYLE, 0); + PInvoke.SetWindowLongPtr(new((nint)hwnd), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, 0); } else { - Win32Helper.SetWindowLong( - hwnd, - WindowLongFlags.GWL_EXSTYLE, - (nint)(WindowStylesEx.WS_EX_LAYERED | WindowStylesEx.WS_EX_COMPOSITED)); + PInvoke.SetWindowLongPtr(new((nint)hwnd), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (nint)(WINDOW_EX_STYLE.WS_EX_LAYERED | WINDOW_EX_STYLE.WS_EX_COMPOSITED)); var dwAttrib = Convert.ToUInt32(true);