找回密码
 加入
搜索
查看: 13798|回复: 12

[系统综合] [已解决] SetupAPI 在64位系统下获取 设备驱动版本 问题

  [复制链接]
发表于 2010-10-30 10:26:25 | 显示全部楼层 |阅读模式
本帖最后由 yhxhappy 于 2010-11-1 12:38 编辑

现已通过其它方法解决取得驱动版本的问题。

如题!
#include <SetupApi.au3>

Local $hDevs, $tDevInfo, $aDisplay[1][2] = [[0]]
$hDevs = _SetupDiGetClassDevs($DIGCF_PRESENT, "Display")
While _SetupDiEnumDeviceInfo($hDevs, $aDisplay[0][0], $tDevInfo)
        $aDisplay[0][0] += 1
        $sDescr = _SetupDiGetDeviceRegistryProperty($hDevs, $tDevInfo, $SPDRP_DEVICEDESC)
        $sName = _SetupDiGetDeviceRegistryProperty($hDevs, $tDevInfo, $SPDRP_FRIENDLYNAME)
        If $sName <> "" Then $sDescr = $sName
        Redim $aDisplay[$aDisplay[0][0] + 1][2]
        $aDisplay[$aDisplay[0][0]][0] = $sDescr        ; 显卡型号
        $aDisplay[$aDisplay[0][0]][1] = _SetupDiGetDeviceInstanceID($hDevs, $tDevInfo) ; 设备范例ID
WEnd
_SetupDiDestroyDeviceInfoList($hDevs)

$Version = Get_Driver_Version($aDisplay[1][1])
MsgBox(0, "", "显卡型号:" & $aDisplay[1][0] & @CRLF & "驱动版本:" & $Version & @CRLF & "范例ID:" & $aDisplay[1][1])
Exit


Func Get_Driver_Version($InstanceID)        
        If $InstanceID = "" Then Return "Unknown"
        Local $hDevs,  $tDevInfo, $tDrvInfo, $tDrvDetail, $sInf, $sDateVer
        
        _SetupDiCreateDeviceDevs($InstanceID, $hDevs, $tDevInfo)
        _SetupDiBuildDriverInfoList($hDevs, $tDevInfo)
        _SetupDiSelectBestCompatDrv($hDevs, $tDevInfo)
        _SetupDiGetSelectedDriver($hDevs, $tDevInfo, $tDrvInfo)
        _SetupDiGetDriverInfoDetail($hDevs, $tDevInfo, $tDrvInfo, $tDrvDetail)
                        
        $sInf = DllStructGetData($tDrvDetail, "InfFileName")
        $sDateVer = IniRead($sInf, "Version", "DriverVer", "Unknown")
        If $sDateVer = "Unknown" Or $sDateVer = "" Then
                Return "Unknown"
        Else
                $VersionArray = StringSplit($sDateVer, ",", 1)
                If $VersionArray[0] = 1 Then
                        Return "Unknown"
                Else
                        While 1
                                If StringLeft($VersionArray[2], 1) <> " " Then ExitLoop
                                $VersionArray[2] = StringTrimLeft($VersionArray[2], 1)
                        WEnd
                        Return $VersionArray[2]
                EndIf
        EndIf
EndFunc
以上部分脚本截取自pusofalse写的”FSeven_V47 设备管理器“,在32位的WINDOWS下可以通过设备范例ID取得驱动版本,但在64位系统下获取失败。
在系统设备管理器里有版本信息,不了解系统是如何获取的。
请pusofalse以及各位大大帮我看看!

评分

参与人数 1金钱 +10 收起 理由
hzxymkb + 10 感谢主动将修改帖子分类为[已解决],请继续 ...

查看全部评分

 楼主| 发表于 2010-10-30 15:26:51 | 显示全部楼层
没人看吗,自己顶!
发表于 2010-11-3 10:30:23 | 显示全部楼层
回复 1# yhxhappy

楼主能提供解决方法上来吗?
 楼主| 发表于 2010-11-6 13:32:29 | 显示全部楼层
本帖最后由 yhxhappy 于 2010-11-6 13:37 编辑

回复 3# hzxymkb

我发的帖子还是第一次被版主打分呢,很高兴。
下面是我解决的代码,有部分是从 pusofalse 写的”FSeven_V47 设备管理器“ 搬的
还是以取显卡驱动版本为例。我在32位和64位的WIN_2K, WIN_XP, WIN_VISTA, WIN_2003, WIN_2008, WIN_2008R2, WIN_7验证通过。
#include <SetupApi.au3>

