Jump to content

Recommended Posts

Posted (edited)

Adding If @OSVersion = "WIN_7" Then Return WinGetTitle($hWnd,"") below that line gets me the window title of the explorer window, it doesn't return the path like I want it to. Any luck getting the path like it does in XP?

Thanks

Edit:

After thinking about this some more, I have something that will work. *Note: I haven't tested on Vista yet, only 7.

;;;This is the code that would go in your code, does the string analysis to get the path
for $i = 1 to $var[0][0]
    If @OSVersion = "WIN_7" Then
        $string = _GetWindowsExplorerPath($var[$i][1])
        $string = StringReplace($string, "Address: ", "")
        $string = StringSplit($string, @CRLF)
        MsgBox(0,"", $string[1])
    ElseIf @OSVersion = "WIN_VISTA" Then
        $string = _GetWindowsExplorerPath($var[$i][1])
        $string = StringReplace($string, "Address: ", "")
        $string = StringSplit($string, @CRLF)
        MsgBox(0,"", $string[1])
    Else
        MsgBox (0, "", _GetWindowsExplorerPath($var[$i][1]))
    EndIf
Next

;;This gets added to the function
;;It goes below this line:
;;If ($className[2] <> "ExploreWClass" And $className[2] <> "CabinetWClass") Then Return SetError(1, 0, "")

If @OSVersion = "WIN_7" Then Return WinGetText($hWnd,"")
If @OSVersion = "WIN_Vista" Then Return WinGetText($hWnd,"")

Hopefully there's a less messy solution out there, but for now this seems like it could work.

Edited by cvocvo
  • 5 months later...
Posted

[...]

Hopefully there's a less messy solution out there, but for now this seems like it could work.

I am wondering why _GetWindowsExplorerPath could not be realized using Shell.Application:

$SHA= ObjCreate("Shell.Application")
  $SHW= $SHA.Windows()
  
  while 1
    for $WIN in $SHW
      if $WIN.hwnd = $w then exitloop 2
    next
    return ""
  wend
  
  $n= $WIN.document.SelectedItems.Count
  
  $SEL= $WIN.document.SelectedItems
  $s= $WIN.LocationURL & ","
  for $ITM in $SEL
    $s &= $ITM.path & ","
  next

Works for me on XP/SP3. Any drawbacks or caveats known for this?

--Klaus

Posted (edited)

Works fine on Win7 64bit too :x...

#cs ----------------------------------------------------------------------------
    AutoIt Version: 3.3.6.1
    Authors:        klaus.s, KaFu
    Script Function: Enum selected files in existing Explorer Windows
#ce ----------------------------------------------------------------------------

#include <Array.au3>
#include <WinApi.au3>
#include <WindowsConstants.au3>

$oShellApp = ObjCreate("Shell.Application")
$oShellApp_Windows = $oShellApp.Windows()

$aWinList = WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")

For $i = 1 To UBound($aWinList) - 1
    $aSelection = _ExplorerSelectedFiles($aWinList[$i][1])
    _ArrayDisplay($aSelection, "Explorer Instance #" & $i & " / " & WinGetTitle($aWinList[$i][1]))
Next

Func _ExplorerSelectedFiles($hWnd)

    If Not IsHWnd($hWnd) Then Return SetError(1)
    If Not IsObj($oShellApp) Then Return SetError(2) ; could not create Object

    Local $aExplorerSelectedFiles[2] = [0, ""]

    For $oShellApp_Inst In $oShellApp_Windows
        If $oShellApp_Inst.hwnd = $hWnd Then ExitLoop
    Next

    Local $oShellApp_Inst_SelectedItems_Count = $oShellApp_Inst.document.SelectedItems.Count
    Local $oShellApp_Inst_LocationURL = $oShellApp_Inst.LocationURL

    $aExplorerSelectedFiles[0] = $oShellApp_Inst_SelectedItems_Count
    $aExplorerSelectedFiles[1] = $oShellApp_Inst_LocationURL
    ReDim $aExplorerSelectedFiles[$aExplorerSelectedFiles[0] + 2]
    $oShellApp_Inst_SelectedItems = $oShellApp_Inst.document.SelectedItems
    $oShellApp_Inst_LocationURL = $oShellApp_Inst.LocationURL & ","
    Local $iCounter = 2
    For $oShellApp_Inst_SelectedItem In $oShellApp_Inst_SelectedItems
        $aExplorerSelectedFiles[$iCounter] = $oShellApp_Inst_SelectedItem.path
        $iCounter += 1
    Next

    Return $aExplorerSelectedFiles
