Jump to content

Automating Windows Explorer


LarsJ
 Share

Recommended Posts

Link to comment
Share on other sites

Since you are not the only one who has asked questions about the desktop I'll implement the code. But it'll not be soon. I'll recommend you to ask the question in the General Help and Support forum. The desktop can also be automated with standard automation code.

Link to comment
Share on other sites

Link to comment
Share on other sites

  • 3 weeks later...

Example 4) and 5) in post 7 uses GetFiles( True, True ) and GetFolders( True, True ) to get selected files or folders with full path in Windows Explorer. Use GetItems( True, True ) to get all selected items with full path no matter if it's files or folders.

This code works in Windows Explorer. It does not work on the Desktop, and it does not work in an Open or Save dialog.

Link to comment
Share on other sites

  • 5 months later...

@LarsJ I Was messing with grabbing the hWnd and IDispatch object of the desktop window using FindWindowSW() and Just couldn't seem to get it to work 

then looking at the source I notices the declaration was just hResult()

So I Expanded it to this:

"FindWindowSW hresult(variant*;variant*;int;long*;int;ptr*);" & _     ; Finds a window in the Shell windows collection and returns the window's handle and IDispatch interface.

So I assume the definition needs expanded for all items not implemented yet or is there a way to do late binding that I'm missing??

Link to comment
Share on other sites

You can Use the desktop for most of the examples With the addition of a couple of functions:

Spoiler
Func FindDesktopShellBrowser()
    Local $_dtag_IShellWindows = $dtag_IShellWindows
    ;Populate Method
    $_dtag_IShellWindows = StringReplace($_dtag_IShellWindows, "FindWindowSW hresult();", _
            "FindWindowSW hresult(variant*;variant*;int;long*;int;ptr*);")

    Local Const $CSIDL_DESKTOP = 0x0
    Local Enum $SWC_EXPLORER = 0x00, $SWC_BROWSER = 0x01, $SWC_3RDPARTY = 0x02, $SWC_CALLBACK = 0x04, $SWC_DESKTOP = 0x08 ; ShellWindowTypeConstants;
    Local Enum $SWFO_NEEDDISPATCH = 0x01, $SWFO_INCLUDEPENDING = 0x02, $SWFO_COOKIEPASSED = 0x04 ; ShellWindowFindWindowOptions;

    Local $pIDispatch, $oIDispatch
    Local $pIWebBrowserApp, $oIWebBrowserApp, $hWnd
    ; IShellWindows interface
    Local $oIShellWindows = ObjCreateInterface($CLSID_ShellWindows, $sIID_IShellWindows, $_dtag_IShellWindows)

    ;Find the desktop window in list of Shell Windows
    ConsoleWrite("FindWindowSW HRESULT 0x" & _
            Hex($oIShellWindows.FindWindowSW($CSIDL_DESKTOP, 0, $SWC_DESKTOP, $hWnd, $SWFO_NEEDDISPATCH, $pIDispatch)) & @CRLF)
    ConsoleWrite("Desktop hWnd = 0x" & Hex($hWnd) & @CRLF)

    If $pIDispatch Then
        $oIDispatch = ObjCreateInterface($pIDispatch, $sIID_IDispatch, $dtag_IDispatch)
        $oIDispatch.QueryInterface($tRIID_IWebBrowserApp, $pIWebBrowserApp)
        If $pIWebBrowserApp Then
            $oIWebBrowserApp = ObjCreateInterface($pIWebBrowserApp, $sIID_IWebBrowserApp, $dtag_IWebBrowserApp)
        EndIf
    EndIf

    ; IServiceProvider interface
    Local $pIServiceProvider, $oIServiceProvider
    $oIWebBrowserApp.QueryInterface($tRIID_IServiceProvider, $pIServiceProvider)
    $oIServiceProvider = ObjCreateInterface($pIServiceProvider, $sIID_IServiceProvider, $dtag_IServiceProvider)

    ; IShellBrowser interface
    Local $pIShellBrowser
    $oIServiceProvider.QueryService($tRIID_STopLevelBrowser, $tRIID_IShellBrowser, $pIShellBrowser)
    $oIShellBrowser = ObjCreateInterface($pIShellBrowser, $sIID_IShellBrowser, $dtag_IShellBrowser)
EndFunc   ;==>FindDesktopShellBrowser

Func ToggleDesktop($objShell)
    If IsObj($objShell) Then
        $objShell.ToggleDesktop
    EndIf
EndFunc   ;==>ToggleDesktop

 

; Get an IShellBrowser interface
    FindDesktopShellBrowser() ;GetIShellBrowser( $hExplorer )
    
    ;And... If needed...
    
    ;Toggle Desktop
    ToggleDesktop(ObjCreate("shell.application"))

