microsoft / CsWin32

A source generator to add a user-defined set of Win32 P/Invoke methods and supporting types to a C# project.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`FindFirstFileExFromApp` generate `void*` at `lpFindFileData`

gumbarros opened this issue · comments

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
  1. NativeMethods.json content (if present):
// 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

  • CsWin32 version: latest
  • Target Framework: net8.0

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.