EndFunc   ;==>_ExplorerSelectedFiles
Edited by KaFu
Posted

Very nice, klaus!

Btw, KaFu - don't over-complicate things lol.

All you need to get the open Explorer windows is one line:

$aWinList=WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")
Posted (edited)

Since the 'LocationURL' string returns values like:

'file:///C:/%5BABracketedFolder%5B'

I wrote the following simple function to decode the string into a usable path. If you know of a better way, let me know:

; ===================================================================================================================
; Func _URLFilePathDecode($sURL)
;
; Function to decode a URL-encoded filepath (one in which there are '%xx' values, '/'s,
;   and a possible 'file:///' prefix.
;
; Example: file:///C:/%5BABracketedFolder%5B
;   becomes: C:\[ABracketedFolder]
;
; Returns: String stripped of URL encoded data
;
; Author: Ascend4nt
; ===================================================================================================================

Func _URLFilePathDecode($sURL)
    Local $aHexCodes,$sFilePath=$sURL
    ; Grab all the '%xx' values into an array so that we can replace them in left-to-right order
    $aHexCodes=StringRegExp($sURL,'%([[:xdigit:]]{2})',3)
    If Not @error Then
        ; Change all the '%xx' values into ';'s (invalid path character)
        $sFilePath=StringRegExpReplace($sURL,'%([[:xdigit:]]{2})',';')
        ; Then go through 1 by 1 and replace each ';' in left-to-right order (same as array order)
        For $i=0 To UBound($aHexCodes)-1
            $sFilePath=StringReplace($sFilePath,';',ChrW('0x'&$aHexCodes[$i]),1)    ; only the 1st occurrence for each rep!
        Next
    EndIf
    $sFilePath=StringReplace($sFilePath,'file:///','')
    $sFilePath=StringReplace($sFilePath,'/','\')
    Return $sFilePath
EndFunc

*edit - Revised function to work correctly in case there are '%xx's in the resultant path

Edited by Ascend4nt
Posted (edited)

Nice :x, and here's it all glued together.

#include <Array.au3>

$aWinList = WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")
For $i = 1 To UBound($aWinList) - 1
    $aSelection = _WindowsExplorer_ExtractSelectedDirAndFiles($aWinList[$i][1])
    _ArrayDisplay($aSelection, "Explorer Instance #" & $i & " / " & WinGetTitle($aWinList[$i][1]))
Next

; ===================================================================================================================
; Name...........: _WindowsExplorer_ExtractSelectedDirAndFiles
; Description....: Function to extract LocationURL and selected files from a "Windows Explorer" Window
; Syntax.........: _WindowsExplorer_ExtractSelectedDirAndFiles($hWnd)
; Parameters.....: $hWnd - Windows handle of an "Windows Explorer" Window
; AutoIt Version.: 3.3.6.1
; Return values..: Success  -   Array
;                               Array[0] = Number of files selected in right-hand Listview
;                               Array[1] = LocationURL - selected in left-hand Treeview or Window Rebar
;                               Array[2] - Array[n] = URL of selected files in right-hand Listview
;                  Failure  -   Array
;                               Array[0] = 0
;                               Array[1] = ""
;                               Sets the @error flag to non-zero.
;                               @error = 1 - $hwnd is not a valid window handle
;                               @error = 2 - $hwnd is not a window handle for an "Windows Explorer" Window
;                               @error = 3 - "Shell.Application" object could not be created
;                               @error = 4 - "$oShellApp.Windows()" object could not be created
; Author.........: Ascend4nt, KaFu, klaus.s
; ===================================================================================================================

Func _WindowsExplorer_ExtractSelectedDirAndFiles($hWnd)
    Local $aExplorerSelectedFiles[2] = [0, ""]
    If Not IsHWnd($hWnd) Then Return SetError(1, 0, $aExplorerSelectedFiles)
    Local $aWinList = WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")
    While 1
        For $i = 1 To UBound($aWinList) - 1
            If $hWnd = $aWinList[$i][1] Then ExitLoop 2
        Next
        Return SetError(2, 0, $aExplorerSelectedFiles)
    WEnd
    Local $oShellApp = ObjCreate("Shell.Application")
    If Not IsObj($oShellApp) Then Return SetError(3, 0, $aExplorerSelectedFiles)
    Local $oShellApp_Windows = $oShellApp.Windows()
    If Not IsObj($oShellApp_Windows) Then Return SetError(4, 0, $aExplorerSelectedFiles)
    For $oShellApp_Inst In $oShellApp_Windows
        If $oShellApp_Inst.hwnd = $hWnd Then ExitLoop
    Next
    Local $oShellApp_Inst_SelectedItems_Count = $oShellApp_Inst.document.SelectedItems.Count
    Local $oShellApp_Inst_LocationURL = $oShellApp_Inst.LocationURL
    Local $aHexCodes = StringRegExp($oShellApp_Inst_LocationURL, '%([[:xdigit:]]{2})', 3)
    If Not @error Then
        ; Change all the '%xx' values into ';'s (invalid path character)
        $oShellApp_Inst_LocationURL = StringRegExpReplace($oShellApp_Inst_LocationURL, '%([[:xdigit:]]{2})', ';')
        ; Then go through 1 by 1 and replace each ';' in left-to-right order (same as array order)
        For $i = 0 To UBound($aHexCodes) - 1
            $oShellApp_Inst_LocationURL = StringReplace($oShellApp_Inst_LocationURL, ';', ChrW('0x' & $aHexCodes[$i]), 1) ; only the 1st occurrence for each rep!
        Next
    EndIf
    $oShellApp_Inst_LocationURL = StringReplace($oShellApp_Inst_LocationURL, 'file:///', '')
    $aExplorerSelectedFiles[0] = $oShellApp_Inst_SelectedItems_Count
    $aExplorerSelectedFiles[1] = StringReplace($oShellApp_Inst_LocationURL, '/', '\')
    ReDim $aExplorerSelectedFiles[$aExplorerSelectedFiles[0] + 2]
    $oShellApp_Inst_SelectedItems = $oShellApp_Inst.document.SelectedItems
    Local $iCounter = 2
    For $oShellApp_Inst_SelectedItem In $oShellApp_Inst_SelectedItems
        $aExplorerSelectedFiles[$iCounter] = $oShellApp_Inst_SelectedItem.path
        $iCounter += 1
    Next
    $oShellApp = 0
    $oShellApp_Windows = 0
    Return $aExplorerSelectedFiles
EndFunc   ;==>_WindowsExplorer_ExtractSelectedDirAndFiles
Edited by KaFu
  • 1 month later...
Posted

Hey, an even better way than my PCRE method is a simple API function I just came across today:

$aRet=DllCall('shlwapi.dll','long','PathCreateFromUrlW','wstr',$sURL,'wstr','','dword*',65534,'dword',0)
    If Not @error And $aRet[0]=0 Then $sURL=$aRet[2]

$sURL there is just a simpler name (KaFu uses '$oShellApp_Inst_LocationURL' - don't ask me why an $o prefix was given to a string).

Posted (edited)

Hey, an even better way than my PCRE method is a simple API function I just came across today:

Nice find :)...

(KaFu uses '$oShellApp_Inst_LocationURL' - don't ask me why an $o prefix was given to a string)

Because nobody really reviewed the snippet I posted :) ?

#include <Array.au3>

$aWinList = WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")
For $i = 1 To UBound($aWinList) - 1
    $aSelection = _WindowsExplorer_ExtractSelectedDirAndFiles($aWinList[$i][1])
    _ArrayDisplay($aSelection, "Explorer Instance #" & $i & " / " & WinGetTitle($aWinList[$i][1]))
Next

; ===================================================================================================================
; Name...........: _WindowsExplorer_ExtractSelectedDirAndFiles
; Description....: Function to extract LocationURL and selected files from a "Windows Explorer" Window
; Syntax.........: _WindowsExplorer_ExtractSelectedDirAndFiles($hWnd)
; Parameters.....: $hWnd - Windows handle of an "Windows Explorer" Window
; AutoIt Version.: 3.3.6.1
; Return values..: Success  -   Array
;                               Array[0] = Number of files selected in right-hand Listview
;                               Array[1] = LocationURL - selected in left-hand Treeview or Window Rebar
;                               Array[2] - Array[n] = URL of selected files in right-hand Listview
;                  Failure  -   Array
;                               Array[0] = 0
;                               Array[1] = ""
;                               Sets the @error flag to non-zero.
;                               @error = 1 - $hwnd is not a valid window handle
;                               @error = 2 - $hwnd is not a window handle for an "Windows Explorer" Window
;                               @error = 3 - "Shell.Application" object could not be created
;                               @error = 4 - "$oShellApp.Windows()" object could not be created
; Author.........: Ascend4nt, KaFu, klaus.s
; ===================================================================================================================

Func _WindowsExplorer_ExtractSelectedDirAndFiles($hWnd)
    Local $aExplorerSelectedFiles[2] = [0, ""]
    If Not IsHWnd($hWnd) Then Return SetError(1, 0, $aExplorerSelectedFiles)
    Local $aWinList = WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")
    While 1
        For $i = 1 To UBound($aWinList) - 1
            If $hWnd = $aWinList[$i][1] Then ExitLoop 2
        Next
        Return SetError(2, 0, $aExplorerSelectedFiles)
    WEnd
    Local $oShellApp = ObjCreate("Shell.Application")
    If Not IsObj($oShellApp) Then Return SetError(3, 0, $aExplorerSelectedFiles)
    Local $oShellApp_Windows = $oShellApp.Windows()
    If Not IsObj($oShellApp_Windows) Then Return SetError(4, 0, $aExplorerSelectedFiles)
    For $oShellApp_Inst In $oShellApp_Windows
        If $oShellApp_Inst.hwnd = $hWnd Then ExitLoop
    Next
    Local $iShellApp_Inst_SelectedItems_Count = $oShellApp_Inst.document.SelectedItems.Count
    Local $sShellApp_Inst_LocationURL = $oShellApp_Inst.LocationURL
    Local $aRet = DllCall('shlwapi.dll', 'long', 'PathCreateFromUrlW', 'wstr', $sShellApp_Inst_LocationURL, 'wstr', '', 'dword*', 65534, 'dword', 0)
    If Not @error And $aRet[0] = 0 Then $sShellApp_Inst_LocationURL = $aRet[2]
    $aExplorerSelectedFiles[0] = $iShellApp_Inst_SelectedItems_Count
    $aExplorerSelectedFiles[1] = $sShellApp_Inst_LocationURL
    ReDim $aExplorerSelectedFiles[$aExplorerSelectedFiles[0] + 2]
    $oShellApp_Inst_SelectedItems = $oShellApp_Inst.document.SelectedItems
    Local $iCounter = 2
    For $oShellApp_Inst_SelectedItem In $oShellApp_Inst_SelectedItems
        $aExplorerSelectedFiles[$iCounter] = $oShellApp_Inst_SelectedItem.path
        $iCounter += 1
    Next
    $oShellApp = 0
    $oShellApp_Windows = 0
    $oShellApp_Inst = 0
    $oShellApp_Inst_SelectedItems = 0
    $oShellApp_Inst_SelectedItem = 0
    Return $aExplorerSelectedFiles
EndFunc   ;==>_WindowsExplorer_ExtractSelectedDirAndFiles
Edited by KaFu
Posted (edited)

Because nobody really reviewed the snippet I posted :) ?

#include <Array.au3>

$aWinList = WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")
For $i = 1 To UBound($aWinList) - 1
    $aSelection = _WindowsExplorer_ExtractSelectedDirAndFiles($aWinList[$i][1])
    _ArrayDisplay($aSelection, "Explorer Instance #" & $i & " / " & WinGetTitle($aWinList[$i][1]))
Next

; ===================================================================================================================
; Name...........: _WindowsExplorer_ExtractSelectedDirAndFiles
; Description....: Function to extract LocationURL and selected files from a "Windows Explorer" Window
; Syntax.........: _WindowsExplorer_ExtractSelectedDirAndFiles($hWnd)
; Parameters.....: $hWnd - Windows handle of an "Windows Explorer" Window
; AutoIt Version.: 3.3.6.1
; Return values..: Success  -   Array
;                               Array[0] = Number of files selected in right-hand Listview
;                               Array[1] = LocationURL - selected in left-hand Treeview or Window Rebar
;                               Array[2] - Array[n] = URL of selected files in right-hand Listview
;                  Failure  -   Array
;                               Array[0] = 0
;                               Array[1] = ""
;                               Sets the @error flag to non-zero.
;                               @error = 1 - $hwnd is not a valid window handle
;                               @error = 2 - $hwnd is not a window handle for an "Windows Explorer" Window
;                               @error = 3 - "Shell.Application" object could not be created
;                               @error = 4 - "$oShellApp.Windows()" object could not be created
; Author.........: Ascend4nt, KaFu, klaus.s
; ===================================================================================================================

Func _WindowsExplorer_ExtractSelectedDirAndFiles($hWnd)
    Local $aExplorerSelectedFiles[2] = [0, ""]
    If Not IsHWnd($hWnd) Then Return SetError(1, 0, $aExplorerSelectedFiles)
    Local $aWinList = WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")
    While 1
        For $i = 1 To UBound($aWinList) - 1
            If $hWnd = $aWinList[$i][1] Then ExitLoop 2
        Next
        Return SetError(2, 0, $aExplorerSelectedFiles)
    WEnd
    Local $oShellApp = ObjCreate("Shell.Application")
    If Not IsObj($oShellApp) Then Return SetError(3, 0, $aExplorerSelectedFiles)
    Local $oShellApp_Windows = $oShellApp.Windows()
    If Not IsObj($oShellApp_Windows) Then Return SetError(4, 0, $aExplorerSelectedFiles)
    For $oShellApp_Inst In $oShellApp_Windows
        If $oShellApp_Inst.hwnd = $hWnd Then ExitLoop
    Next
    Local $iShellApp_Inst_SelectedItems_Count = $oShellApp_Inst.document.SelectedItems.Count
    Local $sShellApp_Inst_LocationURL = $oShellApp_Inst.LocationURL
    Local $aRet = DllCall('shlwapi.dll', 'long', 'PathCreateFromUrlW', 'wstr', $sShellApp_Inst_LocationURL, 'wstr', '', 'dword*', 65534, 'dword', 0)
    If Not @error And $aRet[0] = 0 Then $sShellApp_Inst_LocationURL = $aRet[2]
    $aExplorerSelectedFiles[0] = $iShellApp_Inst_SelectedItems_Count
    $aExplorerSelectedFiles[1] = $sShellApp_Inst_LocationURL
    ReDim $aExplorerSelectedFiles[$aExplorerSelectedFiles[0] + 2]
    $oShellApp_Inst_SelectedItems = $oShellApp_Inst.document.SelectedItems
    Local $iCounter = 2
    For $oShellApp_Inst_SelectedItem In $oShellApp_Inst_SelectedItems
        $aExplorerSelectedFiles[$iCounter] = $oShellApp_Inst_SelectedItem.path
        $iCounter += 1
    Next
    $oShellApp = 0
    $oShellApp_Windows = 0
    $oShellApp_Inst = 0
    $oShellApp_Inst_SelectedItems = 0
    $oShellApp_Inst_SelectedItem = 0
    Return $aExplorerSelectedFiles
EndFunc   ;==>_WindowsExplorer_ExtractSelectedDirAndFiles

May I do that now?

Ok.

Why do you forcibly release those objects. You don't have to do that since they are local.

You miss proper COM error handling for that function because you reference different objects on the fly counting on error free situation.

Both issues are closely related and can be seen in e.g. this part of the code:

$oShellApp_Inst.document.SelectedItems.Count

How many objects do you see and create and reference there?

Let's see...

  • $oShellApp_Inst - did you check that $oShellApp_Inst is actually object before trying to access it
  • $oShellApp_Inst.Document - new object is created. Did you check if it's created? This one is local (flyable too). See, it's released when it gets out of scope (at the end of the line), you don't have to do anything.
  • $oShellApp_Inst.document.SelectedItems - new object is created. But from what? From something that may not be an object. Same remarks as above are here too.
  • $oShellApp_Inst.document.SelectedItems.Count - accessing some property that may not exist for any of the reasons of some object that may not be.
This is not the way to write good and safe code in AutoIt.

Corrected (to some degree and for this particular case) regarding what I just wrote, would be:

Func _WindowsExplorer_ExtractSelectedDirAndFiles($hWnd, $oError = 0)
    Local $aExplorerSelectedFiles[2] = [0, ""]
    If Not IsHWnd($hWnd) Then Return SetError(1, 0, $aExplorerSelectedFiles)
    Local $aWinList = WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")
    While 1
        For $i = 1 To UBound($aWinList) - 1
            If $hWnd = $aWinList[$i][1] Then ExitLoop 2
        Next
        Return SetError(2, 0, $aExplorerSelectedFiles)
    WEnd
    If Not IsObj($oError) And Not ObjEvent("AutoIt.Error") Then $oError = ObjEvent("AutoIt.Error", "_WindowsExplorer_ExtractSelectedDirAndFiles")
    Local $fErrorHandling = False
    If IsObj($oError) Then $fErrorHandling = True
    Local $oShellApp = ObjCreate("Shell.Application")
    If Not IsObj($oShellApp) Then Return SetError(3, 0, $aExplorerSelectedFiles)
    Local $oShellApp_Windows = $oShellApp.Windows()
    If Not IsObj($oShellApp_Windows) Then Return SetError(4, 0, $aExplorerSelectedFiles)
    For $oShellApp_Inst In $oShellApp_Windows
        If $oShellApp_Inst.hwnd = $hWnd Then ExitLoop
    Next
    Local $iShellApp_Inst_SelectedItems_Count = $oShellApp_Inst.document.SelectedItems.Count
    If $fErrorHandling And $oError.number Then Return SetError(5, 0, $aExplorerSelectedFiles)
    Local $sShellApp_Inst_LocationURL = $oShellApp_Inst.LocationURL
    Local $aRet = DllCall('shlwapi.dll', 'long', 'PathCreateFromUrlW', 'wstr', $sShellApp_Inst_LocationURL, 'wstr', '', 'dword*', 65534, 'dword', 0)
    If Not @error And $aRet[0] = 0 Then $sShellApp_Inst_LocationURL = $aRet[2]
    $aExplorerSelectedFiles[0] = $iShellApp_Inst_SelectedItems_Count
    $aExplorerSelectedFiles[1] = $sShellApp_Inst_LocationURL
    ReDim $aExplorerSelectedFiles[$aExplorerSelectedFiles[0] + 2]
    $oShellApp_Inst_SelectedItems = $oShellApp_Inst.document.SelectedItems
    If $fErrorHandling And $oError.number Then Return SetError(6, 0, $aExplorerSelectedFiles)
    Local $iCounter = 2
    For $oShellApp_Inst_SelectedItem In $oShellApp_Inst_SelectedItems
        $aExplorerSelectedFiles[$iCounter] = $oShellApp_Inst_SelectedItem.path
        $iCounter += 1
    Next
    Return $aExplorerSelectedFiles
EndFunc

This happens because no one showed the proper way, likely including me now.

Edited by trancexx
Posted

May I do that now?

Of course you may do, nice :). Freeing the Objects (and vars) was quite an overkill, but I was not sure if local objects are automatically released.

Do I get it right and you reference an error back to the function with this line

$oError = ObjEvent("AutoIt.Error", "_WindowsExplorer_ExtractSelectedDirAndFiles")

, letting the function handle the error, and in this case just silently drop it?

Posted

Of course you may do, nice :). Freeing the Objects (and vars) was quite an overkill, but I was not sure if local objects are automatically released.