Created Example Setting Destop View / Icon Size

#include "Includes\AutomatingWindowsExplorer.au3"

Opt("MustDeclareVars", 1)

Example()

Func Example()
    Local $objShell = ObjCreate("shell.application")
    Local Const $asFVM_VIEWS =["", "Icon", "Small Icon", "List", "Details", "Thumbnail", "Tile", "Thumbstrip", "Content", ""]
    ; Get an IShellBrowser interface
    FindDesktopShellBrowser()

    If Not IsObj($oIShellBrowser) Then
        MsgBox(0, "Automating Windows Explorer", "Could not get Desktop IShellBrowser interface. Terminating.")
        Return
    EndIf

    ; Get other interfaces
    GetShellInterfaces()

    ; Get current icon view
    Local $view = GetIconView()


    Local $iView, $iSize, $iSzRand, $sViewSz
    If IsArray($view) Then ; OS > XP
        ToggleDesktop($objShell) ;Show The Desktop
        $iView = $view[0] ; Icon view
        $iSize = $view[1] ; Icon size
        $sViewSz = "Icon View = " & $asFVM_VIEWS[$iView] & ", Size = " & $iSize

        ConsoleWrite ("Initial: " & $sViewSz & @CRLF)

        For $i = $FVM_FIRST To $FVM_LAST
            $iSzRand = Random(16, 64, 1)
            $sViewSz = "Icon View = " & $asFVM_VIEWS[$i] & ", Size = " & $iSzRand
            ConsoleWrite ($sViewSz & @CRLF)
            SetIconView($i, $iSzRand) ; Set  view
            MsgBox(0, "Desktop View", "Current View: " & $sViewSz & @CRLF & "Next View: " & $asFVM_VIEWS[$i + 1])
        Next

        SetIconView($iView, $iSize) ; Restore old view

    Else ; OS = XP
        $iView = $view
        If $iView <> $FVM_DETAILS Then ; Not details view
            SetIconView($FVM_DETAILS) ; Set details view
        ElseIf $iView <> $FVM_ICON Then ; Not icon view
            SetIconView($FVM_ICON) ; Set icon view
        EndIf
        Sleep(3000) ; Wait 3 seconds
        SetIconView($iView) ; Restore old view
    EndIf
EndFunc   ;==>Example

Func FindDesktopShellBrowser()
    Local $_dtag_IShellWindows = $dtag_IShellWindows
    ;Populate Method
    $_dtag_IShellWindows = StringReplace($_dtag_IShellWindows, "FindWindowSW hresult();", _
            "FindWindowSW hresult(variant*;variant*;int;long*;int;ptr*);")

    Local Const $CSIDL_DESKTOP = 0
    Local Enum $SWC_EXPLORER = 0x00, $SWC_BROWSER = 0x01, $SWC_3RDPARTY = 0x02, $SWC_CALLBACK = 0x04, $SWC_DESKTOP = 0x08 ; ShellWindowTypeConstants;
    Local Enum $SWFO_NEEDDISPATCH = 0x01, $SWFO_INCLUDEPENDING = 0x02, $SWFO_COOKIEPASSED = 0x04 ; ShellWindowFindWindowOptions;

    Local $pIDispatch, $oIDispatch
    Local $pIWebBrowserApp, $oIWebBrowserApp, $hWnd
    ; IShellWindows interface
    Local $oIShellWindows = ObjCreateInterface($CLSID_ShellWindows, $sIID_IShellWindows, $_dtag_IShellWindows)

    ;Find the desktop window in list of Shell Windows
    ConsoleWrite("FindWindowSW HRESULT 0x" & _
            Hex($oIShellWindows.FindWindowSW($CSIDL_DESKTOP, 0, $SWC_DESKTOP, $hWnd, $SWFO_NEEDDISPATCH, $pIDispatch)) & @CRLF)
    ConsoleWrite("Desktop hWnd = 0x" & Hex($hWnd) & @CRLF)

    If $pIDispatch Then
        $oIDispatch = ObjCreateInterface($pIDispatch, $sIID_IDispatch, $dtag_IDispatch)
        $oIDispatch.QueryInterface($tRIID_IWebBrowserApp, $pIWebBrowserApp)
        If $pIWebBrowserApp Then
            $oIWebBrowserApp = ObjCreateInterface($pIWebBrowserApp, $sIID_IWebBrowserApp, $dtag_IWebBrowserApp)
        EndIf
    EndIf

    ; IServiceProvider interface
    Local $pIServiceProvider, $oIServiceProvider
    $oIWebBrowserApp.QueryInterface($tRIID_IServiceProvider, $pIServiceProvider)
    $oIServiceProvider = ObjCreateInterface($pIServiceProvider, $sIID_IServiceProvider, $dtag_IServiceProvider)

    ; IShellBrowser interface
    Local $pIShellBrowser
    $oIServiceProvider.QueryService($tRIID_STopLevelBrowser, $tRIID_IShellBrowser, $pIShellBrowser)
    $oIShellBrowser = ObjCreateInterface($pIShellBrowser, $sIID_IShellBrowser, $dtag_IShellBrowser)