FindDeviceRecur(_CM_Locate_DevNode(""))

Func FindDeviceRecur($hDevInst)
        $aChild = _CM_Enumerate_Children($hDevInst)        
        For $i = 1 To $aChild[0]
                $hDevInst = _CM_Locate_DevNode($aChild[$i])
                $Class = _CM_Get_DevNode_Registry_Property($hDevInst, $CM_DRP_CLASS)
                $sDescr = _CM_Get_DevNode_Registry_Property($hDevInst, 1)
                $Version = Get_Driver_Version($hDevInst)
                If $Class = "Display" Then MsgBox(0,"","显卡型号:" & $sDescr & @CRLF & @CRLF & "驱动版本:" & $Version)
               ;此处只是为了取显卡的信息,所以加了判断,去掉可以取所有硬件驱动版本信息
        FindDeviceRecur($hDevInst)
        Next
EndFunc


Func Get_Driver_Version($hDevInst)
        
        $ClassGUID = _CM_Get_DevNode_Registry_Property($hDevInst, 10)
        
        If $ClassGUID = "" Then Return "Unknown"
        If @OSArch = "X86" Then
                $Reg = "HKLM\SYSTEM\ControlSet001\Control\Class"
        Else
                $Reg = "HKLM64\SYSTEM\ControlSet001\Control\Class"
        EndIf
        
        $Version = RegRead($Reg & $ClassGUID, "DriverVersion")

        If $Version = "" Then
                Return "Unknown"
        Else
                Return $Version
        EndIf
EndFunc
发表于 2011-11-12 22:50:37 | 显示全部楼层
学习了!
谢谢分享
发表于 2014-8-6 09:34:40 | 显示全部楼层
回复 4# yhxhappy

请问如果我的电脑里有一些驱动,他们的类名是一样的,我如何筛选他们【比如类名为system,一搜一大堆】
 楼主| 发表于 2014-8-6 14:35:07 | 显示全部楼层
回复 6# maxf4


    不太明白你问的意思。下面是一个类似设备管理器的脚本供参考
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#Include <GuiTreeView.au3>
#include <SetupApi.au3>


$DMGUI = GUICreate("Device Manager", 800, 600)

$DMTree = GUICtrlCreateTreeView(1, 1, 800, 600)
_HardwareScan()

GUISetState()

While 1
   If GUIGetMsg() = -3 Then Exit
WEnd

Func _HardwareScan()                                                                        ;扫描本机硬件信息并将信息添加至 TREE 控件
   Global $Hardware[2000][4], $Class[2000][2], $HWNum = 1

   _FindDeviceRecur(_CM_Locate_DevNode(""))

   ReDim $Hardware[$HWNum][4]
   $Hardware[0][0] = $HWNum-1

   _ArraySort($Hardware, 0, 1, 0, 1)
   _GUICtrlTreeView_DeleteAll($DMTree)

   Local $ClassItemString = "", $hItem2, $icon, $v
   $hItem = GUICtrlCreateTreeViewItem(@ComputerName, $DMTree)                                                        ;计算机名添加进 TREE控件
   For $a = 1 To $Hardware[0][0]
          $GUID = $Hardware[$a][3]
          $GUIDName = $Hardware[$a][1]
          If Not StringInStr($ClassItemString, $GUIDName & "|") Then
                 $hItem2 = GUICtrlCreateTreeViewItem($GUIDName, $hItem)                                                ;大类
                 $IconString = RegRead("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class" & $GUID, "IconPath")
                 If $IconString <> "" Then
                        $tt = StringSplit($IconString, ",")
                        If Not @error And $tt[0] = 2 Then
                           ;If $GUID = "{4d36e968-e325-11ce-bfc1-08002be10318}" Or $GUID = "{eec5ad98-8080-425f-922a-dabf3de3f69a}" Then        ;显卡及便捷设备图标
                                ;  $icon = @ScriptDir & "\ICON" & $GUID & ".ICO"
                                ;  $v = 0
                           ;Else
                                  $icon = $tt[1]
                                  $v = $tt[2]
                           ;EndIf
                           _GUICtrlTreeView_SetIcon($DMTree, $hItem2, $icon, $v)
                        EndIf
                 EndIf
                 $ClassItemString &= $GUIDName & "|"
          EndIf

          $hItem3 = GUICtrlCreateTreeViewItem($Hardware[$a][0], $hItem2)                        ;硬件添加进 TREE内的大类,如显卡设备属于 显示适配器 类
          _GUICtrlTreeView_SetIcon($DMTree, $hItem3, $icon, $v)
          $hItem4 = GUICtrlCreateTreeViewItem("Version: " & $Hardware[$a][2], $hItem3)
          _GUICtrlTreeView_SetIcon($DMTree, $hItem4, $icon, $v)
   Next
   GUICtrlSetState($hItem, $GUI_EXPAND)                                                                        ;展开父项