Do I get it right and you reference an error back to the function with this line

$oError = ObjEvent("AutoIt.Error", "_WindowsExplorer_ExtractSelectedDirAndFiles")

, letting the function handle the error, and in this case just silently drop it?

Yes, it's only because it has convenient intro. Some dummy function would be required otherwise.
  • 2 months later...
Posted

May I do that now?

Ok.

Why do you forcibly release those objects. You don't have to do that since they are local.

You miss proper COM error handling for that function because you reference different objects on the fly counting on error free situation.

Both issues are closely related and can be seen in e.g. this part of the code:

$oShellApp_Inst.Document.SelectedItems.Count

How many objects do you see and create and reference there?

Let's see...

  • $oShellApp_Inst - did you check that $oShellApp_Inst is actually object before trying to access it
  • $oShellApp_Inst.Document - new object is created. Did you check if it's created? This one is local (flyable too). See, it's released when it gets out of scope (at the end of the line), you don't have to do anything.
  • $oShellApp_Inst.document.SelectedItems - new object is created. But from what? From something that may not be an object. Same remarks as above are here too.
  • $oShellApp_Inst.document.SelectedItems.Count - accessing some property that may not exist for any of the reasons of some object that may not be.
This is not the way to write good and safe code in AutoIt.

Corrected (to some degree and for this particular case) regarding what I just wrote, would be:

