none
C#怎么获取已知USB设备驱动信息(请看内容) RRS feed

  • 问题

  • 我枚举到了USB设备,设备是一个连在USB的手机,我现在可以枚举到它的产品型号,我现在想知道怎么获取此设备的是否已经安装驱动(类似MOTO手机的USB驱动)

    2013年3月19日 13:31

答案

  • Hi 名字真难取,

      欢迎来到MSDN中文论坛。

      你这个问题可以通过两种方式去获得:WMI-Windows Management Instrumentation方式或者通过WDM调用来解决。

     

    1 使用WMI中的Win32_PnPSignedDriver类

    Win32_PnPSignedDriver的详细信息:http://msdn2.microsoft.com/en-us/library/aa394354.aspx
    使用WMI(Windows Management Instrumentation)是最为方便的方法。可以根据下面的程序片段来得到我们所需要的DriverVersion。

    private string GetDriverVersion( string hardwareID )
     {
         string queryString = "SELECT HardwareID, DriverVersion FROM Win32_PnPSignedDriver";
         SelectQuery selectQuery = new SelectQuery( queryString );
         ManagementObjectSearcher searcher = new ManagementObjectSearcher(selectQuery);
    
        foreach (ManagementObject mo in searcher.Get())
         {
             object tempID = mo["HardwareID"];
             if( tempID!=null && tempID.ToString().ToUpper() == hardwareID.Trim().ToUpper() )
             {
                 return mo["DriverVersion"].ToString();
             }
         }
    
        return "UnknownVersion";
     }
    

      这个方法唯一不好的方面是不支持Windows2000,只有Windows Vista,Windows XP和Windows 2003支持这个类。

    2 使用PInvoke

      为了弥补Windows 2000操作系统的这方面不足,因此就想到了使用PInvoke的方式调用Windows API。通过查询MSDN,知道可以使用SetupDixxxx这种函数来实现我们的功能。基本的思路如下:
    (1)利用SetupDiGetClassDevs这个函数得到一个含有所有设备信息的类。
    (2)利用SetupDiEnumDeviceInfo得到某个具体设备的信息,保存在一个名为SP_DEVINFO_DATA的结构中。
    (3)利用SetupDiGetDeviceRegistryProperty得到设备的HardwareID,和输入的HardwareID比较
    (4)如果两个HardwareID是一样的,那么就利用SetupDiBuildDriverInfoList得到这个设备的驱动程序信息列表
    (5)利用SetupDiEnumDriverInfo遍历驱动程序信息列表,得到所有需要的信息,保存在一个名为SP_DRVINFO_DATA的结构中
    (6)从SP_DRVINFO_DATA中就可以得到驱动程序的版本。是一个DWORDLONG类型的数,需要转换成x.x.x.x的结构

    要值得注意的是上述函数都封装在setupapi.dll中,要使用这些函数,需要安装Windows DDK。

    在C#中,我们利用pInvoke的方式来调用Windows API的时候,需要注意类型的对应和结构对齐。比如上面的SP_DEVINFO_DATA结构需要按照如下方式声明

    [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
     public struct SP_DEVINFO_DATA
     {
          public int cbSize;
          public Guid ClassGuid;
          public IntPtr DevInst;
          public IntPtr Reserved;
     }


    要注意的是LayoutKind.Sequential, Pack = 4 和 public IntPtr Reserved。如果不按照这样声明,无法调用成功。
    SP_DRVINFO_DATA也可以按照一样的方式进行声明。

    [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
     public struct SP_DRVINFO_DATA
     {
         public int cbSize;
         public int DriverType;
         public IntPtr 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 ulong DriverVersion;
     }


    对于最后的从DWORDLONG转换成x.x.x.x的版本,可以按照下面的方式转换。DWORDLONG是8字节的无符号整数,x.x.x.x中的x是从0到65536的无符号整数,占2个字节。因此可以直接把8字节的整数分成4个2字节的整数,最后合起来就是版本号了。假设版本version = 1407379348914176,将version转换成2进制数为:
    101 00000000 00000001 00001010 00101000 00000000 00000000
    ---   ---------------------  ----------------------  ---------------------
    5                    1                             2600                              0
    因此,可以得到版本是5.1.2600.0。

    可以用下面这个示例函数来得到版本信息

     

    //version = 1407379348914176,转换后的版本为5.1.2600.0

    private string GetVersionFromLong( ulong version )
     {
         ulong baseNumber = 0xFFFF;
         StringBuilder sb = new StringBuilder();
         ulong temp = 0L;
        
         for( int offset = 48; offset >= 0; offset -= 16 )
         {
             temp = (version >> offset) & baseNumber;
             sb.Append( temp.ToString() + "." );
         }
        
         return sb.ToString();
     }

    这个方法适合于Win2000,Win XP,Win2003和Vista,具体这些介绍你也可以参考:在C#中根据HardwareID获取驱动程序信息(C#卸载USB设备时可能用到)


    Jason Wang [MSFT]
    MSDN Community Support | Feedback to us

    2013年3月20日 2:13
    版主
  • Hi 名字真难取,

      SELECT * FROM Win32_PnPSignedDriver

      如果你想知道其他相关内容,你可以看下面帖子:

      how can I get driver's version of Network Adapter ? by c# code?


    Jason Wang [MSFT]
    MSDN Community Support | Feedback to us

    2013年3月27日 8:19
    版主

全部回复

  • Hi 名字真难取,

      欢迎来到MSDN中文论坛。

      你这个问题可以通过两种方式去获得:WMI-Windows Management Instrumentation方式或者通过WDM调用来解决。

     

    1 使用WMI中的Win32_PnPSignedDriver类

    Win32_PnPSignedDriver的详细信息:http://msdn2.microsoft.com/en-us/library/aa394354.aspx
    使用WMI(Windows Management Instrumentation)是最为方便的方法。可以根据下面的程序片段来得到我们所需要的DriverVersion。

    private string GetDriverVersion( string hardwareID )
     {
         string queryString = "SELECT HardwareID, DriverVersion FROM Win32_PnPSignedDriver";
         SelectQuery selectQuery = new SelectQuery( queryString );
         ManagementObjectSearcher searcher = new ManagementObjectSearcher(selectQuery);
    
        foreach (ManagementObject mo in searcher.Get())
         {
             object tempID = mo["HardwareID"];
             if( tempID!=null && tempID.ToString().ToUpper() == hardwareID.Trim().ToUpper() )
             {
                 return mo["DriverVersion"].ToString();
             }
         }
    
        return "UnknownVersion";
     }
    

      这个方法唯一不好的方面是不支持Windows2000,只有Windows Vista,Windows XP和Windows 2003支持这个类。

    2 使用PInvoke

      为了弥补Windows 2000操作系统的这方面不足,因此就想到了使用PInvoke的方式调用Windows API。通过查询MSDN,知道可以使用SetupDixxxx这种函数来实现我们的功能。基本的思路如下:
    (1)利用SetupDiGetClassDevs这个函数得到一个含有所有设备信息的类。
    (2)利用SetupDiEnumDeviceInfo得到某个具体设备的信息,保存在一个名为SP_DEVINFO_DATA的结构中。
    (3)利用SetupDiGetDeviceRegistryProperty得到设备的HardwareID,和输入的HardwareID比较
    (4)如果两个HardwareID是一样的,那么就利用SetupDiBuildDriverInfoList得到这个设备的驱动程序信息列表
    (5)利用SetupDiEnumDriverInfo遍历驱动程序信息列表,得到所有需要的信息,保存在一个名为SP_DRVINFO_DATA的结构中
    (6)从SP_DRVINFO_DATA中就可以得到驱动程序的版本。是一个DWORDLONG类型的数,需要转换成x.x.x.x的结构

    要值得注意的是上述函数都封装在setupapi.dll中,要使用这些函数,需要安装Windows DDK。

    在C#中,我们利用pInvoke的方式来调用Windows API的时候,需要注意类型的对应和结构对齐。比如上面的SP_DEVINFO_DATA结构需要按照如下方式声明

    [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
     public struct SP_DEVINFO_DATA
     {
          public int cbSize;
          public Guid ClassGuid;
          public IntPtr DevInst;
          public IntPtr Reserved;
     }


    要注意的是LayoutKind.Sequential, Pack = 4 和 public IntPtr Reserved。如果不按照这样声明,无法调用成功。
    SP_DRVINFO_DATA也可以按照一样的方式进行声明。

    [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
     public struct SP_DRVINFO_DATA
     {
         public int cbSize;
         public int DriverType;
         public IntPtr 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 ulong DriverVersion;
     }


    对于最后的从DWORDLONG转换成x.x.x.x的版本,可以按照下面的方式转换。DWORDLONG是8字节的无符号整数,x.x.x.x中的x是从0到65536的无符号整数,占2个字节。因此可以直接把8字节的整数分成4个2字节的整数,最后合起来就是版本号了。假设版本version = 1407379348914176,将version转换成2进制数为:
    101 00000000 00000001 00001010 00101000 00000000 00000000
    ---   ---------------------  ----------------------  ---------------------
    5                    1                             2600                              0
    因此,可以得到版本是5.1.2600.0。

    可以用下面这个示例函数来得到版本信息

     

    //version = 1407379348914176,转换后的版本为5.1.2600.0

    private string GetVersionFromLong( ulong version )
     {
         ulong baseNumber = 0xFFFF;
         StringBuilder sb = new StringBuilder();
         ulong temp = 0L;
        
         for( int offset = 48; offset >= 0; offset -= 16 )
         {
             temp = (version >> offset) & baseNumber;
             sb.Append( temp.ToString() + "." );
         }
        
         return sb.ToString();
     }

    这个方法适合于Win2000,Win XP,Win2003和Vista,具体这些介绍你也可以参考:在C#中根据HardwareID获取驱动程序信息(C#卸载USB设备时可能用到)


    Jason Wang [MSFT]
    MSDN Community Support | Feedback to us

    2013年3月20日 2:13
    版主
  • 你好,先谢谢你的解答

    我想再问问这个private string GetDriverVersion( string hardwareID )里面的hardwareID是从哪个Win32_XXX里面获取到的

    2013年3月20日 12:08
  • Hi 名字真难取,

      SELECT * FROM Win32_PnPSignedDriver

      如果你想知道其他相关内容,你可以看下面帖子:

      how can I get driver's version of Network Adapter ? by c# code?


    Jason Wang [MSFT]
    MSDN Community Support | Feedback to us

    2013年3月27日 8:19
    版主
  • 多谢你的回复,但是那个帖子,主要是讲列举所有的驱动,我现在主要是想通过给定获取的设备ID或者标识之类的或者别的来获取此设备的驱动是否安装
    2013年3月27日 14:54