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 d61030f42b64..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; - } - - [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)] - 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, @@ -88,23 +68,26 @@ 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)] - public static extern bool FindNextFile( + [LibraryImport("api-ms-win-core-file-l1-1-0.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool FindNextFile( IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); - [DllImport("api-ms-win-core-file-l1-1-0.dll")] - public static extern bool FindClose( + [LibraryImport("api-ms-win-core-file-l1-1-0.dll")] + [return:MarshalAs(UnmanagedType.I1)] + public static partial bool FindClose( IntPtr hFindFile); - [DllImport("api-ms-win-core-timezone-l1-1-0.dll", SetLastError = true)] - public static extern bool FileTimeToSystemTime( + [LibraryImport("api-ms-win-core-timezone-l1-1-0.dll", SetLastError = true)] + [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