EndFunc   ;==>FindDesktopShellBrowser

Func ToggleDesktop($objShell)
    If IsObj($objShell) Then
        $objShell.ToggleDesktop
    EndIf
EndFunc   ;==>ToggleDesktop

 

Edited by Bilgus
Link to comment
Share on other sites

Bilgus, Very interesting indeed. Quite a lot of the above items are about automating the desktop. So far, they have been unanswered. I'll look into the code after the Easter holiday.

Link to comment
Share on other sites

Try as I might I couldn't seem to get FindWindowSw() to accept a PIDL for any KnownFolderIds

I figured it might be my error I even tried sequential numbers with a properly formatted tag_Variant and I couldn't get it to work

 

After searching on the net, I don't think it works for anyone else either so maybe its broken or the definition on MSDN is wrong

 

This works just fine for grabbing the desktop window

$oIShellWindows.FindWindowSW(NULL, NULL, $SWC_DESKTOP, $hWnd, $SWFO_NEEDDISPATCH, $pIDispatch)

 

So giving up on a way to find know folders I decided an EnumShellWindows() function would be the next best thing

Spoiler
Func EnumShellWindows()
;
    Local $_dtag_IWebBrowserApp = $dtag_IWebBrowserApp
    Local $_dtag_IShellWindows = $dtag_IShellWindows
    ;Populate Methods
    $_dtag_IWebBrowserApp = StringReplace($_dtag_IWebBrowserApp, "get_LocationName hresult();", _
            "get_LocationName hresult(BStr*);")
    $_dtag_IWebBrowserApp = StringReplace($_dtag_IWebBrowserApp, "get_LocationURL hresult();", _
            "get_LocationURL hresult(BStr*);")

    $_dtag_IShellWindows = StringReplace($_dtag_IShellWindows, "FindWindowSW hresult();", _
            "FindWindowSW hresult(variant*;variant*;int;long*;int;ptr*);")
;           
    Local $pIDispatch, $oIDispatch

    ; IShellWindows interface
    Local $oIShellWindows = ObjCreateInterface($CLSID_ShellWindows, $sIID_IShellWindows, $_dtag_IShellWindows)

    ; Number of shell windows
    Local $iWindows
    $oIShellWindows.get_Count($iWindows)
    ConsoleWrite("Window Count: " & $iWindows & @CRLF)
    ; Get an IWebBrowserApp object for each window
    ; This is done in two steps:
    ; 1. Get an IDispatch object for the window
    ; 2. Get the IWebBrowserApp interface
    ; Check if it's the right window
    Local $pIWebBrowserApp, $oIWebBrowserApp, $hWnd, $sLoc, $aRet[$iWindows + 2][2]
    $aRet[0][0] = 0

    For $i = 0 To $iWindows
        If $i < $iWindows Then
            $oIShellWindows.Item($i, $pIDispatch)
        Else
            $oIShellWindows.FindWindowSW(Null, Null, $SWC_DESKTOP, $hWnd, $SWFO_NEEDDISPATCH, $pIDispatch)
        EndIf
        If $pIDispatch Then
            $oIDispatch = ObjCreateInterface($pIDispatch, $sIID_IDispatch, $dtag_IDispatch)
            $oIDispatch.QueryInterface($tRIID_IWebBrowserApp, $pIWebBrowserApp)
            If $pIWebBrowserApp Then

                $oIWebBrowserApp = ObjCreateInterface($pIWebBrowserApp, $sIID_IWebBrowserApp, $_dtag_IWebBrowserApp)

                $oIWebBrowserApp.get_HWND($hWnd)
                $aRet[$i + 1][0] = "0x" & Hex($hWnd)

                $sLoc = ""
                $oIWebBrowserApp.get_LocationURL($sLoc) ;try to get the full path first
                If $sLoc = "" Then
                    $oIWebBrowserApp.get_LocationName($sLoc)
                Else
                    $sLoc = PathCreateFromUrlW($sLoc)
                EndIf

                If $sLoc = "" And _WinAPI_GetShellWindow() = $hWnd Then $sLoc = "Desktop"
                $aRet[$i + 1][1] = $sLoc

                $aRet[0][0] += 1
            EndIf
        EndIf
    Next

    Return $aRet