Func _WindowsExplorer_ExtractSelectedDirAndFiles($hWnd, $oError = 0)
    Local $aExplorerSelectedFiles[2] = [0, ""]
    If Not IsHWnd($hWnd) Then Return SetError(1, 0, $aExplorerSelectedFiles)
    Local $aWinList = WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")
    While 1
        For $i = 1 To UBound($aWinList) - 1
            If $hWnd = $aWinList[$i][1] Then ExitLoop 2
        Next
        Return SetError(2, 0, $aExplorerSelectedFiles)
    WEnd
    If Not IsObj($oError) And Not ObjEvent("AutoIt.Error") Then $oError = ObjEvent("AutoIt.Error", "_WindowsExplorer_ExtractSelectedDirAndFiles")
    Local $fErrorHandling = False
    If IsObj($oError) Then $fErrorHandling = True
    Local $oShellApp = ObjCreate("Shell.Application")
    If Not IsObj($oShellApp) Then Return SetError(3, 0, $aExplorerSelectedFiles)
    Local $oShellApp_Windows = $oShellApp.Windows()
    If Not IsObj($oShellApp_Windows) Then Return SetError(4, 0, $aExplorerSelectedFiles)
    For $oShellApp_Inst In $oShellApp_Windows
        If $oShellApp_Inst.hwnd = $hWnd Then ExitLoop
    Next
    Local $iShellApp_Inst_SelectedItems_Count = $oShellApp_Inst.Document.SelectedItems.Count
    If $fErrorHandling And $oError.number Then Return SetError(5, 0, $aExplorerSelectedFiles)
    Local $sShellApp_Inst_LocationURL = $oShellApp_Inst.LocationURL
    Local $aRet = DllCall('shlwapi.dll', 'long', 'PathCreateFromUrlW', 'wstr', $sShellApp_Inst_LocationURL, 'wstr', '', 'dword*', 65534, 'dword', 0)
    If Not @error And $aRet[0] = 0 Then $sShellApp_Inst_LocationURL = $aRet[2]
    $aExplorerSelectedFiles[0] = $iShellApp_Inst_SelectedItems_Count
    $aExplorerSelectedFiles[1] = $sShellApp_Inst_LocationURL
    ReDim $aExplorerSelectedFiles[$aExplorerSelectedFiles[0] + 2]
    $oShellApp_Inst_SelectedItems = $oShellApp_Inst.Document.SelectedItems
    If $fErrorHandling And $oError.number Then Return SetError(6, 0, $aExplorerSelectedFiles)
    Local $iCounter = 2
    For $oShellApp_Inst_SelectedItem In $oShellApp_Inst_SelectedItems
        $aExplorerSelectedFiles[$iCounter] = $oShellApp_Inst_SelectedItem.path
        $iCounter += 1
    Next
    Return $aExplorerSelectedFiles
