microsoft / CsWin32

A source generator to add a user-defined set of Win32 P/Invoke methods and supporting types to a C# project.
MIT License
2.07k stars 87 forks source link

`FindFirstFileExFromApp` generate `void*` at `lpFindFileData` #1167

Closed gumbarros closed 5 months ago

gumbarros commented 6 months ago

Actual behavior

FindFirstFileExFromApp generate void* at lpFindFileData

Expected behavior

FindFirstFileExFromApp should generate out WIN32_FIND_DATAW at lpFindFileData

Repro steps

  1. NativeMethods.txt content:
    
    // Copyright (c) 2024 Files Community
    // Licensed under the MIT License. See the LICENSE.

FindFirstFileExFromApp FindNextFile FindClose FileTimeToSystemTime WIN32_FIND_DATAW


2. `NativeMethods.json` content (if present):
```json
// Copyright (c) 2024 Files Community
// Licensed under the MIT License. See the LICENSE.
{
  "$schema": "https://aka.ms/CsWin32.schema.json",

  // Emit COM interfaces instead of structs, and allow generation of non-blittable structs for the sake of an easier to use API.
  "allowMarshaling": true,

  // A value indicating whether to generate APIs judged to be unnecessary or redundant given the target framework.
  // This is useful for multi-targeting projects that need a consistent set of APIs across target frameworks
  // to avoid too many conditional compilation regions.
  "multiTargetingFriendlyAPIs": false,

  // A value indicating whether friendly overloads should use safe handles.
  "useSafeHandles": true,

  // Omit ANSI functions and remove `W` suffix from UTF-16 functions.
  "wideCharOnly": true,

  // A value indicating whether to emit a single source file as opposed to types spread across many files.
  "emitSingleFile": false,

  // The name of a single class under which all p/invoke methods and constants are generated, regardless of imported module.
  "className": "PInvoke",

  // A value indicating whether to expose the generated APIs publicly (as opposed to internally).
  "public": true
}
  1. Any of your own code that should be shared? We migrated from:
    [DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern IntPtr FindFirstFileExFromApp(
    string lpFileName,
    FINDEX_INFO_LEVELS fInfoLevelId,
    out WIN32_FIND_DATA lpFindFileData,
    FINDEX_SEARCH_OPS fSearchOp,
    IntPtr lpSearchFilter,
    int dwAdditionalFlags);

    To:

        public static SafeFileHandle FindFirstFileExFromApp(
            string lpFileName,
            FINDEX_INFO_LEVELS fInfoLevelId,
            out WIN32_FIND_DATAW lpFindFileData,
            FINDEX_SEARCH_OPS fSearchOp,
            IntPtr lpSearchFilter,
            int dwAdditionalFlags)
        {
            return PInvoke.FindFirstFileExFromApp(lpFileName, fInfoLevelId, out lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags);
        }

The new code don't compile because lpFindFileData is void*

Context

AArnott commented 5 months ago

The actual behavior is by design. If you take a look at the header file or the docs, you'll see that the parameter is defined as LPVOID lpFindFileData, which in C# translates to void*. In fact the docs suggest that the type of data that is initialized here depends on other arguments, so assuming it is WIN32_FIND_DATAW sounds like it would lead to malfunctions in at least some cases.

But this shouldn't block you. If you expect a WIN32_FIND_DATAW struct to be initialized based on your other arguments, go ahead and create such a struct and then pass a pointer to it as the argument.