Bilgus Posted June 1, 2016 Posted June 1, 2016 (edited) Faster way to convert multiple dosdevice paths to file paths \Device\HarddiskVolume1\Program Files\ test1.exe =>C:\Program Files\ test1.exe Test 1 caches the drive letter and dosdevicename of every drive in a single string it then uses regexp to find the dosdevice and replace it with the drive letter, only re-caching when string isn't found Test 2 calls DriveGetDrive and _WinAPI_QueryDosDevice everytime and uses simple stringreplace Test 3 caches DriveGetDrive and _WinAPI_QueryDosDevice to an array and uses simple stringreplace, only re-cache when string isn't found expandcollapse popup#include <WinAPIFiles.au3> Local $DosDevicePath = _WinAPI_QueryDosDevice("c:") ConsoleWrite("C: = " & $DosDevicePath & @CRLF & @CRLF) ;Test1-------------------------------------------------------------------------------------- ConsoleWrite($DosDevicePath & "\Program Files\Test\myprogram\test1.exe" & " => ") Local $hTimer = TimerInit() Local $sDosDevMap = EnumDosDeviceMapString() ;ConsoleWrite("Lookup Strings: " & $sDosDevMap & @CRLF) For $x = 0 To 200 GetFilePathFromDosDevicePath("" & $DosDevicePath & "\Program Files\Test\myprogram\test1.exe", $sDosDevMap) Next For $x = 0 To 200 GetFilePathFromDosDevicePath("yu" & $DosDevicePath & "yu\Program Files\Test\myprogram\test1.exe", $sDosDevMap) Next For $x = 0 To 200 GetFilePathFromDosDevicePath($DosDevicePath & "yu\Program Files\Test\myprogram\test1.exe", $sDosDevMap) Next ConsoleWrite(TimerDiff($hTimer) & " MS" & @CRLF) ConsoleWrite(GetFilePathFromDosDevicePath($DosDevicePath & "\Program Files\Test\myprogram\test1.exe", $sDosDevMap) & " @error = " & @error & @CRLF) ConsoleWrite($DosDevicePath & "yu\Program Files\Test\myprogram\test1.exe" & " => ") ConsoleWrite(GetFilePathFromDosDevicePath($DosDevicePath & "yu\Program Files\Test\myprogram\test1.exe", $sDosDevMap) & " @error = " & @error & @CRLF) ConsoleWrite("yu" & $DosDevicePath & "yu\Program Files\Test\myprogram\test1.exe" & " => ") ConsoleWrite(GetFilePathFromDosDevicePath("yu" & $DosDevicePath & "yu\Program Files\Test\myprogram\test1.exe", $sDosDevMap) & " @error = " & @error & @CRLF & @CRLF) ;Test2-------------------------------------------------------------------------------------- ConsoleWrite($DosDevicePath & "\Program Files\Test\myprogram\test2.exe" & " => ") Local $hTimer = TimerInit() For $x = 0 To 200 _DosPathNameToPathName("" & $DosDevicePath & "\Program Files\Test\myprogram\test2.exe") Next For $x = 0 To 200 _DosPathNameToPathName("yu" & $DosDevicePath & "yu\Program Files\Test\myprogram\test2.exe") Next For $x = 0 To 200 _DosPathNameToPathName($DosDevicePath & "yu\Program Files\Test\myprogram\test2.exe") Next ConsoleWrite(TimerDiff($hTimer) & " MS" & @CRLF) ConsoleWrite(_DosPathNameToPathName($DosDevicePath & "\Program Files\Test\myprogram\test2.exe") & " @error = " & @error & @CRLF) ConsoleWrite($DosDevicePath & "yu\Program Files\Test\myprogram\test2.exe" & " => ") ConsoleWrite(_DosPathNameToPathName($DosDevicePath & "yu\Program Files\Test\myprogram\test2.exe") & " @error = " & @error & @CRLF) ConsoleWrite("yu" & $DosDevicePath & "yu\Program Files\Test\myprogram\test2.exe" & " => ") ConsoleWrite(_DosPathNameToPathName("yu" & $DosDevicePath & "yu\Program Files\Test\myprogram\test2.exe") & " @error = " & @error & @CRLF & @CRLF) ;Test3-------------------------------------------------------------------------------------- ConsoleWrite($DosDevicePath & "\Program Files\Test\myprogram\test3.exe" & " => ") Local $hTimer = TimerInit() Local $aEnumDosDevice = EnumDosDeviceMapStringArr() For $x = 0 To 200 _DosPathNameToPathNameArr("" & $DosDevicePath & "\Program Files\Test\myprogram\test3.exe", $aEnumDosDevice) ;_DosPathNameToPathName("" & $DosDevicePath & "uy\Program Files\Test\myprogram\test.exe") Next For $x = 0 To 200 _DosPathNameToPathNameArr("yu" & $DosDevicePath & "yu\Program Files\Test\myprogram\test3.exe", $aEnumDosDevice) Next For $x = 0 To 200 _DosPathNameToPathName($DosDevicePath & "yu\Program Files\Test\myprogram\test2.exe") Next ConsoleWrite(TimerDiff($hTimer) & " MS" & @CRLF) ConsoleWrite(_DosPathNameToPathNameArr($DosDevicePath & "\Program Files\Test\myprogram\test3.exe", $aEnumDosDevice) & " @error = " & @error & @CRLF) ConsoleWrite($DosDevicePath & "yu\Program Files\Test\myprogram\test3.exe" & " => ") ConsoleWrite(_DosPathNameToPathNameArr($DosDevicePath & "yu\Program Files\Test\myprogram\test3.exe", $aEnumDosDevice) & " @error = " & @error & @CRLF) ConsoleWrite("yu" & $DosDevicePath & "yu\Program Files\Test\myprogram\test3.exe" & " => ") ConsoleWrite(_DosPathNameToPathNameArr("yu" & $DosDevicePath & "yu\Program Files\Test\myprogram\test3.exe", $aEnumDosDevice) & " @error = " & @error & @CRLF & @CRLF) ;Test1-------------------------------------------------------------------------------------- Func EnumDosDeviceMapString() ;Make a list of found drives and their DosDevice Name ;c:=\Device\HarddiskVolume1;d:=\Device\HarddiskVolume2; Local $sResult = "" Local $aDrive = DriveGetDrive('ALL') If IsArray($aDrive) Then For $i = 1 To $aDrive[0] $sResult &= StringUpper($aDrive[$i]) & Chr(127) & _WinAPI_QueryDosDevice($aDrive[$i]) & ";" Next ;ConsoleWrite($sResult & @CRLF) Else ConsoleWrite("Error Enumerating Drives") Return SetError(1, 0, $sResult) EndIf Return SetError(@error, 0, $sResult) EndFunc ;==>EnumDosDeviceMapString Func GetFilePathFromDosDevicePath($DosDevicePath, ByRef $sDosDeviceMap) ;Replace DosDeviceName with Drive Letter:\ in a path ;\Device\HarddiskVolume1\Test => c:\Test Local $sDosTempName = "" Local $aResult = StringRegExp($DosDevicePath & "\\", "(?i)(^\\Device\\.+?)(?=\\)", 1, 1) ;Get only the \Device\HarddiskVolume part of the supplied path If IsArray($aResult) Then $sDosTempName = $aResult[0] For $i = 0 To 1 If $i = 1 Then ElseIf Not (StringInStr($sDosDeviceMap, $sDosTempName)) Then $sDosDeviceMap = EnumDosDeviceMapString() ;Failed try to get new drive mappings ContinueLoop EndIf $aResult = StringRegExp($sDosDeviceMap, "(?i)([\S]:(?=" & Chr(127) & StringReplace($sDosTempName, "\", "\\") & ";))", 1, 1) ;Return Drive Letter :\ If IsArray($aResult) Then Return StringReplace($DosDevicePath, $sDosTempName, $aResult[0]) Else Return SetError(1, 0, $DosDevicePath) EndIf Next EndIf Return SetError(2, 1, $DosDevicePath) EndFunc ;==>GetFilePathFromDosDevicePath ;Test2-------------------------------------------------------------------------------------- Func _DosPathNameToPathName($sPath) ;Yashied: www.autoitscript.com/forum/topic/119174-how-to-get-drive-letter-from-deviceharddiskvolumex/ Local $sName, $aDrive = DriveGetDrive('ALL') If Not IsArray($aDrive) Then Return SetError(1, 0, $sPath) EndIf For $i = 1 To $aDrive[0] $sName = _WinAPI_QueryDosDevice($aDrive[$i]) If StringInStr($sPath, $sName) = 1 Then Return StringReplace($sPath, $sName, StringUpper($aDrive[$i]), 1) EndIf Next Return SetError(2, 0, $sPath) EndFunc ;==>_DosPathNameToPathName ;Test3-------------------------------------------------------------------------------------- Func _DosPathNameToPathNameArr($sPath, ByRef $aEnumDosDevice) If Not IsArray($aEnumDosDevice) Then Return SetError(1, 0, $sPath) EndIf For $x = 0 To 1 For $i = 1 To $aEnumDosDevice[0][0] $sName = $aEnumDosDevice[1][$i] If StringInStr($sPath, $sName) = 1 Then Return StringReplace($sPath, $sName, $aEnumDosDevice[0][$i], 1) EndIf Next $aEnumDosDevice = EnumDosDeviceMapStringArr() Next Return SetError(2, 0, $sPath) EndFunc ;==>_DosPathNameToPathNameArr Func EnumDosDeviceMapStringArr() ;Make a list of found drives and their DosDevice Name ;c:=\Device\HarddiskVolume1;d:=\Device\HarddiskVolume2; Local $aDrive = DriveGetDrive('ALL') If IsArray($aDrive) Then Local $aResult[2][$aDrive[0] + 1] $aResult[0][0] = $aDrive[0] For $i = 1 To $aDrive[0] $aResult[0][$i] = StringUpper($aDrive[$i]) $aResult[1][$i] = _WinAPI_QueryDosDevice($aDrive[$i]) Next Else ConsoleWrite("Error Enumerating Drives") Return SetError(1, 0, "") EndIf Return $aResult EndFunc ;==>EnumDosDeviceMapStringArr my results: C: = \Device\HarddiskVolume11 \Device\HarddiskVolume11\Program Files\Test\myprogram\test1.exe => 301.698749422063 MS C:\Program Files\Test\myprogram\test1.exe @error = 0 \Device\HarddiskVolume11yu\Program Files\Test\myprogram\test1.exe => \Device\HarddiskVolume11yu\Program Files\Test\myprogram\test1.exe @error = 1 yu\Device\HarddiskVolume11yu\Program Files\Test\myprogram\test1.exe => yu\Device\HarddiskVolume11yu\Program Files\Test\myprogram\test1.exe @error = 2 \Device\HarddiskVolume11\Program Files\Test\myprogram\test2.exe => 357.898978780823 MS C:\Program Files\Test\myprogram\test2.exe @error = 0 \Device\HarddiskVolume11yu\Program Files\Test\myprogram\test2.exe => C:yu\Program Files\Test\myprogram\test2.exe @error = 0 yu\Device\HarddiskVolume11yu\Program Files\Test\myprogram\test2.exe => yu\Device\HarddiskVolume11yu\Program Files\Test\myprogram\test2.exe @error = 2 \Device\HarddiskVolume11\Program Files\Test\myprogram\test3.exe => 621.037589973027 MS C:\Program Files\Test\myprogram\test3.exe @error = 0 \Device\HarddiskVolume11yu\Program Files\Test\myprogram\test3.exe => C:yu\Program Files\Test\myprogram\test3.exe @error = 0 yu\Device\HarddiskVolume11yu\Program Files\Test\myprogram\test3.exe => yu\Device\HarddiskVolume11yu\Program Files\Test\myprogram\test3.exe @error = 2 Test1 has the added advantage of more selective matching and really shines when the dospath exists Edited June 1, 2016 by Bilgus Parsix 1
Bilgus Posted June 2, 2016 Author Posted June 2, 2016 With a bit of optimization I lopped off a few Milliseconds and made the code slightly more robust I think there are still some caveats that I don't have the ability to test atm These have to do with network drives "LanManRedirect" and possibly usb harddrives. I'd like to see some of these paths if anyone happens to run across them I'll be happy to update this function given the original paths expandcollapse popupFunc EnumDosDeviceMapString() ;Make a list of found drives and their DosDevice Name ;c:*\Device\HarddiskVolume1;d:*\Device\HarddiskVolume2; Local $sResult = "" Local $aDrive = DriveGetDrive('ALL') If IsArray($aDrive) Then For $i = 1 To $aDrive[0] $sResult &= StringUpper($aDrive[$i]) & Chr(127) & _WinAPI_QueryDosDevice($aDrive[$i]) & ";" Next ;Chr(127) is the DEL Char so string will actually show as c:\Device\HarddiskVolume1 ;ConsoleWrite($sResult & @CRLF) Else ConsoleWrite("Error Enumerating Drives") Return SetError(1, 0, $sResult) EndIf Return SetError(@error, 0, $sResult) EndFunc ;==>EnumDosDeviceMapString Func GetFilePathFromDosDevicePath($DosDevicePath, ByRef $sDosDeviceMap) ;Replace DosDeviceName with Drive Letter:\ in a path ;\Device\HarddiskVolume1\Test => c:\Test Local $sDosTempName Local $TempPath Local $aResult = StringRegExp($DosDevicePath & "\\", "(?i)(^\\Device\\.+?)(?=\\)(.*)(\\\\)", 1, 1) ;\Device\HarddiskVolume part is in elem 0 the rest elem 1 and \\ in elem 2 If IsArray($aResult) Then $sDosTempName = $aResult[0] $TempPath = $aResult[1] For $i = 0 To 1 If $i = 0 And Not (StringInStr($sDosDeviceMap, $sDosTempName & ";")) Then $sDosDeviceMap = EnumDosDeviceMapString() ;Failed try to get new drive mappings ContinueLoop EndIf $aResult = StringRegExp($sDosDeviceMap, "(?i)([\S]:(?=" & Chr(127) & StringReplace($sDosTempName, "\", "\\") & ";))", 1, 1) ;Return Drive Letter :\ If IsArray($aResult) Then ;Return StringReplace($DosDevicePath, $sDosTempName, $aResult[0]) Return $aResult[0] & $TempPath Else Return SetError(1, 0, $DosDevicePath) EndIf Next EndIf Return SetError(2, 1, $DosDevicePath) EndFunc ;==>GetFilePathFromDosDevicePath New Results: \Device\HarddiskVolume11\Program Files\Test\myprogram\test1.exe => 299.170215767646 MS C:\Program Files\Test\myprogram\test1.exe @error = 0 \Device\HarddiskVolume11yu\Program Files\Test\myprogram\test1.exe => \Device\HarddiskVolume11yu\Program Files\Test\myprogram\test1.exe @error = 1 yu\Device\HarddiskVolume11yu\Program Files\Test\myprogram\test1.exe => yu\Device\HarddiskVolume11yu\Program Files\Test\myprogram\test1.exe @error = 2 \Device\HarddiskVolume11\Program Files\Test\myprogram\test2.exe => 343.163865798586 MS C:\Program Files\Test\myprogram\test2.exe @error = 0 \Device\HarddiskVolume11yu\Program Files\Test\myprogram\test2.exe => C:yu\Program Files\Test\myprogram\test2.exe @error = 0 yu\Device\HarddiskVolume11yu\Program Files\Test\myprogram\test2.exe => yu\Device\HarddiskVolume11yu\Program Files\Test\myprogram\test2.exe @error = 2 \Device\HarddiskVolume11\Program Files\Test\myprogram\test3.exe => 587.511541271307 MS C:\Program Files\Test\myprogram\test3.exe @error = 0 \Device\HarddiskVolume11yu\Program Files\Test\myprogram\test3.exe => C:yu\Program Files\Test\myprogram\test3.exe @error = 0 yu\Device\HarddiskVolume11yu\Program Files\Test\myprogram\test3.exe => yu\Device\HarddiskVolume11yu\Program Files\Test\myprogram\test3.exe @error = 2 And a run with only valid paths: \Device\HarddiskVolume11\Program Files\Test\myprogram\test1.exe => 22.0635583572773 MS C:\Program Files\Test\myprogram\test1.exe @error = 0 \Device\HarddiskVolume11\Program Files\Test\myprogram\test1.exe => C:\Program Files\Test\myprogram\test1.exe @error = 0 \Device\HarddiskVolume11\Program Files\Test\myprogram\test1.exe => C:\Program Files\Test\myprogram\test1.exe @error = 0 \Device\HarddiskVolume11\Program Files\Test\myprogram\test2.exe => 111.547836387027 MS C:\Program Files\Test\myprogram\test2.exe @error = 0 \Device\HarddiskVolume11\Program Files\Test\myprogram\test2.exe => C:\Program Files\Test\myprogram\test2.exe @error = 0 \Device\HarddiskVolume11\Program Files\Test\myprogram\test2.exe => C:\Program Files\Test\myprogram\test2.exe @error = 0 \Device\HarddiskVolume11\Program Files\Test\myprogram\test3.exe => 19.30355673695959 MS C:\Program Files\Test\myprogram\test3.exe @error = 0 \Device\HarddiskVolume11\Program Files\Test\myprogram\test3.exe => C:\Program Files\Test\myprogram\test3.exe @error = 0 \Device\HarddiskVolume11\Program Files\Test\myprogram\test3.exe => C:\Program Files\Test\myprogram\test3.exe @error = 0 Parsix 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now