EndFunc

This happens because no one showed the proper way, likely including me now.

Good, but don't work for Desktop. :unsure:
Automatic Update UDF - IP Address UDF - WinPcap AutoIt _FindDevice()[font="Verdana"][size="2"]AutoIt Spanish/Brasil/World community!!![/size][/font]Use you wanna a dot.tk domain please use my link:
Posted

Good, but don't work for Desktop. :unsure:

To get a handle to the Desktop is a slightly different problem, especially on Vista+. See a good method for getting that handle in this thread:

  • 4 months later...
Posted (edited)

After toying around with Shell objects and the like, I've shortened the code even more. Note that you'll need to add code for an AutoIt COM error handler. I removed that because it shouldn't be part of a UDF function in my opinion.

Also, with separating out the code to get the 'ShellFolderView' object, its possible to do other things like selecting, focusing, and other Shell object operations.

; ==========================================================================================================================
 
; Func _ObjectSHFolderViewFromWin($hWnd)
;
; Returns an 'ShellFolderView' Object for the given Window handle
;
; Author: Ascend4nt, based on code by KaFu, klaus.s
; ==========================================================================================================================
 
Func _ObjectSHFolderViewFromWin($hWnd)
    If Not IsHWnd($hWnd) Then Return SetError(1,0,0)
    Local $oShell,$oShellWindows,$oIEObject,$oSHFolderView
 
    ; Shell Object
    $oShell=ObjCreate("Shell.Application")
    If Not IsObj($oShell) Then Return SetError(2,0,0)
 
