Bilgus

multiple calls DosDevicePath to FilePath

2 posts in this topic

#1 ·  Posted (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

#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 by Bilgus

Share this post


Link to post
Share on other sites

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

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

 

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.


Sign In Now