EndFunc   ;==>EnumShellWindows

Func PathCreateFromUrlW($sURL, $vDll = "shlwapi.dll")
    Local $aRet = DllCall($vDll, "long", "PathCreateFromUrlW", "wstr", $sURL, "wstr", "", "dword*", 65534, "dword", 0) ;Ascend4nt
    If Not @error And IsArray($aRet) And $aRet[0] = 0 Then
        Return $aRet[2]
    EndIf
EndFunc   ;==>PathCreateFromUrlW

 

Do Note The populate Methods part won't be needed eventually but they are just there to make it work with the current example files

Edited by Bilgus
PathCreateFromUrlW($sLoc)
Link to comment
Share on other sites

I updated the GetSetIconView example quite a bit It now lists all windows found with the above handy enum function 

Allows finding windows by Pidl(FolderIds)  The example uses CSIDL for ease of putting in a list but that function is depreciated

Adds a few functions from shlwapi and a some other misc stuff,

there are still some other parts I'm not particularly happy with but I'll probably save that for an update of my DeskViewChanger script

Spoiler
Opt("MustDeclareVars", 1)

#include "Includes\AutomatingWindowsExplorer.au3"

#include <GuiComboBoxEx.au3>
#include <GuiListView.au3>
#include <ButtonConstants.au3>
#include <ComboConstants.au3>
#include <GUIConstantsEx.au3>
#include <GUIListBox.au3>
#include <WindowsConstants.au3>
Global Const $asFVM_VIEWS = ["", "Icon", "Small Icon", "List", "Details", "Thumbnail", "Tile", "Thumbstrip", "Content", ""]

Example()