;   Get a 'ShellWindows Collection' object
    $oShellWindows = $oShell.Windows()
    If Not IsObj($oShellWindows) Then Return SetError(3,0,0)
 
;   Iterate through the collection - each of type 'InternetExplorer' Object
 
    For $oIEObject In $oShellWindows
        If $oIEObject.HWND = $hWnd Then
            ; InternetExplorer->Document = ShellFolderView object
            $oSHFolderView=$oIEObject.Document
            If IsObj($oSHFolderView) Then Return $oSHFolderView
            Return SetError(4,0,0)
        EndIf
    Next
 
    Return SetError(-1,0,0)
EndFunc
 
; ==========================================================================================================================
; Func _ExplorerWinGetSelectedItems($hWnd)
;
;
; Author: klaus.s, KaFu, Ascend4nt (consolidation & cleanup, Path name simplification)
; ==========================================================================================================================
 
Func _ExplorerWinGetSelectedItems($hWnd)
    If Not IsHWnd($hWnd) Then Return SetError(1,0,'')
    Local $oSHFolderView
    Local $iSelectedItems,$iCounter=2,$aSelectedItems[2] = [0, ""]
 
    $oSHFolderView=_ObjectSHFolderViewFromWin($hWnd)
    If @error Then Return SetError(@error,0,'')
 
