xzf680 发表于 2021-7-30 14:53:56

【已解决】关于P版磁盘信息的一段代码为什么要执行两次,有没办法执行一次就得到

本帖最后由 xzf680 于 2021-8-2 13:47 编辑

这是P版的一段代码,感觉不错,但为什么要执行两次才能得到结果,大家帮忙分析一下,谢谢
pusofalse原帖地址:https://www.autoitx.com/forum.php?mod=viewthread&tid=9470&highlight=%B4%C5%C5%CC


#include <WinAPI.au3>
#include <GUIConstants.au3>
#include <GUIComboBox.au3>
#include <Array.au3>
CONST $tagSPDEVINFODATA = "dword Size;byte Guid;dword DevInst;ulong_ptr Reserved"
Global $iPhysDisk
Global $aDrive, $aUdrive = [], $aTrayItem =
      $aUdrive = 0
      Redim $aUdrive
_AddItem()
_AddItem();为什么要执行两次才能得到结果?

Func _AddItem()
      $aDrive = _EnumPhysicalDrives()      
      For $i = 1 to $aDrive
                $sString = $aDrive[$i] & " - " & $aDrive[$i]
               ConsoleWrite($sString & @LF)
                _ArrayDisplay($aDrive)
                If bitAND($aDrive[$i], 2) Then
                        $aUdrive += 1
                        Redim $aUdrive[$aUdrive + 1]
                        $aUdrive[$aUdrive] = $aDrive[$i]
                        $aUdrive[$aUdrive] = $aDrive[$i]
                        $aUdrive[$aUdrive] = $aDrive[$i]
                        $aUdrive[$aUdrive] = $aDrive[$i]
                Else
                        TrayItemSetState(-1, 128)
                EndIf
      Next
EndFunc      ;==>_AddItem

Func _EnumPhysicalDrives()
      Local $sTempDriveStr, $aTempDriveArray, $hDevice
      Local $iNumDisks, $tSP_DEVINFO, $aGUID, $hDevs
      Local $sDrivePresent, $aDrivePresent, $aResult = []

      For $i = 0 to 120
                $sTempDriveStr &= $i & ","
      Next
      $sTempDriveStr = StringTrimRight($sTempDriveStr, 1)
      $aTempDriveArray = StringSplit($sTempDriveStr, ",")

      $aGUID = _SetupDiClassGuidsFromName("DiskDrive")   
      If $aGUID = 0 Then Return SetError(2, 0, $aResult)
      $hDevs = _SetupDiGetClassDevs(2, _WinAPI_GUIDFromString($aGUID))
      While _SetupDiEnumDeviceInfo($hDevs, $iNumDisks, $tSP_DEVINFO)
                $iNumDisks += 1
      WEnd
      $aResult = $iNumDisks
      Redim $aResult[$iNumDisks + 1]

      For $i = 1 to $aTempDriveArray - 1
                $sDrive = "\\.\PhysicalDrive" & $aTempDriveArray[$i]
                $hDevice = _WinAPI_CreateFile($sDrive, 2, 6, 6, 1)
                If $hDevice = 0xFFFFFFFF Then ContinueLoop
                _DeviceCloseHandle($hDevice)
                $sDrivePresent &= $aTempDriveArray[$i] & ","
      Next
      $sDrivePresent = StringTrimRight($sDrivePresent, 1)
      $aDrivePresent = StringSplit($sDrivePresent, ",")
      For $i = 1 to $iNumDisks
                If $i > $aDrivePresent Then ContinueLoop
                _SetupDiEnumDeviceInfo($hDevs, $i - 1, $tSP_DEVINFO)
                $aResult[$i] = "\\.\PhysicalDrive" & $aDrivePresent[$i]
                $aResult[$i] = _SetupDiGetDeviceRegistryProperty($hDevs, $tSP_DEVINFO, 0xC)
                $aResult[$i] = StringTrimRight(BinaryToString($aResult[$i]), 1)
                $aResult[$i] = _GetDiskPartitions($aDrivePresent[$i])
                $aResult[$i] = Number(_SetupDiGetDeviceRegistryProperty($hDevs, $tSP_DEVINFO, 32))
      Next
      
      _SetupDiDestroyDeviceInfoList($hDevs)
      Return $aResult
