Reputation: 2640
I am trying to access information about drivers associated with devices in C# utilizing the win32 APIs.
I have managed to enable/disable devices (so the handles I am retrieving seem OK), however I have no luck when trying to call SetupDiEnumDriverInfo.
This is the code I am using:
private List<String> ListCompatibleDrivers(IntPtr hDevInfo, SP_DEVINFO_DATA devInfoData)
{
List<String> result = new List<String>();
try
{
SP_DRVINFO_DATA drvInfo = new SP_DRVINFO_DATA();
for (int i = 0; SetupDiEnumDriverInfo(hDevInfo, devInfoData, SPDIT_CLASSDRIVER, i, drvInfo); i++)
{
result.Add(drvInfo.Description);
}
if (result.Count < 1)
{
result.Add(Marshal.GetLastWin32Error().ToString());
}
return result;
}
catch
{
throw;
}
}
Where the parameters can be assumed to be okay (as I said, other methods from the setup API use them successfully).
These are the struct and the DllImport which might be corrupt:
[StructLayout(LayoutKind.Sequential)]
public class SP_DRVINFO_DATA
{
public Int32 cbSize;
public Int32 driverType;
public UIntPtr reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public String description;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public String mfgName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
public String providerName;
public FILETIME driverDate;
public Int64 driverVersion;
};
[DllImport("setupapi.dll", SetLastError = true)]
public static extern bool SetupDiEnumDriverInfo(IntPtr lpInfoSet, SP_DEVINFO_DATA deviceInfoData, UInt32 driverType, Int32 memberIndex, SP_DRVINFO_DATA driverInfoData);
The API call returns with false immediately, the Marshal.GetLastWin32Error().ToString()
returns 259
, which is ERROR_NO_MORE_ITEMS
.
I just don't get it, and my hopes are high I am just making some stupid mistake that I am not able to see because I have read hardly anything but msdn lately, and it gets incredibly tiring...
Any help is greatly appreciated, thanks a lot!
Upvotes: 2
Views: 2471
Reputation: 11
Here are the API and struct definitions that both worked on x64 and x86. I am adding also SetupDiGetDriverInfoDetail, good chance that you'll also need it.
API:
DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SetupDiGetDriverInfoDetail(
IntPtr DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
ref SP_DRVINFO_DATA DriverInfoData,
ref SP_DRVINFO_DETAIL_DATA DriverInfoDetailData,
Int32 DriverInfoDetailDataSize,
ref Int32 RequiredSize);
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SetupDiEnumDriverInfo(
IntPtr DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
int DriverType,
int MemberIndex,
ref SP_DRVINFO_DATA DriverInfoData);
structs:
#if !WIN64
[StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Unicode)]
#else
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)]
#endif
public struct SP_DRVINFO_DATA
{
public int cbSize;
public uint DriverType;
public UIntPtr Reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Description;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string MfgName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string ProviderName;
public System.Runtime.InteropServices.ComTypes.FILETIME DriverDate;
public ulong DriverVersion;
}
#if !WIN64
[StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Unicode)]
#else
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)]
#endif
public struct SP_DRVINFO_DETAIL_DATA
{
public Int32 cbSize;
public System.Runtime.InteropServices.ComTypes.FILETIME InfDate;
public Int32 CompatIDsOffset;
public Int32 CompatIDsLength;
public IntPtr Reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String SectionName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public String InfFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String DrvDescription;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public String HardwareID;
};
Upvotes: 1
Reputation: 2640
There are several problems with the struct, the most annoying being that one has to specify pack=4 so the native code will find the correct entry points.
This works:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
public struct SP_DRVINFO_DATA
{
public int cbSize;
public int DriverType;
public UInt32 Reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Description;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string MfgName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string ProviderName;
public System.Runtime.InteropServices.ComTypes.FILETIME DriverDate;
public long DriverVersion;
}
Of course it is a god idea to actually prefix the P/Invokes with Charset=Charset.Unicode
, too.
Upvotes: 1
Reputation: 5138
Well off the top I can tell you you don't match the function signature which should be:
[DllImport("setupapi.dll", SetLastError = true, charset=Charset.Unicode)]
[return:MarshalAs(UnmanagedType.Bool)]
private static extern bool SetupDiEnumDriverInfo(
[In] IntPtr lpInfoSet,
[In, Optional] SP_DEVINFO_DATA deviceInfoData,
[In] UInt32 driverType,
[In] Int32 memberIndex,
[Out] out SP_DRVINFO_DATA driverInfoData);
That out is important as it specifies that it needs to pull back out the data from the PInvoke.
Upvotes: 1