Func Example()

    Local $hForm1 = GUICreate("Form1", 303, 366, 254, 156)
    Local $IdListVw1 = GUICtrlCreateListView("Hwnd    | Path", 8, 8, 281, 278)
    Local $hListVw = GUICtrlGetHandle($IdListVw1)

    Local $IdCombo1 = GUICtrlCreateCombo("By CSIDL", 8, 296, 281, 25)
    Local $hCombo1 = GUICtrlGetHandle($IdCombo1)

    Local $IdCombo2 = GUICtrlCreateCombo("Auto", 8, 328, 169, 25, BitOR($CBS_DROPDOWN, $CBS_AUTOHSCROLL))
    Local $hCombo2 = GUICtrlGetHandle($IdCombo2)

    Local $IdButton1 = GUICtrlCreateButton("Go", 192, 328, 97, 25)

    Local $aRet = EnumShellWindows()

    For $i = 1 To $aRet[0][0]
        GUICtrlCreateListViewItem($aRet[$i][0] & "|" & $aRet[$i][1], $IdListVw1)
    Next

    Local $iCSIDL, $sItems, $sPath = "|"
    For $i = 0 To 70
        $sPath = _WinAPI_ShellGetSpecialFolderPath($i)
        $sPath = StringMid($sPath, StringInStr($sPath, "\", 1, -2) + 1)
        $sItems &= $sPath & "|"
    Next
    GUICtrlSetData($IdCombo1, $sItems)

    $sItems = ""
    For $i = 1 To UBound($asFVM_VIEWS) - 2
        $sItems &= $asFVM_VIEWS[$i] & "|"
    Next

    GUICtrlSetData($IdCombo2, $sItems)
    _GUICtrlComboBox_SetCurSel($hCombo2, 0)

    GUISetState(@SW_SHOW)

    Local $nMsg, $hWnd, $pPidl
    While 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
            Case $GUI_EVENT_CLOSE
                Exit
            Case $IdCombo1
                _GUICtrlListView_SetItemSelected($hListVw, -1, False)
            Case $IdButton1
                $hWnd = HWnd(_GUICtrlListView_GetItemText($hListVw, List_Index($hListVw)))
                If Not $hWnd Then
                    ConsoleWrite("CSIDL = " & _GUICtrlComboBoxEx_GetCurSel($hCombo1) - 1 & @CRLF)
                    $pPidl = _WinAPI_ShellGetSpecialFolderLocation(_GUICtrlComboBoxEx_GetCurSel($hCombo1) - 1)
                    ConsoleWrite("pPidl = " & $pPidl & @CRLF)
                EndIf
                ConsoleWrite("View = " & _GUICtrlComboBoxEx_GetCurSel($hCombo2) & @CRLF)
                ShellSetView($hWnd, $pPidl, _GUICtrlComboBoxEx_GetCurSel($hCombo2), Random(16, 64, 1))
                _WinAPI_CoTaskMemFree($pPidl)
        EndSwitch
    WEnd

EndFunc   ;==>Example

Func List_Index($hWndList1)
    Local $iIndex = _GUICtrlListView_GetSelectionMark($hWndList1)
    If _GUICtrlListView_GetItemSelected($hWndList1, $iIndex) Then Return $iIndex
    Return -1
EndFunc   ;==>List_Index

Func ShellSetView($hExplorer, $pPidl, $iView, $iSize = 16)
    ;hExplorer = 0 & pPidl = 0 grabs desktop

    ; Get an IShellBrowser interface
    FindIShellBrowser($hExplorer, $pPidl) ;$hExplorer);GetIShellBrowser( $hExplorer )

    If Not IsHWnd($hExplorer) Then
        MsgBox(0, "Automating Windows Explorer", "Window does not exist.")
        Return
    ElseIf Not IsObj($oIShellBrowser) Then
        MsgBox(0, "Automating Windows Explorer", "Could not get an IShellBrowser interface.")
        Return
    EndIf

    ; Get other interfaces
    GetShellInterfaces()

    ; Get current icon view
    Local $view = GetIconView()

    If StringInStr(_WinAPI_GetClassName($hExplorer), "Progman") Then ;This Might be flaky..
        ToggleDesktop(ObjCreate("shell.application")) ;Show The Desktop
    Else
        WinActivate($hExplorer)
    EndIf

    If $iView < $FVM_FIRST Then
        $iView = -1 ;(Auto)
    ElseIf $iView > $FVM_LAST Then
        $iView = $FVM_LAST
    EndIf

    If IsArray($view) Then ; OS > XP
        SetIconView($iView, $iSize) ; NewView
        MsgBox(0, "Desktop View", "Current View: " & $asFVM_VIEWS[GetIconView()[0]] & @CRLF & _
                "Original View: " & $asFVM_VIEWS[$view[0]])
        $iView = $view[0] ; Icon view
        $iSize = $view[1] ; Icon size
        SetIconView($iView, $iSize) ; Restore old view

    Else ; OS = XP
        MsgBox(0, "Automating Windows Explorer", "XP Not Tested / Supported. Terminating.")
        Return
        $iView = $view
        If $iView <> $FVM_DETAILS Then ; Not details view
            SetIconView($FVM_DETAILS) ; Set details view
        ElseIf $iView <> $FVM_ICON Then ; Not icon view
            SetIconView($FVM_ICON) ; Set icon view
        EndIf
        Sleep(3000) ; Wait 3 seconds
        SetIconView($iView) ; Restore old view
    EndIf

EndFunc   ;==>ShellSetView

Func ToggleDesktop($objShell)
    If IsObj($objShell) Then
        $objShell.ToggleDesktop
    EndIf
EndFunc   ;==>ToggleDesktop
#Region #SHELLFUNCTIONS#

Func Create_IShellFolder()
    ;Don't forget IUnknown::Release;;;Apparently Autoit Releases this for us..
    Local Static $oIShellFolder
    If Not IsObj($oIShellFolder) Then
        Local $pIShellFolder
        SHGetDesktopFolder($pIShellFolder)
        $oIShellFolder = ObjCreateInterface($pIShellFolder, $sIID_IShellFolder, $dtag_IShellFolder)
    EndIf
    Return $oIShellFolder
EndFunc   ;==>Create_IShellFolder

Func Create_IShellWindows()
    ; IShellWindows interface
    ;;Populate Methods
    Local $_dtag_IShellWindows = $dtag_IShellWindows

    $_dtag_IShellWindows = StringReplace($_dtag_IShellWindows, "FindWindowSW hresult();", _
            "FindWindowSW hresult(variant*;variant*;int;long*;int;ptr*);")
    ;;
    Local $oIShellWindows = ObjCreateInterface($CLSID_ShellWindows, $sIID_IShellWindows, $_dtag_IShellWindows)

    Return $oIShellWindows
EndFunc   ;==>Create_IShellWindows

Func EnumShellWindows()
    ;;Populate Methods
    Local $_dtag_IWebBrowserApp = $dtag_IWebBrowserApp

    $_dtag_IWebBrowserApp = StringReplace($_dtag_IWebBrowserApp, "get_LocationName hresult();", _
            "get_LocationName hresult(BStr*);")
    $_dtag_IWebBrowserApp = StringReplace($_dtag_IWebBrowserApp, "get_LocationURL hresult();", _
            "get_LocationURL hresult(BStr*);")
    ;;

    ; IShellWindows interface
    Local $oIShellWindows = Create_IShellWindows()

    Local $pIDispatch, $oIDispatch, $iError, $aRet[1][2]

    If IsObj($oIShellWindows) Then
        ; Number of shell windows
        Local $iWindows
        $oIShellWindows.get_Count($iWindows)
        ConsoleWrite("Window Count: " & $iWindows & @CRLF)
        ; Get an IWebBrowserApp object for each window
        ; This is done in two steps:
        ; 1. Get an IDispatch object for the window
        ; 2. Get the IWebBrowserApp interface
        ; Check if it's the right window
        Local $pIWebBrowserApp, $oIWebBrowserApp, $hWnd, $sLoc, $aRet[$iWindows + 2][2]
        $aRet[0][0] = 0

        For $i = 0 To $iWindows
            If $i < $iWindows Then
                $oIShellWindows.Item($i, $pIDispatch)
            Else
                $pIDispatch = IShellWindows_Desktop($oIShellWindows, $hWnd)
            EndIf
            If $pIDispatch Then
                $oIDispatch = ObjCreateInterface($pIDispatch, $sIID_IDispatch, $dtag_IDispatch)
                If IsObj($oIDispatch) Then
                    $oIDispatch.QueryInterface($tRIID_IWebBrowserApp, $pIWebBrowserApp)
                EndIf
                If $pIWebBrowserApp Then

                    $oIWebBrowserApp = ObjCreateInterface($pIWebBrowserApp, $sIID_IWebBrowserApp, $_dtag_IWebBrowserApp)

                    $oIWebBrowserApp.get_HWND($hWnd)
                    $aRet[$i + 1][0] = "0x" & Hex($hWnd)

                    $sLoc = ""
                    $oIWebBrowserApp.get_LocationURL($sLoc) ;try to get the full path first
                    If $sLoc = "" Then
                        $oIWebBrowserApp.get_LocationName($sLoc)
                    Else
                        $sLoc = PathCreateFromUrlW($sLoc)
                    EndIf

                    If $sLoc = "" And _WinAPI_GetShellWindow() = $hWnd Then $sLoc = "Desktop"
                    $aRet[$i + 1][1] = $sLoc

                    $aRet[0][0] += 1
                EndIf
            EndIf
        Next
    Else
        $iError = 1 ;No $oIShellWindows
    EndIf
    Return SetError($iError, 0, $aRet)
EndFunc   ;==>EnumShellWindows

Func FindIShellBrowser(ByRef $hExplorer, $pPidl = 0)
    ; IShellWindows interface
    Local $iError
    Local $oIShellWindows = Create_IShellWindows()

    Local $pIDispatch, $oIDispatch, $hWnd

    If IsObj($oIShellWindows) And (IsHWnd($hExplorer) Or $pPidl) Then
        $pIDispatch = IShellWindows_Desktop($oIShellWindows, $hWnd)
        If Not IsHWnd($hExplorer) Or $hWnd <> $hExplorer Then
            ; Number of shell windows
            Local $iWindows
            $oIShellWindows.get_Count($iWindows)
            ConsoleWrite("Window Count: " & $iWindows & @CRLF)
            ; Get an IWebBrowserApp object for each window
            ; This is done in two steps:
            ; 1. Get an IDispatch object for the window
            ; 2. Get the IWebBrowserApp interface
            ; Check if it's the right window
            Local $pIWebBrowserApp, $oIWebBrowserApp
            For $i = 0 To $iWindows - 1
                $oIShellWindows.Item($i, $pIDispatch)
                If $pIDispatch Then

                    $oIDispatch = ObjCreateInterface($pIDispatch, $sIID_IDispatch, $dtag_IDispatch)
                    $oIDispatch.QueryInterface($tRIID_IWebBrowserApp, $pIWebBrowserApp)
                    If $pIWebBrowserApp Then

                        $oIWebBrowserApp = ObjCreateInterface($pIWebBrowserApp, $sIID_IWebBrowserApp, $dtag_IWebBrowserApp)
                        $oIWebBrowserApp.get_HWND($hWnd)
                        Local $pPidlFolder = $pPidl ? GetShellPidl($pIDispatch) : 0

                        If $hWnd = $hExplorer Or ($pPidl And IShellFolder_CompareIds($pPidlFolder, $pPidl) = 0) Then ;;ILIsEqual($pPidlFolder, $pPidl) Then
                            ConsoleWrite("Found 0x" & Hex($hWnd) & @CRLF)
                            _WinAPI_CoTaskMemFree($pPidlFolder)
                            $hExplorer = HWnd($hWnd)
                            ExitLoop
                        EndIf
                        _WinAPI_CoTaskMemFree($pPidlFolder)
                    EndIf
                EndIf
            Next
        EndIf

    ElseIf IsObj($oIShellWindows) Then ;Get Desktop ShellWindow
        $pIDispatch = IShellWindows_Desktop($oIShellWindows, $hWnd)
    Else
        $iError = 1 ;No $oIShellWindows
    EndIf

    If $pIDispatch Then
        Local $pIShellBrowser = IUnknown_QueryService($pIDispatch, $tRIID_STopLevelBrowser, $tRIID_IShellBrowser)
        $oIShellBrowser = ObjCreateInterface($pIShellBrowser, $sIID_IShellBrowser, $dtag_IShellBrowser)
    ElseIf Not $iError Then
        ConsoleWrite("Error retrieving IShellBrowser Object")
        $iError = 2
    EndIf

    Return SetError($iError, 0, $oIShellBrowser)
EndFunc   ;==>FindIShellBrowser

Func GetShellPidl($pUnk)
    ;Don't forget to free with  _WinAPI_CoTaskMemFree()
    Local $pIFolderView, $oIFolderView
    Local $pIPersistFolder2, $pPidlFolder, $iError

    ; IFolderView interface
    $pIFolderView = IUnknown_QueryService($pUnk, $tRIID_IFolderView, $tRIID_IFolderView)
    If $pIFolderView Then
        $oIFolderView = ObjCreateInterface($pIFolderView, $sIID_IFolderView, $dtag_IFolderView)
    Else
        $iError = 1
    EndIf

    If IsObj($oIFolderView) Then
        ; IPersistFolder2 interface
        $oIFolderView.GetFolder($tRIID_IPersistFolder2, $pIPersistFolder2)
        Local $oIPersistFolder2 = ObjCreateInterface($pIPersistFolder2, $sIID_IPersistFolder2, $dtag_IPersistFolder2)
        If IsObj($oIPersistFolder2) Then
            $oIPersistFolder2.GetCurFolder($pPidlFolder)
            ConsoleWrite($pPidlFolder & ":" & _WinAPI_ShellGetPathFromIDList($pPidlFolder) & @CRLF)
        Else
            $iError = 3
        EndIf
    Else
        $iError = 2 ;No $oIFolderView
    EndIf
    Return SetError($iError, 0, $pPidlFolder)
EndFunc   ;==>GetShellPidl

Func IShellFolder_GetDisplayNameOf($pPidl, $fName = 0, $fFullPath = True)
    Local $iError
    Local $oIShellFolder = Create_IShellFolder()
    Local $tSTRRET = DllStructCreate($tagSTRRET), $sName

    ; Name format
    If Not $fFullPath Then
        If $fName = $SHGDN_NORMAL Then
            $fName = $SHGDN_INFOLDER
        Else ; $fName = $SHGDN_FORPARSING
            $fName = BitOR($SHGDN_INFOLDER, $SHGDN_FORPARSING)
        EndIf
    EndIf
    If IsObj($oIShellFolder) Then
        $oIShellFolder.GetDisplayNameOf($pPidl, $fName, $tSTRRET)
        StrRetToBuf(DllStructGetPtr($tSTRRET), $NULL, $sName)
    Else
        $iError = 1
    EndIf

    Return $sName
EndFunc   ;==>IShellFolder_GetDisplayNameOf

Func IShellFolder_CompareIds($pPidl1, $pPidl2)
    Local Enum $SHCIDS_ALLFIELDS = 0x80000000, $SHCIDS_CANONICALONLY = 0x10000000
    Local $iError, $iCompare
    Local $oIShellFolder = Create_IShellFolder()
    If IsObj($oIShellFolder) Then
        $iCompare = $oIShellFolder.CompareIds(0, $pPidl1, $pPidl2)
    Else
        $iError = 1
    EndIf
    ;Fallback
    If $iCompare <> 0 And IShellFolder_GetDisplayNameOf($pPidl1, $SHGDN_FORPARSING) = IShellFolder_GetDisplayNameOf($pPidl2, $SHGDN_FORPARSING) Then $iCompare = 0

    Return SetError($iError, 0, $iCompare)
EndFunc   ;==>IShellFolder_CompareIds

Func IShellWindows_Desktop($oIShellWindows, ByRef $hWnd)
    Local Enum $SWC_EXPLORER = 0x00, $SWC_BROWSER = 0x01, $SWC_3RDPARTY = 0x02, $SWC_CALLBACK = 0x04, $SWC_DESKTOP = 0x08 ; ShellWindowTypeConstants;
    Local Enum $SWFO_NEEDDISPATCH = 0x01, $SWFO_INCLUDEPENDING = 0x02, $SWFO_COOKIEPASSED = 0x04 ; ShellWindowFindWindowOptions;
    Local $pIDispatch
    If IsObj($oIShellWindows) Then
        $oIShellWindows.FindWindowSW(Null, Null, $SWC_DESKTOP, $hWnd, $SWFO_NEEDDISPATCH, $pIDispatch)
    EndIf

    Return $pIDispatch
EndFunc   ;==>IShellWindows_Desktop
#Region #SHLWAPIFUNCTIONS#

Func IUnknown_QueryService($pUnk, $tClsid, $tRiid, $vDll = "Shlwapi.dll")
    Local $sFunc = "IUnknown_QueryService"

    Local $aCall = DllCall($vDll, "long", $sFunc, "ptr", $pUnk, "ptr", DllStructGetPtr($tClsid), _
            "ptr", DllStructGetPtr($tRiid), "ptr*", 0)

    If Not @error And IsArray($aCall) Then
        If $aCall[0] = $S_OK Then
            ConsoleWrite($sFunc & " S_OK " & $aCall[4] & @CRLF)
            Return $aCall[4]
        Else
            ConsoleWrite($sFunc & " Com Err: 0x" & Hex($aCall[0]) & @CRLF)
        EndIf
    Else
        ConsoleWrite($sFunc & " Failed")
    EndIf
EndFunc   ;==>IUnknown_QueryService

Func PathCreateFromUrlW($sURL, $vDll = "shlwapi.dll")
    Local $sFunc = "PathCreateFromUrlW"
    ;65534 => Sizeof(Wstr) - 2 Null bytes
    Local $aCall = DllCall($vDll, "long", $sFunc, "wstr", _
            $sURL, "wstr", "", "dword*", 65534, "dword", 0) ;Ascend4nt

    If Not @error And IsArray($aCall) Then
        If $aCall[0] = $S_OK Then
            ConsoleWrite($sFunc & " S_OK " & $aCall[2] & @CRLF)
            Return $aCall[2]
        Else
            ConsoleWrite($sFunc & " Com Err: 0x" & Hex($aCall[0]) & @CRLF)
        EndIf
    Else
        ConsoleWrite($sFunc & " Failed")
    EndIf
EndFunc   ;==>PathCreateFromUrlW
#EndRegion #SHLWAPIFUNCTIONS#

#EndRegion #SHELLFUNCTIONS#

 

SetIcons.png.6c84455a5560863dd5e034d50369bd9d.png

Edited by Bilgus
Link to comment
Share on other sites

I haven't looked at the code yet, but I'm sure it's nice code.

I think it's possible to automate the standard Open/Save dialogs in similar ways. But I've not tried. Do you know about techniques to automate these dialogs?

Link to comment
Share on other sites

  • 2 weeks later...

Playing with the interfaces for Dialogs for a few days I've come to the conclusion that you are only going to be able to access dialogs you create within your process.

 

Well I should say easily access,

I was able to get IUnknown from open/save as dialogs with AccessibleObjectFromWindow but The only interfaces exposed were IUnknown and IOleWindow so I've a feeling this is a dead end

 

For the next try I found a function SHShellFolderView_Message that is depreciated It gets IShellFolderView from another function 

that seems to be unexposed ShellFolderViewFromWindow and only used by the former depreciated function

This led me to an undocumented message CWM_GETISHELLBROWSER 

searching the net I found it as WM_GETISHELLBROWSER = WM_USER + 0x7 but very little info beyond that

 

Basically I was able to identify a window as having an IShellBrowser interface if there was a pointer returned

from SendMessage($hWnd, $WM_GETISHELLBROWSER, 0, 0) but it was a pointer within the host process therefore useless in its current form.

 

From what I can tell you would need to inject code into the host of the dialog to make use of the object returned by the call

to WM_GETISHELLBROWSER but that is as far as I've gotten thus far

 

 

Link to comment
Share on other sites

  • 2 years later...

Hi,

Thank you for this great work. I'm new to this though and could do with a bit of help. I want to automate clicking on a mapped network drive in windows explorer. Do I open your GUI using AutoIt and use other AutoIt commands on your GUI window? If so I couldn't find how to automate clicking on the 'Browse' tab? Or can the commands be sent directly somehow? I'm not sure of the work flow. An example would be amazing.

Thank you,

A

Link to comment
Share on other sites

On 7/9/2020 at 10:21 AM, artyb said:

I want to automate clicking on a mapped network drive in windows explorer.

This seems to be a completely normal automation task. If you're lucky, it can be done with the automation functions in the help file. The GUI in first post is just for demonstration of the features in the UDF. It cannot be used for your task. If you've more questions, ask them in the General Help and Support forum. Here you get much faster answers.

Link to comment
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
 Share

  • Recently Browsing   0 members

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