Skip to content

Code Quality: Migrate DllImportAttribute to LibraryImportAttribute at NativeFindStorageItemHelper.cs #15056

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static class Win32StorageEnumerator
public static async Task<List<ListedItem>> ListEntries(
string path,
IntPtr hFile,
NativeFindStorageItemHelper.WIN32_FIND_DATA findData,
Core.Helpers.WIN32_FIND_DATA findData,
CancellationToken cancellationToken,
int countLimit,
Func<List<ListedItem>, Task> intermediateAction
Expand Down Expand Up @@ -145,7 +145,7 @@ public static ListedItem GetAlternateStream((string Name, long Size) ads, Listed
}

public static async Task<ListedItem> GetFolder(
NativeFindStorageItemHelper.WIN32_FIND_DATA findData,
Core.Helpers.WIN32_FIND_DATA findData,
string pathRoot,
bool isGitRepo,
CancellationToken cancellationToken
Expand Down Expand Up @@ -222,7 +222,7 @@ CancellationToken cancellationToken
}

public static async Task<ListedItem> GetFile(
NativeFindStorageItemHelper.WIN32_FIND_DATA findData,
Core.Helpers.WIN32_FIND_DATA findData,
string pathRoot,
bool isGitRepo,
CancellationToken cancellationToken
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App/Utils/Storage/Search/FolderSearch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
3 changes: 3 additions & 0 deletions src/Files.Core/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;

[assembly:DisableRuntimeMarshalling]
1 change: 1 addition & 0 deletions src/Files.Core/Files.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<Configurations>Debug;Release;Stable;Preview;Store</Configurations>
<Platforms>x86;x64;arm64</Platforms>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
Expand Down
47 changes: 15 additions & 32 deletions src/Files.Core/Helpers/NativeFindStorageItemHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices.Marshalling;

namespace Files.Core.Helpers
{
/// <summary>
/// Provides a bunch of Win32API for native find storage items.
/// </summary>
public sealed class NativeFindStorageItemHelper
public sealed partial class NativeFindStorageItemHelper
{
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEMTIME
Expand Down Expand Up @@ -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)]
Copy link
Contributor Author

@gumbarros gumbarros Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need help with someone with Win32 knowledge to know if this CharSet property is important, the only equivalent is StringMarshalling

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,
Expand All @@ -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;

Expand Down
24 changes: 24 additions & 0 deletions src/Files.Core/Helpers/Win32FindData.cs
Original file line number Diff line number Diff line change
@@ -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;
}
92 changes: 92 additions & 0 deletions src/Files.Core/Helpers/Win32FindDataMarshaller.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}