;   SelectedItems = FolderItems Collection object->Count
    $iSelectedItems = $oSHFolderView.SelectedItems.Count
 
    Dim $aSelectedItems[$iSelectedItems+2]  ; 2 extra -> 1 for count [0], 1 for Folder path [1]
 
    $aSelectedItems[0]=$iSelectedItems
;   ShellFolderView->Folder->Self as 'FolderItem'->Path
    $aSelectedItems[1]=$oSHFolderView.Folder.Self.Path
 
;   ShellFolderView->SelectedItems = FolderItems Collection object
    $oSelectedFolderItems = $oSHFolderView.SelectedItems
 
#cs
    ; For ALL items in an Explorer window (not just the selected ones):
    $oSelectedFolderItems = $oSHFolderView.Folder.Items
    ReDim $aSelectedItems[$oSelectedFolderItems.Count+2]
#ce
 
    For $oFolderItem In $oSelectedFolderItems
        $aSelectedItems[$iCounter] = $oFolderItem.Path
        $iCounter += 1
    Next
 
    Return SetExtended($iCounter-2,$aSelectedItems)
EndFunc   ;==>_ExplorerWinGetSelectedItems
 
 
; ==========================================================================================================================
; ==========================================================================================================================
 
#include <Array.au3>
 
$aWinList=WinList("[REGEXPCLASS:^(Explore|Cabinet)WClass$]")
 
