From a23263150d4f9977e2471c7462c147b9e24963d6 Mon Sep 17 00:00:00 2001 From: gumbarros Date: Tue, 26 Mar 2024 20:33:02 -0300 Subject: [PATCH 1/2] Migrate `DllImportAttribute` to `LibraryImport` --- src/Files.Core/Helpers/NativeFindStorageItemHelper.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Files.Core/Helpers/NativeFindStorageItemHelper.cs b/src/Files.Core/Helpers/NativeFindStorageItemHelper.cs index d61030f42b64..4259902540fe 100644 --- a/src/Files.Core/Helpers/NativeFindStorageItemHelper.cs +++ b/src/Files.Core/Helpers/NativeFindStorageItemHelper.cs @@ -76,7 +76,7 @@ public struct WIN32_FIND_DATA public string cAlternateFileName; } - [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [LibraryImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true)] public static extern IntPtr FindFirstFileExFromApp( string lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, @@ -88,16 +88,16 @@ public static extern IntPtr FindFirstFileExFromApp( public const int FIND_FIRST_EX_CASE_SENSITIVE = 1; public const int FIND_FIRST_EX_LARGE_FETCH = 2; - [DllImport("api-ms-win-core-file-l1-1-0.dll", CharSet = CharSet.Unicode)] + [LibraryImport("api-ms-win-core-file-l1-1-0.dll")] public static extern bool FindNextFile( IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); - [DllImport("api-ms-win-core-file-l1-1-0.dll")] + [LibraryImport("api-ms-win-core-file-l1-1-0.dll")] public static extern bool FindClose( IntPtr hFindFile); - [DllImport("api-ms-win-core-timezone-l1-1-0.dll", SetLastError = true)] + [LibraryImport("api-ms-win-core-timezone-l1-1-0.dll", SetLastError = true)] public static extern bool FileTimeToSystemTime( ref FILETIME lpFileTime, out SYSTEMTIME lpSystemTime); From 0ee9ae007a183744fa32b1e4453b4598898dd1f0 Mon Sep 17 00:00:00 2001 From: gumbarros Date: Tue, 26 Mar 2024 22:35:26 -0300 Subject: [PATCH 2/2] Custom marshalling for Win32FindData --- .../Enumerators/Win32StorageEnumerator.cs | 6 +- .../Storage/Operations/FileSizeCalculator.cs | 2 +- .../Utils/Storage/Search/FolderSearch.cs | 2 +- src/Files.Core/AssemblyInfo.cs | 3 + src/Files.Core/Files.Core.csproj | 1 + .../Helpers/NativeFindStorageItemHelper.cs | 41 +++------ src/Files.Core/Helpers/Win32FindData.cs | 24 +++++ .../Helpers/Win32FindDataMarshaller.cs | 92 +++++++++++++++++++ 8 files changed, 137 insertions(+), 34 deletions(-) create mode 100644 src/Files.Core/AssemblyInfo.cs create mode 100644 src/Files.Core/Helpers/Win32FindData.cs create mode 100644 src/Files.Core/Helpers/Win32FindDataMarshaller.cs diff --git a/src/Files.App/Utils/Storage/Enumerators/Win32StorageEnumerator.cs b/src/Files.App/Utils/Storage/Enumerators/Win32StorageEnumerator.cs index 0e56a6511b4e..10ef72a0d8e4 100644 --- a/src/Files.App/Utils/Storage/Enumerators/Win32StorageEnumerator.cs +++ b/src/Files.App/Utils/Storage/Enumerators/Win32StorageEnumerator.cs @@ -22,7 +22,7 @@ public static class Win32StorageEnumerator public static async Task> ListEntries( string path, IntPtr hFile, - NativeFindStorageItemHelper.WIN32_FIND_DATA findData, + Core.Helpers.WIN32_FIND_DATA findData, CancellationToken cancellationToken, int countLimit, Func, Task> intermediateAction @@ -145,7 +145,7 @@ public static ListedItem GetAlternateStream((string Name, long Size) ads, Listed } public static async Task GetFolder( - NativeFindStorageItemHelper.WIN32_FIND_DATA findData, + Core.Helpers.WIN32_FIND_DATA findData, string pathRoot, bool isGitRepo, CancellationToken cancellationToken @@ -222,7 +222,7 @@ CancellationToken cancellationToken } public static async Task GetFile( - NativeFindStorageItemHelper.WIN32_FIND_DATA findData, + Core.Helpers.WIN32_FIND_DATA findData, string pathRoot, bool isGitRepo, CancellationToken cancellationToken diff --git a/src/Files.App/Utils/Storage/Operations/FileSizeCalculator.cs b/src/Files.App/Utils/Storage/Operations/FileSizeCalculator.cs index b5d6df77a544..f1dfaac882d9 100644 --- a/src/Files.App/Utils/Storage/Operations/FileSizeCalculator.cs +++ b/src/Files.App/Utils/Storage/Operations/FileSizeCalculator.cs @@ -38,7 +38,7 @@ await Parallel.ForEachAsync(_paths, cancellationToken, async (path, token) => aw using var hFile = FindFirstFileEx( directory + "\\*.*", FINDEX_INFO_LEVELS.FindExInfoBasic, - out WIN32_FIND_DATA findData, + out Vanara.PInvoke.WIN32_FIND_DATA findData, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, FIND_FIRST.FIND_FIRST_EX_LARGE_FETCH); diff --git a/src/Files.App/Utils/Storage/Search/FolderSearch.cs b/src/Files.App/Utils/Storage/Search/FolderSearch.cs index cc76814f217a..42fdeb800ed8 100644 --- a/src/Files.App/Utils/Storage/Search/FolderSearch.cs +++ b/src/Files.App/Utils/Storage/Search/FolderSearch.cs @@ -8,7 +8,7 @@ using Windows.Storage.Search; using static Files.Core.Helpers.NativeFindStorageItemHelper; using FileAttributes = System.IO.FileAttributes; -using WIN32_FIND_DATA = Files.Core.Helpers.NativeFindStorageItemHelper.WIN32_FIND_DATA; +using WIN32_FIND_DATA = Files.Core.Helpers.WIN32_FIND_DATA; namespace Files.App.Utils.Storage { diff --git a/src/Files.Core/AssemblyInfo.cs b/src/Files.Core/AssemblyInfo.cs new file mode 100644 index 000000000000..eab9e5671759 --- /dev/null +++ b/src/Files.Core/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly:DisableRuntimeMarshalling] \ No newline at end of file diff --git a/src/Files.Core/Files.Core.csproj b/src/Files.Core/Files.Core.csproj index 5425b782907b..60864d952676 100644 --- a/src/Files.Core/Files.Core.csproj +++ b/src/Files.Core/Files.Core.csproj @@ -8,6 +8,7 @@ Debug;Release;Stable;Preview;Store x86;x64;arm64 win-x86;win-x64;win-arm64 + true diff --git a/src/Files.Core/Helpers/NativeFindStorageItemHelper.cs b/src/Files.Core/Helpers/NativeFindStorageItemHelper.cs index 4259902540fe..5050bd983fab 100644 --- a/src/Files.Core/Helpers/NativeFindStorageItemHelper.cs +++ b/src/Files.Core/Helpers/NativeFindStorageItemHelper.cs @@ -3,13 +3,14 @@ using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; +using System.Runtime.InteropServices.Marshalling; namespace Files.Core.Helpers { /// /// Provides a bunch of Win32API for native find storage items. /// - public sealed class NativeFindStorageItemHelper + public sealed partial class NativeFindStorageItemHelper { [StructLayout(LayoutKind.Sequential)] public struct SYSTEMTIME @@ -54,30 +55,9 @@ public enum FINDEX_SEARCH_OPS FindExSearchLimitToDirectories = 1, FindExSearchLimitToDevices = 2 } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public struct WIN32_FIND_DATA - { - public uint dwFileAttributes; - - public FILETIME ftCreationTime; - public FILETIME ftLastAccessTime; - public FILETIME ftLastWriteTime; - - public uint nFileSizeHigh; - public uint nFileSizeLow; - public uint dwReserved0; - public uint dwReserved1; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string cFileName; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] - public string cAlternateFileName; - } - - [LibraryImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true)] - public static extern IntPtr FindFirstFileExFromApp( + + [LibraryImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] + public static partial IntPtr FindFirstFileExFromApp( string lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, out WIN32_FIND_DATA lpFindFileData, @@ -89,22 +69,25 @@ public static extern IntPtr FindFirstFileExFromApp( public const int FIND_FIRST_EX_LARGE_FETCH = 2; [LibraryImport("api-ms-win-core-file-l1-1-0.dll")] - public static extern bool FindNextFile( + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool FindNextFile( IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); [LibraryImport("api-ms-win-core-file-l1-1-0.dll")] - public static extern bool FindClose( + [return:MarshalAs(UnmanagedType.I1)] + public static partial bool FindClose( IntPtr hFindFile); [LibraryImport("api-ms-win-core-timezone-l1-1-0.dll", SetLastError = true)] - public static extern bool FileTimeToSystemTime( + [return:MarshalAs(UnmanagedType.I1)] + public static partial bool FileTimeToSystemTime( ref FILETIME lpFileTime, out SYSTEMTIME lpSystemTime); public static bool GetWin32FindDataForPath( string targetPath, - out WIN32_FIND_DATA findData) + [MarshalUsing(typeof(Win32FindDataMarshaller))] out WIN32_FIND_DATA findData) { FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic; diff --git a/src/Files.Core/Helpers/Win32FindData.cs b/src/Files.Core/Helpers/Win32FindData.cs new file mode 100644 index 000000000000..39eb1f981831 --- /dev/null +++ b/src/Files.Core/Helpers/Win32FindData.cs @@ -0,0 +1,24 @@ +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using System.Runtime.InteropServices.Marshalling; + +namespace Files.Core.Helpers; + +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] +[NativeMarshalling(typeof(Win32FindDataMarshaller))] +public struct WIN32_FIND_DATA +{ + public uint dwFileAttributes; + + public FILETIME ftCreationTime; + public FILETIME ftLastAccessTime; + public FILETIME ftLastWriteTime; + public uint nFileSizeHigh; + public uint nFileSizeLow; + public uint dwReserved0; + public uint dwReserved1; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string cFileName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] + public string cAlternateFileName; +} \ No newline at end of file diff --git a/src/Files.Core/Helpers/Win32FindDataMarshaller.cs b/src/Files.Core/Helpers/Win32FindDataMarshaller.cs new file mode 100644 index 000000000000..271b0e32486f --- /dev/null +++ b/src/Files.Core/Helpers/Win32FindDataMarshaller.cs @@ -0,0 +1,92 @@ +using System.Runtime.InteropServices.Marshalling; + +namespace Files.Core.Helpers; + +[CustomMarshaller(typeof(WIN32_FIND_DATA), MarshalMode.ManagedToUnmanagedOut, typeof(Win32FindDataMarshaller))] +internal static unsafe class Win32FindDataMarshaller +{ + public struct WIN32_FIND_DATA_UNMANAGED + { + public SystemIO.FileAttributes dwFileAttributes; + public uint ftCreationTime_dwLowDateTime; + public uint ftCreationTime_dwHighDateTime; + public uint ftLastAccessTime_dwLowDateTime; + public uint ftLastAccessTime_dwHighDateTime; + public uint ftLastWriteTime_dwLowDateTime; + public uint ftLastWriteTime_dwHighDateTime; + public uint nFileSizeHigh; + public uint nFileSizeLow; + public uint dwReserved0; + public uint dwReserved1; + public fixed ushort cFileName[256]; + public fixed ushort cAlternateFileName[14]; + } + + + public static WIN32_FIND_DATA ConvertToManaged(WIN32_FIND_DATA_UNMANAGED unmanaged) + { + var managed = new WIN32_FIND_DATA(); + managed.dwFileAttributes = (uint)unmanaged.dwFileAttributes; + managed.ftCreationTime.dwLowDateTime = (int)unmanaged.ftCreationTime_dwLowDateTime; + managed.ftCreationTime.dwHighDateTime = (int)unmanaged.ftCreationTime_dwHighDateTime; + managed.ftLastAccessTime.dwLowDateTime = (int)unmanaged.ftLastAccessTime_dwLowDateTime; + managed.ftLastAccessTime.dwHighDateTime = (int)unmanaged.ftLastAccessTime_dwHighDateTime; + managed.ftLastWriteTime.dwLowDateTime = (int)unmanaged.ftLastWriteTime_dwLowDateTime; + managed.ftLastWriteTime.dwHighDateTime = (int)unmanaged.ftLastWriteTime_dwHighDateTime; + managed.nFileSizeHigh = unmanaged.nFileSizeHigh; + managed.nFileSizeLow = unmanaged.nFileSizeLow; + + managed.cFileName = GetStringFromBuffer(unmanaged.cFileName); + managed.cAlternateFileName = GetStringFromBuffer(unmanaged.cAlternateFileName); + return managed; + } + + public static WIN32_FIND_DATA_UNMANAGED ConvertToUnmanaged(WIN32_FIND_DATA managed) + { + WIN32_FIND_DATA_UNMANAGED unmanaged = new WIN32_FIND_DATA_UNMANAGED(); + unmanaged.dwFileAttributes = (SystemIO.FileAttributes)managed.dwFileAttributes; + unmanaged.ftCreationTime_dwLowDateTime = (uint)managed.ftCreationTime.dwLowDateTime; + unmanaged.ftCreationTime_dwHighDateTime = (uint)managed.ftCreationTime.dwHighDateTime; + unmanaged.ftLastAccessTime_dwLowDateTime = (uint)managed.ftLastAccessTime.dwLowDateTime; + unmanaged.ftLastAccessTime_dwHighDateTime = (uint)managed.ftLastAccessTime.dwHighDateTime; + unmanaged.ftLastWriteTime_dwLowDateTime = (uint)managed.ftLastWriteTime.dwLowDateTime; + unmanaged.ftLastWriteTime_dwHighDateTime = (uint)managed.ftLastWriteTime.dwHighDateTime; + unmanaged.nFileSizeHigh = managed.nFileSizeHigh; + unmanaged.nFileSizeLow = managed.nFileSizeLow; + + CopyStringToBuffer(managed.cFileName, unmanaged.cFileName); + CopyStringToBuffer(managed.cAlternateFileName, unmanaged.cAlternateFileName); + return unmanaged; + } + + private static void CopyStringToBuffer(string source, ushort* destination) + { + int index = 0; + foreach (char c in source) + { + destination[index++] = c; + if (index >= source.Length) + break; + } + + destination[index] = '\0'; // Null-terminate the string + } + + private static string GetStringFromBuffer(ushort* source) + { + int index = 0; + char[] chars = new char[256]; // Assuming max buffer size for file name + while (source[index] != '\0' && index < 256) + { + chars[index] = (char)source[index]; + index++; + } + + return new string(chars, 0, index); + } + + public static void Free(WIN32_FIND_DATA_UNMANAGED unmanaged) + { + throw new NotImplementedException(); + } +} \ No newline at end of file