I'm am testing out the C#/Win32 project so I can call Win32 Setup API functions with automatically generated PInvoke wrappers. I am unable to make my code call the correct overload of one of the generated functions (SetupDiGetDeviceRegistryProperty) and I need someone to tell me what I am doing wrong.
Below are the two generated overloads of SetupDiGetDeviceRegistryProperty.. The "nice" one that I want to call is on top. It takes a SafeHandle as the first argument (given to me by another generated function) and does all the proper boiler-plate work with fixed statements and all that so I don't have to.
The second overload is the "raw" one that is called by the first.
[SupportedOSPlatform("windows5.0")]
internal static unsafe winmdroot.Foundation.BOOL SetupDiGetDeviceRegistryProperty(SafeHandle DeviceInfoSet, in winmdroot.Devices.DeviceAndDriverInstallation.SP_DEVINFO_DATA DeviceInfoData, winmdroot.Devices.DeviceAndDriverInstallation.SETUP_DI_REGISTRY_PROPERTY Property, uint* PropertyRegDataType, Span<byte> PropertyBuffer, uint* RequiredSize)
{
// ... generated code removed for brevity. Suffice it to say I want to call this overload.
}
[DllImport("SETUPAPI.dll", ExactSpelling = true, EntryPoint = "SetupDiGetDeviceRegistryPropertyW", SetLastError = true),DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[SupportedOSPlatform("windows5.0")]
internal static extern unsafe winmdroot.Foundation.BOOL SetupDiGetDeviceRegistryProperty(winmdroot.Devices.DeviceAndDriverInstallation.HDEVINFO DeviceInfoSet, winmdroot.Devices.DeviceAndDriverInstallation.SP_DEVINFO_DATA* DeviceInfoData, winmdroot.Devices.DeviceAndDriverInstallation.SETUP_DI_REGISTRY_PROPERTY Property, [Optional] uint* PropertyRegDataType, [Optional] byte* PropertyBuffer, uint PropertyBufferSize, [Optional] uint* RequiredSize);
Here is my test code. Step #3 below is where I am having issues. Visual Studio thinks I am trying to call the second overload and so complains about the first argument being wrong, which of course, it is for that overload.
internal unsafe bool TryGetUsbDeviceRegistryString(
string deviceInstance,
SETUP_DI_REGISTRY_PROPERTY prop,
out string name)
{
name = string.Empty;
// We assume our deviceInstance refers to a USB device
var guidDevinterfaceUsbDevice =
new Guid("{A5DCBF10-6530-11D2-901F-00C04FB951ED}");
SETUP_DI_GET_CLASS_DEVS_FLAGS flags =
SETUP_DI_GET_CLASS_DEVS_FLAGS.DIGCF_DEVICEINTERFACE | SETUP_DI_GET_CLASS_DEVS_FLAGS.DIGCF_PRESENT;
// 1. Get the SafeHandle to the DeviceInfoList
SetupDiDestroyDeviceInfoListSafeHandle info =
PInvoke.SetupDiGetClassDevs(guidDevinterfaceUsbDevice, deviceInstance, HWND.Null, flags);
uint dwSize = 0;
var did = new SP_DEVINFO_DATA{ cbSize = (uint)Marshal.SizeOf<SP_DEVINFO_DATA>()};
uint memberIndex = 0;
uint propType = 0;
Span<byte> buffer = stackalloc byte[1];
// 2. Iterate through all the devices
while (PInvoke.SetupDiEnumDeviceInfo(info, memberIndex, ref did))
{
// 3. First try to get the buffer size required for the registry property 'dwProp'.
// *** THIS COMPILES AGAINST THE WRONG OVERLOAD ***
PInvoke.SetupDiGetDeviceRegistryProperty(info, did, prop, ref propType, buffer, ref dwSize);
// .... allocate a buffer, get the actual property value, yada yada yada...//
memberIndex++;
}
return false;
}
The first argument in Step #3 -- info -- is a SafeHandle. That's what I was given above.
It is a SetupDiDestroyDeviceInfoListSafeHandle which looks like this in generated code:
/// Represents a Win32 handle that can be closed with <see cref="PInvoke.SetupDiDestroyDeviceInfoList(winmdroot.Devices.DeviceAndDriverInstallation.HDEVINFO)"/>.
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Microsoft.Windows.CsWin32", "0.3.183+73e6125f79.RR")]
internal class SetupDiDestroyDeviceInfoListSafeHandle
:SafeHandle {
/// ... etc etc etc.
No matter what I do with the rest of the arguments, Intellisense and the compiler keep assuming I'm calling the second overload and so complain that they cannot convert that SafeHandle into an HDEVINFO. On arguments 4 and 6, I've tried using ref and out and even &. No help.
Here is the compiler output
Build started at 12:20 PM...
1>------ Build started: Project: TestPInvoke, Configuration: Debug x64 ------
1>C:\Users\joe\source\repos\TestPInvoke\TestPInvoke\DeviceInfoSet.cs(39,50,39,54): error CS1503: Argument 1: cannot convert from 'Windows.Win32.SetupDiDestroyDeviceInfoListSafeHandle' to 'Windows.Win32.Devices.DeviceAndDriverInstallation.HDEVINFO'
1>C:\Users\joe\source\repos\TestPInvoke\TestPInvoke\DeviceInfoSet.cs(39,74,39,82): error CS1615: Argument 4 may not be passed with the 'ref' keyword
1>C:\Users\joe\source\repos\TestPInvoke\TestPInvoke\DeviceInfoSet.cs(39,90,39,96): error CS1503: Argument 6: cannot convert from 'System.Span<byte>' to 'uint'
1>C:\Users\joe\source\repos\TestPInvoke\TestPInvoke\DeviceInfoSet.cs(39,102,39,108): error CS1615: Argument 7 may not be passed with the 'ref' keyword
1>Done building project "TestPInvoke.csproj" -- FAILED.
Build has been canceled.
========== Elapsed 00.993 seconds ==========
Can someone tell me what I am doing wrong?
PInvoke.SetupDiGetDeviceRegistryProperty(info, did, prop, &propType, buffer, &dwSize);to compile (not sure if it works after that)