For $i = 1 To $aWinList[0][0]
    $aSelection = _ExplorerWinGetSelectedItems($aWinList[$i][1])
    _ArrayDisplay($aSelection, "Explorer Instance #" & $i & " / " & $aWinList[$i][0])
Next

Here's code to select only 1 item (and focus on it), then select all, then deselect all:

$hWin=WinGetHandle('[REGEXPCLASS:^(Explore|Cabinet)WClass$]')
$hCtrl=ControlGetHandle($hWin,'','[CLASS:SysListView32; INSTANCE:1]')
; Windows 7
If $hCtrl='' Then $hCtrl=ControlGetHandle($hWin,'','[CLASS:DirectUIHWND]')
$sFileToSelect=''
$oSHFolderView=_ObjectSHFolderViewFromWin($hWin)
If Not @error Then
    ; Comment this out to choose your own file here:
    $sFileToSelect=$oSHFolderView.FocusedItem.Name
    ConsoleWrite("Focusing on : "&$sFileToSelect&@CRLF)
    WinActivate($hWin)
    ; Select ONLY the item
    $oSHFolderView.SelectItem($oSHFolderView.Folder.ParseName($sFileToSelect),4+1+8+16)
    Sleep(1000)
    ; Select ALL items (easiest way):
    ControlSend($hWin,'',$hCtrl,'^a')
    Sleep(1000)
    ; Deselect ALL items, while maintaining 'focused item'
    $oSHFolderView.SelectItem($oSHFolderView.FocusedItem,4)
EndIf

*Edit: Some helpful links:

Shell Objects

InternetExplorer Object

Edited by Ascend4nt
  • 2 months later...
Posted

ineedh3lp,

Sure, call 'SelectItem' for each item you want to highlight. Note that the 'Name' member of a FolderItem object will often not include the extension (I think shortcuts were particularly a problem), so you'd best select items based on the 'Path' member which would need to be stripped of everything but the filename & extension if it is passed to 'SelectItem' as it was above.

Here's a link to the SelectItem method so you can see what the options are (I used 4+1+8+16 in my example above).

Posted (edited)

Excellent! Thank you for the script and resources.

This works without problems in Windows Explorer. May I extend the discussion and ask you if it is possible to select items in a different file manager? For example, I am using xplorer2, and I did try everything I could think of for the window and control handles, but I couldn't get it to work. Is your script bound to work with Windows Explorer only? I suspect it has something to do with $oShellWindows = $oShell.Windows(), but maybe you can tell me more.

Edited by ineedh3lp
Posted

Yes, Windows Explorer windows only

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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...