EndFunc      ;==>_EnumPhysicalDrives



Func _GetDiskPartitions($iPhysDriveIndex)
      Local $aDrive, $sResult, $tBuffer, $hDev, $iIndex

      $aDrive = DriveGetDrive("All")
      $tBuffer = DllStructCreate("dword")
      For $i = 1 to $aDrive
                $hDev = _WinAPI_CreateFile("\\.\" & $aDrive[$i], 2, 6, 6, 1, 0)
                If $hDev = 0xFFFFFFFF Then ContinueLoop
                _DeviceIoControl($hDev, 0x2D1080, 0, 0, $tBuffer, 12, 0)
                _DeviceCloseHandle($hDev)
                $iIndex = DllStructGetData($tBuffer, 1, 2)
                If $iPhysDriveIndex = $iIndex Then $sResult &= $aDrive[$i] & ","
      Next
      $tBuffer = 0
      Return (StringTrimRight($sResult, 1))
EndFunc      ;==>_GetDiskPartitions


Func _DeviceIoControl($hDevice, $iCtrlCode, $pIn, $iIn, $pOut, $iOut, $pOverlapped = 0)
      Local $iResult

      If IsDllStruct($pIn) Then $pIn = DllStructGetPtr($pIn)
      If IsDllStruct($pOut) Then $pOut = DllStructGetPtr($pOut)
      If IsDllStruct($pOverlapped) Then $pOverlapped = DllStructGetPtr($pOverLapped)
      $iResult = DllCall("Kernel32.dll", "int", "DeviceIoControl", "ptr", $hDevice, _
                        "dword", $iCtrlCode, "ptr", $pIn, "dword", $iIn, _
                        "ptr", $pOut, "dword", $iOut, "int*", 0, "ptr", $pOverlapped)
      Return SetError(_WinAPI_GetLastError(), $iResult, $iResult)
EndFunc      ;==>_DeviceIoControl


Func _SetupDiEnumDeviceInfo($hDevs, $iMemberIdx, ByRef $tSP_DEVINFO_DATA)
      Local $iResult, $pSP_DEVINFO_DATA

      If Not IsDllStruct($tSP_DEVINFO_DATA) Then
                $tSP_DEVINFO_DATA = DllStructCreate($tagSPDEVINFODATA)
                DllStructSetData($tSP_DEVINFO_DATA, "Size", DllStructGetSize($tSP_DEVINFO_DATA))
      EndIf
      $pSP_DEVINFO_DATA = DllStructGetPtr($tSP_DEVINFO_DATA)
      $iResult = DllCall("Setupapi.dll", "int", "SetupDiEnumDeviceInfo", _
                        "hWnd", $hDevs, "int", $iMemberIdx, "ptr", $pSP_DEVINFO_DATA)
      Return SetError(_WinAPI_GetLastError(), 0, $iResult)
EndFunc      ;==>_SetupDiEnumDeviceInfo


Func _SetupDiGetClassDevs($iFlags, $pGuid = 0, $sEnumerator = "")
      Local $iResult, $sType = "str"
      If $sEnumerator = "" Then $sType = "ptr"

      If IsDllStruct($pGuid) Then $pGuid = DllStructGetPtr($pGuid)
      $iResult = DllCall("Setupapi.dll", "hWnd", "SetupDiGetClassDevs", _
                        "ptr", $pGuid, $sType,$sEnumerator, "hWnd", 0, "dword", $iFlags)
      Return SetError(_WinAPI_GetLastError(), 0, $iResult)
EndFunc      ;==>_SetupDiGetClassDevs

Func _SetupDiDestroyDeviceInfoList($hDevs)
      Local $iResult
      $iResult = DllCall("Setupapi.dll", "int", "SetupDiDestroyDeviceInfoList", "ptr", $hDevs)
      Return SetError(_WinAPI_GetLastError(), 0, $iResult)
EndFunc      ;==>_SetupDiDestroyDeviceInfoList


Func _SetupDiRemoveDevice($hDevs, $pSP_DEVINFO_DATA)
      Local $iResult

      If IsDllStruct($pSP_DEVINFO_DATA) Then
                $pSP_DEVINFO_DATA = DllStructGetPtr($pSP_DEVINFO_DATA)
      EndIf
      $iResult = DllCall("Setupapi.dll", "int", "SetupDiRemoveDevice", _
                        "hWnd", $hDevs, "ptr", $pSP_DEVINFO_DATA)
      Return SetError(_WinAPI_GetLastError(), 0, $iResult)
EndFunc      ;==>_SetupDiRemoveDevice



Func _SetupDiClassGuidsFromName($sClassName)
      Local $tBuffer, $pBuffer, $aResult = , $iResult, $tagBuffer, $iSysError

      $iResult = DllCall("Setupapi.dll", "int", "SetupDiClassGuidsFromName", _
                        "str", $sClassName, "ptr", 0, "dword", 0, "dword*", 0)
      $aResult = $iResult
      Redim $aResult[$iResult + 1]
      For $i = 1 to $iResult
                $tagBuffer &= "byte;"
      Next
      $tBuffer = DllStructCreate($tagBuffer)
      $pBuffer = DllStructGetPtr($tBuffer)
      $iResult = DllCall("Setupapi.dll", "int", "SetupDiClassGuidsFromName", _
                        "str", $sClassName, "ptr", $pBuffer, _
                        "dword", $iResult, "dword*", 0)
      If $iResult = 0 Then $iSysError = _WinAPI_GetLastError()
      For $i = 1 to $iResult
                $aResult[$i] = _WinAPI_StringFromGUID(DllStructGetPtr($tBuffer, $i))
      Next
      $tBuffer = 0
      Return SetError($iSysError, 0, $aResult)
EndFunc      ;==>_SetupDiClassGuidsFromName



Func _SetupDiGetDeviceRegistryProperty($hDevs, $pSP_DEVINFO_DATA, $iProperty)
      Local $iResult, $tBuffer, $pBuffer, $vResult, $iSysError

      If IsDllStruct($pSP_DEVINFO_DATA) Then
                $pSP_DEVINFO_DATA = DllStructGetPtr($pSP_DEVINFO_DATA)
      EndIf
      $iResult = DllCall("Setupapi.dll", "int", "SetupDiGetDeviceRegistryProperty", _
                        "hWnd", $hDevs, "ptr", $pSP_DEVINFO_DATA, _
                        "dword", $iProperty, "int*", 0, "ptr", 0, "dword", 0, "int*", 0)
      $tBuffer = DllStructCreate("byte[" & $iResult & "]")
      $pBuffer = DllStructGetPtr($tBuffer)
      $iResult = DllCall("Setupapi.dll", "int", "SetupDiGetDeviceRegistryProperty", _
                        "hWnd", $hDevs, "ptr", $pSP_DEVINFO_DATA, _
                        "dword", $iProperty, "int*", 0, "ptr", $pBuffer, _
                        "dword", $iResult, "int*", 0)
      If $iResult = 0 Then $iSysError = _WinAPI_GetLastError()
      $vResult = DllStructGetData($tBuffer, 1)
      $tBuffer = 0
      Return SetError($iSysError, $iResult, $vResult)
EndFunc      ;==>_SetupDiGetDeviceRegistryProperty


Func _DeviceCloseHandle($hDevice)
      Local $iResult = DllCall("Kernel32.dll", "int", "CloseHandle", "long", $hDevice)
      Return $iResult <> 0
EndFunc      ;==>_DeviceCloseHandle



另外一个问题If bitAND($aDrive[$i], 2) Then这里是怎么判断的USB磁盘,如本地磁盘又怎么判断?

然后我测试注释了      _ArrayDisplay($aDrive)   添加一行 ConsoleWrite($sString & @LF)    居然取不到结果了,怪事!!!

haijie1223 发表于 2021-8-1 17:19:20

问题1:先dllopen,再dllcall。
问题2:按照你给的代码,2、3代表可移动磁盘,1是本地磁盘。
问题3:问题1解决了,这个问题应该就解决了。
没有实际测试,需要你自己试验。

xzf680 发表于 2021-8-2 13:46:13

haijie1223 发表于 2021-8-1 17:19
问题1:先dllopen,再dllcall。
问题2:按照你给的代码,2、3代表可移动磁盘,1是本地磁盘。
问题3:问题 ...

原来是这样,学习了,谢谢发哥
页: [1]
查看完整版本: 【已解决】关于P版磁盘信息的一段代码为什么要执行两次,有没办法执行一次就得到