2

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!

Janis F
  • 2,637
  • 1
  • 25
  • 36

3 Answers3

1

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.

Mgetz
  • 5,108
  • 2
  • 33
  • 51
  • Thanks, that's certainly one thing that's faulty in my code! However, it did not solve my problem. Thank you for the effort, though! – Janis F Jun 27 '13 at 14:00
  • is it possible that the enumeration is empty? Have you tried a small unmanaged console app to test? – Mgetz Jun 27 '13 at 14:06
  • I test against the DevCon tool-- I believe they use the same API, and I know that for the device I am testing, there is definitely more than one driver instance available. – Janis F Jun 27 '13 at 14:12
  • It also appears your structure is wrong, I've updated my answer based on MSDN – Mgetz Jun 27 '13 at 14:18
  • I believe you are mixing up SP_DEVINFO_DATA and SP_D**R**VINFO_DATA – Janis F Jun 27 '13 at 14:20
  • Yes, but I am passing in a SP_DEVINFO_DATA (which I use successfully for enabling/disabling devices). It is the out struct that is a SP_DRVINFO_DATA (http://msdn.microsoft.com/en-us/library/windows/hardware/ff553287%28v=vs.85%29.aspx). – Janis F Jun 27 '13 at 14:25
  • Saw that and deleted my comment, very confusing on Microsoft's part – Mgetz Jun 27 '13 at 14:26
  • Yes, I know :/ Thanks heaps for the effort! – Janis F Jun 27 '13 at 14:27
1

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.

Janis F
  • 2,637
  • 1
  • 25
  • 36
1

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;
        };