EndFunc

Func _FindDeviceRecur($hDevInst)                                                        ;找到并将符合条件的设备添加进数组,此函数供 _HardwareScan() 函数调用
   $aChild = _CM_Enumerate_Children_Ex($hDevInst, 0)
   For $i = 1 To $aChild[0]
          $hDevInst = _CM_Locate_DevNode($aChild[$i])
          $aChild[$i] = StringUpper($aChild[$i])
          $iStatus = _CM_Get_DevNode_Status($hDevInst)                                                        ;根据设备号来判断设备是否在 设备管理器 内显示出来 $DN_NO_SHOW_IN_DM
          If bitAND($iStatus, $DN_NO_SHOW_IN_DM) Then ContinueLoop

          $CLASSGuid = _CM_Get_DevNode_Registry_Property($hDevInst, $CM_DRP_CLASSGUID)                ;根据设备ID取得该设备所属的CLASS
          If $CLASSGuid = "{8ECC055D-047F-11D1-A537-0000F8753ED1}" Then ContinueLoop                ;非即插即用设备 排除

          $DEVName = _CM_Get_DevNode_Registry_Property($hDevInst, $CM_DRP_FRIENDLYNAME)                ;设备名称
          If $DEVName = "" Then $DEVName = _CM_Get_DevNode_Registry_Property($hDevInst, $CM_DRP_DEVICEDESC)                ;设备名称

          $GetClass = _CM_Get_DevNode_Registry_Property($hDevInst, $CM_DRP_CLASS)                ;根据设备ID取得该设备所属的CLASS
          $GetService = _CM_Get_DevNode_Registry_Property($hDevInst, $CM_DRP_SERVICE)
          $tStatus = _CM_Query_Device_Problem($hDevInst)                                                                ;根据设备号返回设备状态代码
          $CLASSName = _SetupDiGetClassDescription($CLASSGuid)


          $Hardware[$HWNum][1] = _SetupDiGetClassDescription($CLASSGuid)                                ;将设备所属的 Class 中文名称
          $Hardware[$HWNum][0] = $DEVName                                                                                                ;将设备名称 写进数组
          $Hardware[$HWNum][2] = _Get_Driver_Version($hDevInst)                                                        ;驱动版本
          $Hardware[$HWNum][3] = $CLASSGuid                                                                                                ;

          $HWNum += 1
          _FindDeviceRecur($hDevInst)
   Next
EndFunc


Func _Get_Driver_Version($hDevInst)
   $ClassGUID = _CM_Get_DevNode_Registry_Property($hDevInst, 10)
   If $ClassGUID = "" Then Return "Unknown"
   If @OSArch = "X86" Then
          $Reg = "HKLM\SYSTEM\ControlSet001\Control\Class"
   Else
          $Reg = "HKLM64\SYSTEM\ControlSet001\Control\Class"
   EndIf

   $Version = RegRead($Reg & $ClassGUID, "DriverVersion")
   If $Version = "" Then
          Return "Unknown"
   Else
          Return $Version
   EndIf
EndFunc
发表于 2014-9-8 21:17:42 | 显示全部楼层
哇个坟,给其他遇到类似问题的人一个解决方法。
楼主代码无需任何更改,第一行增加 #PRE_UseX64=n 已32位方式运行程序即可。
 楼主| 发表于 2014-9-9 22:11:48 | 显示全部楼层
回复 8# nmgwddj


    我都是用AUTOIT官网下载的原版软件,加这个参数能用吗?我一直认为这些参数是汉化版才行的。
发表于 2014-9-10 09:13:35 | 显示全部楼层
回复 9# yhxhappy


    其实就是编译为32位就可以了。
发表于 2016-4-30 16:08:23 | 显示全部楼层
回复 1# yhxhappy

您好,我用主楼的代码可以编译运行,为什么下面发的运行提示已重复定义的变量,我在论坛上搜了下,说忽略就可以编译,但是我这过不去,实在不知道为什么了.请问下是您用的是什么版本啊?
发表于 2019-1-14 22:59:38 | 显示全部楼层
来回复求金币来着
发表于 2019-1-15 04:40:19 | 显示全部楼层
来回复求金币来着.h
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-11-15 00:51 , Processed in 0.096160 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表