Sign in to follow this  
Followers 0
ModemJunki

I built a 2d array of devices from devcon (works but doesn't seem right).

7 posts in this topic

The below code works (requires DevCon / Windows 7) - an array of device ID strings and their names comes - but it doesn't seem right to have to manipulate the drive letter strings in the array to "fix them up" as I have done.

I need a list of all devices from Devcon (including non-present devices). At the end I will check for both present and non-present devices filtered against a list of known devices so I can see which are unplugged from the computer, but first I am building the list of all devices (plugged in or not).

I am doing this workaround because DevCon outputs a list with ":" delimiter and if a filter driver (for some softwares) populates a drive letter they also have ":" in the description. See my comments in the "_RunDevcon" functions for where I do this manipulation.

Is there a better/smarter way to do this?

#include <String.au3>
#include <Constants.au3>
#include <Array.au3>

Global $path_Devcon = @ScriptDir & '\devcon.exe'
Global $aRemovable, $strRun, $foundall

$foundall = _RunDevcon('"' & $path_Devcon & '" findall *'); the findall means we will see "non present devices"
_ArrayDisplay($foundall, "List of devices and their PnP IDs", -1, 0, "", "", "Index|Device String|Device Name")

; Builds a device list using devcon
; by BugFix in 2009 and modified for this script
Func _RunDevcon($strRun)
    Local $data, $dvcn = Run("cmd.exe", @SystemDir, @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD)
    StdinWrite($dvcn, $strRun & @CRLF)
    StdinWrite($dvcn)
    While True
        $data &= StdoutRead($dvcn)
        If @error Then ExitLoop
        Sleep(25)
    WEnd
    Local $split = StringSplit($data, @LF)
    $data = ''

    For $i = 5 To $split[0]
        If StringStripWS($split[$i], 8) == '' Then ExitLoop
        $data &= $split[$i]
        Dim $devices[1][1]
        $devices = StringSplit($data, @CRLF)
    Next

    _ArrayDelete($devices, $devices[0] - 1); because the last line is "<number> matching device(s) found."
    $devices[0] = UBound($devices, 1)

;~ Some hoops to jump because Devcon returns a list of devices with
;~ a ":" in their descriptions and the delimiter between the devices is a ":"!
    $dvstr = _ArrayToString($devices, "'"); split array to string
    $dvstr_fixed = StringReplace($dvstr, ":", "!", 0, 2); replace the colons with something else
    $devarray = _String_Split($dvstr, "'", ":"); put all back into an array

    For $j = 1 To $devarray[0][0] - 1; we remove leading whitespace from second column
        If $devarray[$j][2] = "\" Then; now we fix the drive letters to have a colon again
            $Noblank = StringReplace($devarray[$j][1] & ":" & $devarray[$j][2], " ", "", 1)
            $devarray[$j][1] = $Noblank
        Else
            $Noblank = StringReplace($devarray[$j][1], " ", "", 1)
            $devarray[$j][1] = $Noblank
        EndIf
    Next

    _ArrayDeleteCol($devarray, 2); now we can delete the not-needed column
    _ArrayDelete($devarray, $devarray[0][0] - 1); we ended up with a blank at the end
    $devarray[0][0] = UBound($devarray, 1)

    Return $devarray
EndFunc   ;==>_RunDevcon

;~ Splits a string into an multidimensional array
;~ By wolf9228 in 2009
Func _String_Split($string, $delimiters1, $delimiters2)
    $Array1 = StringSplit($string, $delimiters1)
    Dim $MAXUBound = 0, $OutArray2[1][1]

    For $i = 1 To $Array1[0] Step 1
        $OutArray = StringSplit($Array1[$i], $delimiters2)
        If $MAXUBound < $OutArray[0] Then
            ReDim $OutArray2[$i][$OutArray[0]]
            $MAXUBound = $OutArray[0]
        Else
            ReDim $OutArray2[$i][UBound($OutArray2, 2)]
        EndIf

        For $j = 1 To $OutArray[0] Step 1
            $OutArray2[$i - 1][$j - 1] = $OutArray[$j]
        Next
    Next
    Return $OutArray2
EndFunc   ;==>_String_Split

;~ Deletes column from array
;~ By PsaltyDS in 2008
Func _ArrayDeleteCol(ByRef $avWork, $iCol)
    If Not IsArray($avWork) Then Return SetError(1, 0, 0); Not an array
    If UBound($avWork, 0) <> 2 Then Return SetError(1, 1, 0); Not a 2D array
    If ($iCol < 0) Or ($iCol > (UBound($avWork, 2) - 1)) Then Return SetError(1, 2, 0); $iCol out of range
    If $iCol < UBound($avWork, 2) - 1 Then
        For $c = $iCol To UBound($avWork, 2) - 2
            For $r = 0 To UBound($avWork) - 1
                $avWork[$r][$c] = $avWork[$r][$c + 1]
            Next
        Next
    EndIf
    ReDim $avWork[UBound($avWork)][UBound($avWork, 2) - 1]
    Return 1
EndFunc   ;==>_ArrayDeleteCol

Share this post


Link to post
Share on other sites



ModemJunki,

On my machine one device called "HTREEROOT0" does not have a description. 

The below code works (requires DevCon / Windows 7)

 

Are you sure about that?  Your code returns 2 devices, in fact there are 251 devices.

The output returned uses a ': ' (colon+space) delimiter between the device name and description.  Incidentally, some of the device names also have a colon in them.

Based on that I would do this...

#include <String.au3>
#include <Constants.au3>
#include <Array.au3>
#include <userudfs.au3>

Global $path_Devcon = @ScriptDir & '\devcon.exe'
Global $aRemovable, $strRun, $foundall

$foundall = _RunDevcon('"' & $path_Devcon & '" findall *'); the findall means we will see "non present devices"
_ArrayDisplay($foundall, "List of devices and their PnP IDs", -1, 0, "", "", "Index|Device String|Device Name")

; Builds a device list using devcon
; by BugFix in 2009 and modified for this script

Func _RunDevcon($strRun)
    Local $data, $dvcn = Run("cmd.exe", @SystemDir, @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD)
    StdinWrite($dvcn, $strRun & @CRLF)
    StdinWrite($dvcn)
    While True
        $data &= StdoutRead($dvcn)
        If @error Then ExitLoop
        Sleep(25)
    WEnd

    local $aData = stringregexp($data,'([\V]+\: [\V]+)',3)

    local $aRet[ubound($aData)][2]
    for $1 = 0 to ubound($aData) - 1
        $aRet[$1][0] = stringregexpreplace($aData[$1],'([\V]+)\: [\V]+','$1')
        $aRet[$1][1] = stringregexpreplace($aData[$1],'[\V]+\: ([\V]+)','$1')
    next

    return $aRet

EndFunc

kylomas


Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Thank you kylomas, that is a much better implementation. I will have to find time to study regex now. http://xkcd.com/1171/

On my system the original returned the same number of devices as devcon (in a cmd box) did.

Edited by ModemJunki

Share this post


Link to post
Share on other sites

ModemJunki,

On my system the original returned the same number of devices as devcon (in a cmd box) did

 

The problem is in the  _arraydisplay.  When I comment out allof the parameters I get all of the data.  I never use the parms so have no idea why I am getting abbreviated output (2 items) with them.

SRE Explanation:

local $aData = stringregexp($data,'([V]+: [V]+)',3)
 

(             - start capture group

[V]          - capture all non vertical whitespace chars (everything except line feed, form feed vertical tab and carrige return)

+             - repeat the previous group/class 1 or more times up to...

:            - the first colon followed by a space ("" = escape special chars)

                This effectively eliminates any lines not having a ": " sequence.

[V]+         - as before, capture all the rest of the string

)             - end capture group

,3            - store each captured group in an array

$aRet[$1][0] = stringregexpreplace($aData[$1],'([V]+): [V]+','$1')

([V]+)       - capture all non-vertical whitespace characters up to..

:            - a colon followed by a space

[V]+         - continue matching till end of string

,'$1'         - replace the matched string with the capture group

$aRet[$1][0]  - write the replacement to column 0 of row $1

$aRet[$1][1] = stringregexpreplace($aData[$1],'[V]+: ([V]+)','$1')

[V]+         - match all non-vertical whitespace characters up to..

:            - a colon followed by a space

([V]+)       - cature everything after the colon+space sequence

,'$1'         - replace the matched string with the capture group

$aRet[$1][1]  - write the replacement to column 1 of row $1

kylomas


Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

Interesting - on my system there are two items with no description. These get omitted from the final array with the regexed script. :-(

HTREEROOT0
HIDVID_046D&PID_C52B&MI_02&COL038&F5A49A3&0&0002

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Interesting - on my system there are two items with no description. These get omitted from the final array with the regexed script. :-(

HTREEROOT0

HIDVID_046D&PID_C52B&MI_02&COL038&F5A49A3&0&0002

 

Is that a problem?

edit: if it is then this will get the entries with no description.

#include <String.au3>
#include <Constants.au3>
#include <Array.au3>

Global $path_Devcon = @ScriptDir & '\devcon.exe'
Global $aRemovable, $strRun, $foundall

$foundall = _RunDevcon('"' & $path_Devcon & '" findall *'); the findall means we will see "non present devices"
_ArrayDisplay($foundall, "List of devices and their PnP IDs", -1, 0, "", "", "Index|Device String|Device Name")

; Builds a device list using devcon
; by BugFix in 2009 and modified for this script

Func _RunDevcon($strRun)
    Local $data, $dvcn = Run("cmd.exe", @SystemDir, @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD)
    StdinWrite($dvcn, $strRun & @CRLF)
    StdinWrite($dvcn)
    While True
        $data &= StdoutRead($dvcn)
        If @error Then ExitLoop
        Sleep(25)
    WEnd

    local $aData = stringsplit($data,@crlf,3)

    local $aRet[ubound($aData)-7][2]
    for $1 = 4 to ubound($aData) - 4
        if stringregexp($adata[$1],'\: ') then
            $aRet[$1-4][0] = stringregexpreplace($aData[$1],'([\V]+)\: [\V]+','$1')
            $aRet[$1-4][1] = stringregexpreplace($aData[$1],'[\V]+\: ([\V]+)','$1')
        Else
            $aret[$1-4][0] = $adata[$1]
        endif
    next

    return $aRet

EndFunc
Edited by kylomas

Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

and in a listview control...

; *** Start added by AutoIt3Wrapper ***
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
; *** End added by AutoIt3Wrapper ***
#include <String.au3>
#include <Constants.au3>
#include <Array.au3>
#include <GuiListView.au3>

Global $path_Devcon = @ScriptDir & '\devcon.exe'

$foundall = _RunDevcon('"' & $path_Devcon & '" findall *'); the findall means we will see "non present devices"
;_ArrayDisplay($foundall, "List of devices and their PnP IDs", -1, 0, "", "", "Index|Device String|Device Name")

#AutoIt3Wrapper_Add_Constants=n

local $gui010   =   guicreate('DevCon List',1000,700)
local $aSize    =   wingetclientsize($gui010)
local $lst010   =   guictrlcreatelistview('Device|Description',0,20,$aSize[0],550)
                    guictrlsetbkcolor(-1,$GUI_BKCOLOR_LV_ALTERNATE)

for $1 = 0 to ubound($foundall) - 1
    GUICtrlCreateListViewItem($foundall[$1][0] & '|' & $foundall[$1][1],$lst010)
    guictrlsetbkcolor(-1,0xc0f0c0)
next

for $1= 0 to _GUICtrlListView_GetColumnCount($lst010)
    _GUICtrlListView_SetColumnWidth( $lst010, $1, ($aSize[0]/ _GUICtrlListView_GetColumnCount($lst010)-8) )
next

guisetstate()

while 1
    switch guigetmsg()
        case $gui_event_close
            Exit
    EndSwitch
WEnd

; Builds a device list using devcon
; by BugFix in 2009 and modified for this script

Func _RunDevcon($strRun)
    Local $data, $dvcn = Run("cmd.exe", @SystemDir, @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD)
    StdinWrite($dvcn, $strRun & @CRLF)
    StdinWrite($dvcn)
    While True
        $data &= StdoutRead($dvcn)
        If @error Then ExitLoop
        Sleep(25)
    WEnd

    local $aData = stringsplit($data,@crlf,3)

    local $aRet[ubound($aData)-7][2]
    for $1 = 4 to ubound($aData) - 4
        if stringregexp($adata[$1],'\: ') then
            $aRet[$1-4][0] = stringregexpreplace($aData[$1],'([\V]+)\: [\V]+','$1')
            $aRet[$1-4][1] = stringregexpreplace($aData[$1],'[\V]+\: ([\V]+)','$1')
        Else
            $aret[$1-4][0] = $adata[$1]
        endif
    next

    return $aRet

EndFunc

Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

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
Sign in to follow this  
Followers 0

  • Similar Content

    • logmein
      By logmein
      Hi,
      I'm trying to develope a program to safely eject an USB device. I have tried a lot of way but there was no satisfactory result. I used to consult wraithdu's script here : but that script wasn't work on my Win7 machine, then I heard someone talk about Devcon, then I started to explore it, I have scripted, tested for days and get nothing but errors. I used this command : devcon remove @usb\* to remove all removable devices but here the result goes :



      All failed? I have just plugged on two USB Kingmax and Transcend!

      I need some professional guys to solve the problem:D Thanks!