Results 1 to 10 of 10

Thread: Using UIAutomationClient to automate the Save As file download in IE11

  1. #1
    Board Regular
    Join Date
    Oct 2007
    Posts
    5,857
    Post Thanks / Like
    Mentioned
    8 Post(s)
    Tagged
    2 Thread(s)

    Default Using UIAutomationClient to automate the Save As file download in IE11

    Here is VBA code which automates the complete 'Save As' file download procedure in IE11, when a download is offered by IE's Download Notification Bar.

    To use for your own web site downloads you would automate IE and do whatever is necessary to make the Download Notification Bar appear at the bottom of the IE window and then call IE_Download_File_Using_UIAutomation. It has the following parameters:

    Public Function IE_Download_File_Using_UIAutomation(IEhwnd As Long, ByVal saveInFolder As String, ByVal saveAsFileName As String, ByVal replaceExistingFile As Boolean, ByRef downloadResult As String) As Boolean

    • IEhwnd - The handle of the IE window. The Download Notification Bar must be displayed in the active tab. If necessary, call IE_Click_Tab_Like to activate the required tab before calling this function.
    • saveInFolder - The folder path where the downloaded file will be saved. Specify "" to save the file in IE's default download folder.
    • saveAsFileName - The file name which the downloaded file will be given. Specify "" to use the file name provided by the web site.
    • replaceExistingFile - True to replace the file if it already exists; False to overwrite the file.
    • downloadResult - Output string returned to the caller showing whether the file was successfully download or not, including the file name of the downloaded file (including its path if saveInFolder was specified).

    Function return value - True: the file was downloaded; False: the file was not downloaded.

    NOTE - The only issue I had was that after calling SetValue to put a specific file name in the Save As dialogue and clicking Save (Invoke), the download doesn't recognise the specified file name and still uses the default file name provided by the web site. A simple workaround which has worked in all tests is SendKeys " ", True to insert a space character at start of the file name input element, however I know that SendKeys is unreliable and this might not always work for some people.

    Also note that the IE tab offering the download must be the active tab, and the IE_Click_Tab_Like routine should be called to activate it if necessary. The code also includes several debugging functions which can be helpful to understand the UIAutomation hierarchy.

    Here is the complete code, including a test procedure for downloading a 2 Kb csv file from morningstar.com

    Code:
    '07-Feb-2019
    'Use UIAutomationClient to automate the Save As file download in IE11
    
    'References:
    'Microsoft Internet Controls
    'Microsoft HTML Object Library
    'UIAutomationClient
    
    
    Option Explicit
    
    #If  VBA7 Then
        Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
        Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWndParent As LongPtr, ByVal hwndChildAfter As LongPtr, ByVal lpszClass As String, ByVal lpszWindow As String) As LongPtr
        Private Declare PtrSafe Function SetForegroundWindow Lib "user32" (ByVal hWnd As LongPtr) As Long
    #Else 
        Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
        Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWndParent As Long, ByVal hwndChildAfter As Long, ByVal lpszClass As String, ByVal lpszWindow As String) As Long
        Private Declare Function SetForegroundWindow Lib "user32" (ByVal hWnd As Long) As Long
    #End  If
    
    
    Public Sub IE_Download_File_Save_As()
    
        Dim URL As String
        Dim IE As InternetExplorer
        Dim HTMLdoc As HTMLDocument
        Dim exportLink As HTMLLinkElement
        Dim saveInFolder As String
        Dim saveAsFileName As String
        Dim replaceExistingFile As Boolean
        Dim downloadResult As String, downloadStatus As Boolean
        
        saveInFolder = ""                           'Save in IE11's default download folder
        saveInFolder = "c:\path\to\folder"          'Save in this folder
        saveAsFileName = ""                         'Save As the file name provided by web site
        saveAsFileName = "My Csv Data"              'Save As this file name
        replaceExistingFile = True
        
        URL = "http://financials.morningstar.com/balance-sheet/bs.html?t=INTC&region=usa&culture=en-US"
        
        'See if an IE window is already open at the site
        
        Set IE = Get_IE_Window(CStr(URL))
        If IE Is Nothing Then
            Set IE = New InternetExplorer
            With IE
                SetForegroundWindow .hWnd
                .Visible = True
                If .LocationURL <> URL Then
                    .navigate URL
                    While .Busy Or .readyState <> READYSTATE_COMPLETE: DoEvents: Sleep 100: Wend
                    While .document.readyState <> "complete": DoEvents: Sleep 100: Wend
                End If
            End With
        End If
        Set HTMLdoc = IE.document
               
        Set exportLink = HTMLdoc.getElementsByClassName("rf_export")(0)
        
        If Not exportLink Is Nothing Then
        
            'Click the Export link, which opens IE's Download Notification Bar
            '
            '   Do you want to open or save INTC Balance Sheet.csv from financials.morningstar.com?
            '       with buttons [Open] [Save][Down Arrow] [Cancel] [X]
            
            exportLink.Click
            
            'Activate the morningstar.com IE tab and download the file using Save As
            
            IE_Click_Tab_Like IE.hWnd, "*morningstar.com*"
            downloadStatus = IE_Download_File_Using_UIAutomation(IE.hWnd, saveInFolder, saveAsFileName, replaceExistingFile, downloadResult)
            Debug.Print "Download status = " & downloadStatus
            MsgBox "Download result = " & downloadResult
            
        Else
        
            MsgBox "Export link not found - file not downloaded"
            
        End If
        
    End Sub
    
    #If  VBA7 Then
    Public Function IE_Download_File_Using_UIAutomation(IEhwnd As LongPtr, ByVal saveInFolder As String, ByVal saveAsFileName As String, ByVal replaceExistingFile As Boolean, ByRef downloadResult As String) As Boolean
    #Else 
    Public Function IE_Download_File_Using_UIAutomation(IEhwnd As Long, ByVal saveInFolder As String, ByVal saveAsFileName As String, ByVal replaceExistingFile As Boolean, ByRef downloadResult As String) As Boolean
    #End  If
    
        'Automate IE11's Download Notification Bar in the active tab, by clicking the Save As item, downloading the file and closing the Notification Bar.
        'The IE option 'Notify when downloads complete' must be enabled.
        '
        'Parameters:
        'IEhwnd                 The handle of the IE window. The Download Notification Bar must be displayed in the active tab.
        '                       If necessary, call IE_Click_Tab_Like to activate the required tab before calling this function.
        'saveInFolder           The folder path where the downloaded file will be saved.  Specify "" to save the file in IE's default download folder.
        'saveAsFileName         The file name which the downloaded file will be given.  If file extension is omitted, the file extension provided by
        '                       the web site is used. Specify "" to use the file name provided by the web site.
        'replaceExistingFile    True to replace the file if it already exists; False to overwrite the file
        'downloadResult         Output string returned to the caller showing whether the file was successfully download or not, including the file name of the
        '                       downloaded file (including its path if saveInFolder was specified).
        '
        'Function return value  True: the file was downloaded; False: the file was not downloaded
        
        #If  VBA7 Then
            Dim hWnd As LongPtr
        #Else 
            Dim hWnd As Long
        #End  If
        Dim UIAutomation As IUIAutomation
        Dim DesktopRoot As IUIAutomationElement
        Dim FrameNotificationBarPane As IUIAutomationElement
        Dim Button As IUIAutomationElement
        Dim NotificationBarText As IUIAutomationElement
        Dim SplitButtons As IUIAutomationElementArray
        Dim DownArrow As IUIAutomationElement
        Dim InvokePattern As IUIAutomationInvokePattern
        Dim ContextMenu As IUIAutomationElement
        Dim SaveAsMenuItem As IUIAutomationElement
        Dim SaveAsWindow As IUIAutomationElement
        Dim FileNameInput As IUIAutomationElement
        Dim FileNameInputPattern As IUIAutomationValuePattern, FileNameInputPatternLegacy As IUIAutomationLegacyIAccessiblePattern
        Dim ConfirmSaveAsWindow As IUIAutomationElement
        Dim ConfirmSaveAsWindowText As IUIAutomationElement
        Dim SaveAsWarningWindow As IUIAutomationElement, SaveAsWarningText As IUIAutomationElement
        Dim NotificationToolbar As IUIAutomationElement
        Dim ControlName As IUIAutomationCondition, ControlType As IUIAutomationCondition, NameAndType As IUIAutomationCondition
        Dim TreeWalker As IUIAutomationTreeWalker
        Dim defaultFileName As String, fullFileName As String
        Dim ConfirmSaveAsWindowTextString As String
        Dim SaveAsWarningTextString As String
        Dim NotificationBarTextString As String, p1 As Long, p2 As Long
        Dim timeout As Date
        Dim downloaded As Boolean
        Dim destCell As Range, numRows As Long
        
        Const DebugMode As Boolean = True
        
        IE_Download_File_Using_UIAutomation = True
        downloadResult = ""
        
        'If specified, ensure folder ends with \
        
        If saveInFolder <> "" And Right(saveInFolder, 1) <> "" Then saveInFolder = saveInFolder & ""
        
        'Create main UIAutomation object
        
        Set UIAutomation = New CUIAutomation
        
        'Find the IE11 Frame Notification Bar, waiting until it exists
        
        Do
            hWnd = FindWindowEx(IEhwnd, 0, "Frame Notification Bar", vbNullString)
            DoEvents
            Sleep 200
        Loop While hWnd = 0
        If DebugMode Then Debug.Print Time; "Frame Notification Bar " & hWnd
    
        'Get the Frame Notification Bar pane from the window frame
        'Class         = Frame Notification Bar
        'Ctrl type     = UIA_PaneControlTypeId
    
        Set FrameNotificationBarPane = UIAutomation.ElementFromHandle(ByVal hWnd)
        'DumpElement FrameNotificationBarPane
            
        If DebugMode Then
            With Worksheets(1)
                .Cells.Clear
                Set destCell = .Range("A1")
            End With
            destCell.Value = "  FrameNotificationBarPane children"
            numRows = UIElements_To_Cells(UIAutomation, FrameNotificationBarPane, destCell.Offset(1))
            Set destCell = destCell.Offset(numRows + 2)
        End If
    
        'Find the Notification tool bar, a child of the Frame Notification Bar pane, waiting until it exists
        'Name:          "Notification"
        'ControlType:   UIA_ToolBarControlTypeId
    
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Notification")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ToolBarControlTypeId)
        Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
        Do
            Set NotificationToolbar = FrameNotificationBarPane.FindFirst(TreeScope_Children, NameAndType)
            Sleep 200
            If DebugMode Then Debug.Print Time; "Find Notification tool bar"
            DoEvents
        Loop While NotificationToolbar Is Nothing
        If DebugMode Then
            destCell.Value = "  NotificationToolbar children"
            numRows = UIElements_To_Cells(UIAutomation, NotificationToolbar, destCell.Offset(1))
            Set destCell = destCell.Offset(numRows + 2)
        End If
        
        'Find the Notification tool bar text element and extract the default file name from it
        'Name:          "Notification bar Text"
        'ControlType:   UIA_TextControlTypeId
        'Value.Value:   "Do you want to open or save xxxx.csv from yyyy.com?"
            
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Notification bar Text")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_TextControlTypeId)
        Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
        Set NotificationBarText = FrameNotificationBarPane.FindFirst(TreeScope_Descendants, NameAndType)
        NotificationBarTextString = NotificationBarText.GetCurrentPropertyValue(UIA_ValueValuePropertyId)
        p1 = InStr(NotificationBarTextString, "Do you want to open or save ")
        If p1 = 1 Then
            p1 = p1 + Len("Do you want to open or save ")
            p2 = InStr(p1, NotificationBarTextString, " from ")
            defaultFileName = Mid(NotificationBarTextString, p1, p2 - p1)
        Else
            defaultFileName = ""
        End If
        
        'Get 2nd split button, which is the Down arrow next to Save in the Notification tool bar
        
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_SplitButtonControlTypeId)
        Set SplitButtons = NotificationToolbar.FindAll(TreeScope_Descendants, ControlType)
        Set DownArrow = SplitButtons.GetElement(1)
            
        'When the Down arrow is clicked, 3 items are displayed: Save; Save as; Save and open.  These 3 items are children of an element
        'with the following properties:
        '
        'Name:          "Context"
        'ControlType:   UIA_MenuControlTypeId
        '
        'IMPORTANT - this Context menu is a child of the Desktop element, NOT the Notification tool bar, nor the Down arrow
        
        'Create criteria to find the Context menu
        
        Set DesktopRoot = UIAutomation.GetRootElement
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Context")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_MenuControlTypeId)
        Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
           
        'Click the Down arrow repeatedly, until the Context menu, containing the 3 items (Save; Save as; Save and open) exists.
        'Note - Because the Context menu is a child of the Desktop element, the FindFirst call specifies TreeScope_Children,
        'not TreeScope_Descendants, to reduce the number of elements searched.
        'See https://docs.microsoft.com/en-us/win...ment-findfirst
        
        Set InvokePattern = DownArrow.GetCurrentPattern(UIA_InvokePatternId)
        Do
            DownArrow.SetFocus
            InvokePattern.Invoke
            DoEvents
            Sleep 200
            Set ContextMenu = DesktopRoot.FindFirst(TreeScope_Children, NameAndType)
        Loop While ContextMenu Is Nothing
        
        If DebugMode Then
            destCell.Value = "  ContextMenu children"
            numRows = UIElements_To_Cells(UIAutomation, ContextMenu, destCell.Offset(1))
            Set destCell = destCell.Offset(numRows + 2)
        End If
            
        'Find the Save as item in the Context menu
        'Name:          "Save as"
        'ControlType:   UIA_MenuItemControlTypeId
        
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Save as")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_MenuItemControlTypeId)
        Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
        Set SaveAsMenuItem = ContextMenu.FindFirst(TreeScope_Children, NameAndType)
            
        'Click the Save as item to display the Save As dialogue window
        
        Set InvokePattern = SaveAsMenuItem.GetCurrentPattern(UIA_InvokePatternId)
        InvokePattern.Invoke
        
        'Find the Save As dialogue window, which is a child of the Desktop, looping until it exists.
        'Again, the FindFirst specifies TreeScope_Children to reduce the number of elements searched.
        'Name:          "Save As"
        'ControlType:   UIA_WindowControlTypeId
        
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Save As")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_WindowControlTypeId)
        Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
        Do
            Set SaveAsWindow = DesktopRoot.FindFirst(TreeScope_Children, NameAndType)
            DoEvents
            Sleep 100
        Loop While SaveAsWindow Is Nothing
                
        If DebugMode Then
            destCell.Value = "  SaveAsWindow children"
            numRows = UIElements_To_Cells(UIAutomation, SaveAsWindow, destCell.Offset(1))
            Set destCell = destCell.Offset(numRows + 2)
        End If
                
        'If the caller has specified either the folder or the file name, then populate the file name input box in the Save As window
        
        If saveInFolder <> "" Or saveAsFileName <> "" Then
        
            If saveAsFileName = "" Then
                'The caller has not specified the file name, so use the default file name from the Notification bar
                saveAsFileName = defaultFileName
            Else
                'If the caller has not specified an extension in the file name, append the extension from the default file name
                p1 = InStrRev(saveAsFileName, ".")
                If p1 = 0 Then
                    saveAsFileName = saveAsFileName & Mid(defaultFileName, InStrRev(defaultFileName, "."))
                ElseIf p1 = Len(saveAsFileName) Then
                    saveAsFileName = saveAsFileName & Mid(defaultFileName, InStrRev(defaultFileName, ".") + 1)
                End If
            End If
            
            'Construct the full file name
            
            fullFileName = saveInFolder & saveAsFileName
            
            'Create criteria to find the file name input box, which is a child of the Save As window
            'Name:          "File name:"
            'ControlType:   UIA_EditControlTypeId
        
            Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "File name:")
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_EditControlTypeId)
            Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
            'Find the file name input box
            
            Set FileNameInput = SaveAsWindow.FindFirst(TreeScope_Descendants, NameAndType)
            
            'Put the full file name in the input box, using IUIAutomationValuePattern
    
            Set FileNameInputPattern = FileNameInput.GetCurrentPattern(UIA_ValuePatternId)
            FileNameInput.SetFocus
            FileNameInputPattern.SetValue fullFileName
            
            'Alternative code to put the full file name in the input box using IUIAutomationLegacyIAccessiblePattern.
            'Same effect as using UIA_ValuePatternId above.
            '
            'Set FileNameInputPatternLegacy = FileNameInput.GetCurrentPattern(UIA_LegacyIAccessiblePatternId)
            'FileNameInputPatternLegacy.Select 1 '1=SELFLAG_TAKEFOCUS
            'FileNameInputPatternLegacy.SetValue fullFileName
            
            'If the Save button is clicked now, the Save As thinks the default file name is still being used.
            'To overcome this, and use the specified file name, we put a single space at the start of the input box with SendKeys
            
            SendKeys " ", True          'press space key
                 
        Else
        
            'The caller has specified neither the folder nor the file name, so use the default file name provided by the remote site.
            'The file, if downloaded, will be saved in IE's default download folder
            
            fullFileName = defaultFileName
        
        End If
        
        'Create criteria to find the Save button
        'Name:          "Save"
        'ControlType:   UIA_ButtonControlTypeId
        
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Save")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
        Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
        
        'Find the Save button, a child of the Save As window
        
        Set Button = SaveAsWindow.FindFirst(TreeScope_Children, NameAndType)
            
        'Click the Save button
        
        Button.SetFocus
        Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
        InvokePattern.Invoke
        If DebugMode Then Debug.Print Time; "Save clicked"
            
        'Logical steps after clicking the Save button
        '
        'Find the Confirm Save As window, if it exists
        'If the Confirm Save As window was found Then
        '   If replaceExistingFile Then
        '       Click Yes
        '       downloaded = True
        '   Else
        '       Click No
        '       Click Cancel in Notification Bar
        '       downloaded = False
        '   End If
        'Else
        '   downloaded = True
        'End If
        'If downloaded Then
        '   Wait until Notification Bar contains "download has completed"
        '   Extract downloaded file name from Notification Bar
        'End If
        'Close Notification Bar
            
        
        'Create criteria to find the Confirm Save As dialogue window, if it exists
        'Name:          "Confirm Save As"
        'ControlType:   UIA_WindowControlTypeId
        
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Confirm Save As")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_WindowControlTypeId)
        Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
        'Find the Confirm Save As window, a child of the Save As window, waiting a maximum of 3 seconds
        
        timeout = DateAdd("s", 3, Now)
        Do
            Set ConfirmSaveAsWindow = SaveAsWindow.FindFirst(TreeScope_Children, NameAndType)
            Sleep 200
            If DebugMode Then Debug.Print Time; "Find Confirm Save As"
            DoEvents
        Loop While ConfirmSaveAsWindow Is Nothing And Now < timeout
           
        If Not ConfirmSaveAsWindow Is Nothing Then
            
            'The Confirm Save As window exists, so click the Yes or No button depending on the replaceExistingFile flag
        
            If replaceExistingFile Then
            
                'Criteria to find Yes button
                'Name:          "Yes"
                'ControlType:   UIA_ButtonControlTypeId
                
                Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Yes")
                Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
                Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
                'Find the Yes button
                
                Set Button = ConfirmSaveAsWindow.FindFirst(TreeScope_Children, NameAndType)
            
                'Click the Yes button
                
                Button.SetFocus
                Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
                InvokePattern.Invoke
                If DebugMode Then Debug.Print Time; "Yes clicked"
            
                downloaded = True
    
            Else 'replaceExistingFile = False
            
                'Extract the text warning from the Confirm Save As window
                
                Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_TextControlTypeId)
                Set ConfirmSaveAsWindowText = ConfirmSaveAsWindow.FindFirst(TreeScope_Children, ControlType)
                ConfirmSaveAsWindowTextString = ConfirmSaveAsWindowText.GetCurrentPropertyValue(UIA_NamePropertyId)
            
                'Criteria to find No button
                'Name:          "No"
                'ControlType:   UIA_ButtonControlTypeId
                
                Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "No")
                Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
                Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
                'Find the No button, waiting until it exists
                
                Set Button = ConfirmSaveAsWindow.FindFirst(TreeScope_Children, NameAndType)
            
                'Click the No button
                
                Button.SetFocus
                Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
                InvokePattern.Invoke
                If DebugMode Then Debug.Print Time; "No clicked"
                            
                downloadResult = fullFileName & " NOT DOWNLOADED - " & ConfirmSaveAsWindowTextString & " - replaceExistingFile = False"
                IE_Download_File_Using_UIAutomation = False
                
            End If
        
        Else
        
            'The Confirm Save As window doesn't exist.  This means that either the file was downloaded, or a Save As warning is
            'being displayed, giving the reason why it was not downloaded.
            
            'Criteria to find Save As warning window
            'Name:          "Save As"
            'ControlType:   UIA_WindowControlTypeId
            
            Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Save As")
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_WindowControlTypeId)
            Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
    
            'Find the Save As warning window - a child of the main Save As window
    
            Set SaveAsWarningWindow = SaveAsWindow.FindFirst(TreeScope_Children, NameAndType)
            
            If Not SaveAsWarningWindow Is Nothing Then
            
                'The Save As warning window exists, so extract the text warning from it
                
                Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_TextControlTypeId)
                Set SaveAsWarningText = SaveAsWarningWindow.FindFirst(TreeScope_Children, ControlType)
                SaveAsWarningTextString = SaveAsWarningText.GetCurrentPropertyValue(UIA_NamePropertyId)
                
                'Create criteria to find the OK button in the Save As warning window
                'Name:          "OK"
                'ControlType:   UIA_ButtonControlTypeId
                
                Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "OK")
                Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
                Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
                
                'Find the OK button - a child of the Save As warning window
                
                Set Button = SaveAsWarningWindow.FindFirst(TreeScope_Children, NameAndType)
                
                'Click the OK button
                
                Button.SetFocus
                Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
                InvokePattern.Invoke
                If DebugMode Then Debug.Print Time; "OK clicked"
                
                IE_Download_File_Using_UIAutomation = False
                downloadResult = fullFileName & " - NOT DOWNLOADED - " & SaveAsWarningTextString
                
            Else
            
                'The Save As warning window doesn't exist, so the file was downloaded
                
                IE_Download_File_Using_UIAutomation = True
                
            End If
                
        End If
        
        If IE_Download_File_Using_UIAutomation = True Then
        
            If DebugMode Then
                destCell.Value = "  FrameNotificationBarPane children"
                numRows = UIElements_To_Cells(UIAutomation, FrameNotificationBarPane, destCell.Offset(1))
                Set destCell = destCell.Offset(numRows + 2)
            End If
        
            'Create criteria to find the "Notification bar Text" element
            'Name:          "Notification bar Text"
            'ControlType:   UIA_TextControlTypeId
            'Value.Value:   The xxxx yyyy.zzz download has completed.
            
            Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Notification bar Text")
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_TextControlTypeId)
            Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
            'Find the Notification bar Text element in the Frame Notification Bar pane and wait until it contains "download has completed"
            
            NotificationBarTextString = ""
            Do
                Set NotificationBarText = FrameNotificationBarPane.FindFirst(TreeScope_Descendants, NameAndType)
                Sleep 200
                DoEvents
                If Not NotificationBarText Is Nothing Then
                    NotificationBarTextString = NotificationBarText.GetCurrentPropertyValue(UIA_ValueValuePropertyId)
                End If
                If DebugMode Then Debug.Print Time; NotificationBarTextString
            Loop Until InStr(NotificationBarTextString, "download has completed")
    
            'Extract file name from Notification bar text, e.g. "The xxxx yyyy.zzz download has completed."
            
            p1 = InStr(NotificationBarTextString, "The ") + Len("The ")
            p2 = InStr(p1, NotificationBarTextString, " download has completed")
            
            Debug.Print "Notification Bar downloaded = " & Mid(NotificationBarTextString, p1, p2 - p1)
            Debug.Print "Full file name = " & fullFileName
            downloadResult = fullFileName & " - SUCCESSFULLY DOWNLOADED"
            
        Else
        
            'Not downloaded, so click the Cancel button in the Save As window
                
            'Create criteria to find the Cancel button in the Save As window
            'Name:          "Cancel"
            'ControlType:   UIA_ButtonControlTypeId
            
            Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Cancel")
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
            Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
            'Find the Cancel button, waiting until it exists
            
            Set Button = SaveAsWindow.FindFirst(TreeScope_Children, NameAndType)
            
            'Click the Cancel button
            
            Button.SetFocus
            Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
            InvokePattern.Invoke
            If DebugMode Then Debug.Print Time; "Cancel clicked"
    
        End If
                 
        'Create criteria to find the Close (X) button on the Notification pane
        'Name:          "Close"
        'ControlType:   UIA_ButtonControlTypeId
        
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Close")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
        Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
        'Find the Close button in the IE Download Notification Bar
        
        Set Button = FrameNotificationBarPane.FindFirst(TreeScope_Descendants, NameAndType)
        
        'Click the Close button
        
        Button.SetFocus
        Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
        InvokePattern.Invoke
        If DebugMode Then Debug.Print Time; "Close clicked"
                     
    End Function
    
    
    'This finds all TabItemControls of the IE element and loops through them looking for the tab item whose CurrentName property matches the specified tab name.
    'If found, it activates that tab.  Uses the Like operator, so wildcards can be used (see - https://docs.microsoft.com/en-us/off.../like-operator)
    'to specify the tab name to be found and activated.
    'This is useful because sometimes although the visible the tab name - shown when hovering over the tab - may be "xxxxx", the actual tab name
    'according to UIAutomation is "xxxxx Tab Group 1".
    
    #If  VBA7 Then
    Public Sub IE_Click_Tab_Like(IEhwnd As LongPtr, findTabName As String)
    #Else 
    Public Sub IE_Click_Tab_Like(IEhwnd As Long, findTabName As String)
    #End  If
       
        Dim UIauto As IUIAutomation
        Dim IEwindow As IUIAutomationElement, IEtab As IUIAutomationElement
        Dim IEtabs As IUIAutomationElementArray
        Dim tabItemCondition As IUIAutomationCondition
        Dim IEtabPattern As IUIAutomationLegacyIAccessiblePattern
        Dim i As Long
        
        'Create UIAutomation object
        
        Set UIauto = New CUIAutomation
        
        'Get Internet Explorer UIAutomation element
        
        Set IEwindow = UIauto.ElementFromHandle(ByVal IEhwnd)
        
        'Create condition to find a TabItemControl
        
        Set tabItemCondition = UIauto.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_TabItemControlTypeId)
     
        'Find all tabs
        
        Set IEtabs = IEwindow.FindAll(TreeScope_Descendants, tabItemCondition)
        
        'Look for the tab which matches the specified tab name
        
        Set IEtab = Nothing
        i = 0
        While i < IEtabs.Length And IEtab Is Nothing
            Debug.Print i; IEtabs.GetElement(i).CurrentName
            If LCase(IEtabs.GetElement(i).CurrentName) Like LCase(findTabName) Then Set IEtab = IEtabs.GetElement(i)
            i = i + 1
        Wend
            
        If Not IEtab Is Nothing Then
        
            'Access the legacy pattern of the IE tab, which has the DoDefaultAction method (Click)
        
            Set IEtabPattern = IEtab.GetCurrentPattern(UIA_LegacyIAccessiblePatternId)
            IEwindow.SetFocus   'optional - brings the IE window to the foreground
            IEtabPattern.DoDefaultAction
        
        Else
        
            MsgBox "IE tab with name '" & findTabName & "' not found"
            
        End If
            
        Set IEtabPattern = Nothing
        Set IEtab = Nothing
        Set IEwindow = Nothing
        Set UIauto = Nothing
        
    End Sub
    
    
    Public Sub DumpElement(UIAutoElem As IUIAutomationElement)
        Dim ct As Long
        ct = Get_UIA_PropertyValue(UIAutoElem, UIA_ControlTypePropertyId)
        Debug.Print "----------------"
        Debug.Print "Name                 = " & Get_UIA_PropertyValue(UIAutoElem, UIA_NamePropertyId)
        Debug.Print "Class                = " & Get_UIA_PropertyValue(UIAutoElem, UIA_ClassNamePropertyId)
        Debug.Print "ControlType          = " & Get_UIA_ControlType(ct) & " (0x" & Hex(ct) & ")"
        Debug.Print "LocalisedControlType = " & Get_UIA_PropertyValue(UIAutoElem, UIA_LocalizedControlTypePropertyId)
        Debug.Print "Value                = " & Get_UIA_PropertyValue(UIAutoElem, UIA_ValueValuePropertyId)
        Debug.Print "Handle               = " & Get_UIA_PropertyValue(UIAutoElem, UIA_NativeWindowHandlePropertyId)
        Debug.Print "AccessKey            = " & Get_UIA_PropertyValue(UIAutoElem, UIA_AccessKeyPropertyId)
        Debug.Print "DefaultAction        = " & Get_UIA_PropertyValue(UIAutoElem, UIA_LegacyIAccessibleDefaultActionPropertyId)
        Debug.Print "Description          = " & Get_UIA_PropertyValue(UIAutoElem, UIA_FullDescriptionPropertyId)
        Debug.Print "NativeWindowHandle   = " & "0x" & Hex(Get_UIA_PropertyValue(UIAutoElem, UIA_NativeWindowHandlePropertyId))
    End Sub
    
    
    'Get property value for a UI element
    Private Function Get_UIA_PropertyValue(UIAutoElem As IUIAutomationElement, propertyId As Long)
        
        Dim tVal As Variant
        Dim tStr As String, i As Integer
        
        tVal = UIAutoElem.GetCurrentPropertyValue(propertyId)
        
        If IsArray(tVal) Then
            tStr = tVal(0)
            For i = 1 To UBound(tVal)
                tStr = tStr & "; " & tVal(i)
            Next
            Get_UIA_PropertyValue = tStr
        Else
            Get_UIA_PropertyValue = tVal
        End If
        
    End Function
    
    
    'Convert a UI property id to its constant name
    Private Function Get_UIA_ControlType(propertyId As Long) As String
    
        Dim cn As String
        
        Select Case propertyId
            Case 50040: cn = "UIA_AppBarControlTypeId"
            Case 50000: cn = "UIA_ButtonControlTypeId"
            Case 50001: cn = "UIA_CalendarControlTypeId"
            Case 50002: cn = "UIA_CheckBoxControlTypeId"
            Case 50003: cn = "UIA_ComboBoxControlTypeId"
            Case 50025: cn = "UIA_CustomControlTypeId"
            Case 50028: cn = "UIA_DataGridControlTypeId"
            Case 50029: cn = "UIA_DataItemControlTypeId"
            Case 50030: cn = "UIA_DocumentControlTypeId"
            Case 50004: cn = "UIA_EditControlTypeId"
            Case 50026: cn = "UIA_GroupControlTypeId"
            Case 50034: cn = "UIA_HeaderControlTypeId"
            Case 50035: cn = "UIA_HeaderItemControlTypeId"
            Case 50005: cn = "UIA_HyperlinkControlTypeId"
            Case 50006: cn = "UIA_ImageControlTypeId"
            Case 50008: cn = "UIA_ListControlTypeId"
            Case 50007: cn = "UIA_ListItemControlTypeId"
            Case 50010: cn = "UIA_MenuBarControlTypeId"
            Case 50009: cn = "UIA_MenuControlTypeId"
            Case 50011: cn = "UIA_MenuItemControlTypeId"
            Case 50033: cn = "UIA_PaneControlTypeId"
            Case 50012: cn = "UIA_ProgressBarControlTypeId"
            Case 50013: cn = "UIA_RadioButtonControlTypeId"
            Case 50014: cn = "UIA_ScrollBarControlTypeId"
            Case 50039: cn = "UIA_SemanticZoomControlTypeId"
            Case 50038: cn = "UIA_SeparatorControlTypeId"
            Case 50015: cn = "UIA_SliderControlTypeId"
            Case 50016: cn = "UIA_SpinnerControlTypeId"
            Case 50031: cn = "UIA_SplitButtonControlTypeId"
            Case 50017: cn = "UIA_StatusBarControlTypeId"
            Case 50018: cn = "UIA_TabControlTypeId"
            Case 50019: cn = "UIA_TabItemControlTypeId"
            Case 50036: cn = "UIA_TableControlTypeId"
            Case 50020: cn = "UIA_TextControlTypeId"
            Case 50027: cn = "UIA_ThumbControlTypeId"
            Case 50037: cn = "UIA_TitleBarControlTypeId"
            Case 50021: cn = "UIA_ToolBarControlTypeId"
            Case 50022: cn = "UIA_ToolTipControlTypeId"
            Case 50023: cn = "UIA_TreeControlTypeId"
            Case 50024: cn = "UIA_TreeItemControlTypeId"
            Case 50032: cn = "UIA_WindowControlTypeId"
            Case Else: cn = "UNKNOWN"
        End Select
        
        Get_UIA_ControlType = cn
        
    End Function
    
    
    'Recursively walk the hierarchy of UIAutomationElements starting at the specified parent element and output UI elements to Excel cells.
    
    Public Function UIElements_To_Cells(UIAutomation As IUIAutomation, parentElement As IUIAutomationElement, destCell As Range) As Long
    
        Dim n As Long
        Dim sibling As Long
        Static TreeWalker As IUIAutomationTreeWalker
        Dim childElement As IUIAutomationElement
        Dim ct As Long
        
        n = 0
        
        If Not parentElement Is Nothing Then
        
            'Any of these tree walkers can be used
            'If TreeWalker Is Nothing Then Set TreeWalker = UIAutomation.RawViewWalker
            If TreeWalker Is Nothing Then Set TreeWalker = UIAutomation.ControlViewWalker
            'If TreeWalker Is Nothing Then Set TreeWalker = UIAutomation.ContentViewWalker
            
            Set childElement = TreeWalker.GetFirstChildElement(parentElement)
            sibling = 0
            While Not childElement Is Nothing
                ct = Get_UIA_PropertyValue(childElement, UIA_ControlTypePropertyId)
                sibling = sibling + 1
                Debug.Print "-- Sibling " & sibling
                Debug.Print "Name                 = " & Get_UIA_PropertyValue(childElement, UIA_NamePropertyId)
                Debug.Print "Class                = " & Get_UIA_PropertyValue(childElement, UIA_ClassNamePropertyId)
                Debug.Print "ControlType          = " & Get_UIA_ControlType(ct) & " (0x" & Hex(ct) & ")"
                Debug.Print "LocalisedControlType = " & Get_UIA_PropertyValue(childElement, UIA_LocalizedControlTypePropertyId)
                Debug.Print "Value                = " & Get_UIA_PropertyValue(childElement, UIA_ValueValuePropertyId)
                Debug.Print "Handle               = 0x" & Hex(Get_UIA_PropertyValue(childElement, UIA_NativeWindowHandlePropertyId))
                Debug.Print "AccessKey            = " & Get_UIA_PropertyValue(childElement, UIA_AccessKeyPropertyId)
                Debug.Print "DefaultAction        = " & Get_UIA_PropertyValue(childElement, UIA_LegacyIAccessibleDefaultActionPropertyId)
                Debug.Print "Description          = " & Get_UIA_PropertyValue(childElement, UIA_FullDescriptionPropertyId)
                destCell.Offset(n + 0).Value = "'-- Sibling " & sibling
                destCell.Offset(n + 1).Value = "Name = " & Get_UIA_PropertyValue(childElement, UIA_NamePropertyId)
                destCell.Offset(n + 2).Value = "Class = " & Get_UIA_PropertyValue(childElement, UIA_ClassNamePropertyId)
                destCell.Offset(n + 3).Value = "ControlType = " & Get_UIA_ControlType(ct) & " (0x" & Hex(ct) & ")"
                destCell.Offset(n + 4).Value = "LocalisedControlType = " & Get_UIA_PropertyValue(childElement, UIA_LocalizedControlTypePropertyId)
                destCell.Offset(n + 5).Value = "Value = " & Get_UIA_PropertyValue(childElement, UIA_ValueValuePropertyId)
                destCell.Offset(n + 6).Value = "Handle = 0x" & Hex(Get_UIA_PropertyValue(childElement, UIA_NativeWindowHandlePropertyId))
                destCell.Offset(n + 7).Value = "AccessKey = " & Get_UIA_PropertyValue(childElement, UIA_AccessKeyPropertyId)
                destCell.Offset(n + 8).Value = "DefaultAction = " & Get_UIA_PropertyValue(childElement, UIA_LegacyIAccessibleDefaultActionPropertyId)
                destCell.Offset(n + 9).Value = "Description = " & Get_UIA_PropertyValue(childElement, UIA_FullDescriptionPropertyId)
                
                n = n + 10 + UIElements_To_Cells(UIAutomation, childElement, destCell.Offset(n + 10, 1))
                
                Set childElement = TreeWalker.GetNextSiblingElement(childElement)
            Wend
        
        End If
        
        UIElements_To_Cells = n
    
    End Function
    
    
    Private Function Get_IE_Window(URL As String) As InternetExplorer
    
        'Look for an IE browser window or tab already open at the domain of the specified URL (which can start with http://, https://
        'or nothing) and, if found, return that browser as an InternetExplorer object.  Otherwise return Nothing
    
        Dim domain As String
        Dim Shell As Object
        Dim IE As InternetExplorer
        Dim i As Variant 'Must be a Variant to index Shell.Windows.Item() array
        Dim p1 As Integer, p2 As Integer
        
        p1 = InStr(URL, "://")
        If p1 = 0 Then
            p1 = 1
        Else
            p1 = p1 + 3
        End If
        p2 = InStr(p1, URL, "/")
        If p2 = 0 Then p2 = Len(URL) + 1
        domain = Mid(URL, p1, p2 - p1)
        
        Set Shell = CreateObject("Shell.Application")
        
        i = 0
        Set Get_IE_Window = Nothing
        While i < Shell.Windows.Count And Get_IE_Window Is Nothing
            Set IE = Shell.Windows.Item(i)
            If Not IE Is Nothing Then
                If TypeName(IE.document) = "HTMLDocument" Then
                    If InStr(IE.LocationURL, domain) > 0 Then
                        Set Get_IE_Window = IE
                    End If
                End If
            End If
            i = i + 1
        Wend
         
    End Function

  2. #2
    Board Regular Kyle123's Avatar
    Join Date
    Jan 2012
    Location
    Leeds, UK
    Posts
    2,642
    Post Thanks / Like
    Mentioned
    10 Post(s)
    Tagged
    2 Thread(s)

    Default Re: Using UIAutomationClient to automate the Save As file download in IE11

    My god that's a lot of code :shocked: - it must have taken you ages

    It doesn't actually work for me though. It identifies the download bar, clicks save as, opens the save as dialog and then gets stuck in a loop waiting for input (in here: Function UIElements_To_Cells)

    I'm intrigued as to your reason for this epic amount of work, as I know you know full well how to download things from the internet "properly" without automating IE
    Last edited by Kyle123; Feb 7th, 2019 at 12:34 PM.

  3. #3
    Board Regular
    Join Date
    Oct 2007
    Posts
    5,857
    Post Thanks / Like
    Mentioned
    8 Post(s)
    Tagged
    2 Thread(s)

    Default Re: Using UIAutomationClient to automate the Save As file download in IE11

    Yes, it's certainly a lot of code! It was simply a development exercise to see if it could be done, because I've never seen UIAutomation used this way before.

    Using Microsoft's Inspect.exe tool, I discovered that the Save As option is in a context menu which is a child of the Desktop element, not the Download Toolbar, as you might expect. I also spent some time trying different methods to fix the issue with the input file name not being 'taken' by the download. You can turn off the calls the UIElements_To_Cells by setting the DebugMode Const to False, but I don't know why it's waiting for input.

    Although this was a lot of work initially, callng this function would probably be easier and far less work than writing custom code to download using XMLhttp requests.

  4. #4
    Board Regular Kyle123's Avatar
    Join Date
    Jan 2012
    Location
    Leeds, UK
    Posts
    2,642
    Post Thanks / Like
    Mentioned
    10 Post(s)
    Tagged
    2 Thread(s)

    Default Re: Using UIAutomationClient to automate the Save As file download in IE11

    Fairy nuff, I can see why it would be useful to point people to on forums, guiding them through doing it the proper way is often impossible. I'm not sure it's easier to do the if you know what you're doing though as you're likely needing to change code whether automating IE or direct requests for each site anyway. I often find it easier to use winhttp rather than xmlhttp too due to the additional authentication options and automatic cookie handling.

    Nevertheless - great work
    Last edited by Kyle123; Feb 7th, 2019 at 03:46 PM.

  5. #5
    Board Regular
    Join Date
    Oct 2007
    Posts
    5,857
    Post Thanks / Like
    Mentioned
    8 Post(s)
    Tagged
    2 Thread(s)

    Default Re: Using UIAutomationClient to automate the Save As file download in IE11

    Thanks

    You're right about WinHttp. My default method is usually XMLhttp for simple requests, however one disadvantage is that it hides cookies in the response, whereas WinHttp provides them in the Set-Cookie headers.

    Another thing, which you probably know about, is that the following is needed when using Fiddler to capture the WinHttp requests and responses:

    Code:
    Const HTTPREQUEST_PROXYSETTING_PROXY = 2
    WinHttp.SetProxy HTTPREQUEST_PROXYSETTING_PROXY, "127.0.0.1:8888"

  6. #6
    Board Regular Kyle123's Avatar
    Join Date
    Jan 2012
    Location
    Leeds, UK
    Posts
    2,642
    Post Thanks / Like
    Mentioned
    10 Post(s)
    Tagged
    2 Thread(s)

    Default Re: Using UIAutomationClient to automate the Save As file download in IE11

    I don't really use fiddler - I just use Chrome dev tools for that.

    That's not quite what I meant with the cookies, winhttp will automatically send received cookies with each request, with xml you need to add them manually. This is especially useful for scraping pages which require logging in, once you have the authenticated session cookie, winhttp just sends it automatically - xml doesn't. I tend to use xml on forums though as it has fewer issues with corporate networks, winhttp sometimes requires fiddling with for some posters on the forum; xml request also allows for more asynchronousity.

  7. #7
    Board Regular
    Join Date
    Oct 2007
    Posts
    5,857
    Post Thanks / Like
    Mentioned
    8 Post(s)
    Tagged
    2 Thread(s)

    Default Re: Using UIAutomationClient to automate the Save As file download in IE11

    Here is a list of useful links for UI Automation:

    UI Automation introduction
    https://docs.microsoft.com/en-gb/win...y-uiauto-win32

    UI Automation Fundamentals
    https://docs.microsoft.com/en-us/win...ocore-overview

    UI Automation Client Programmer's Guide
    https://docs.microsoft.com/en-us/win...o-clientportal

    An introduction to UI Automation
    http://blog.functionalfun.net/2009/0...tion-with.html

    Introduction to UIA: Microsoft's Accessibility API, including using Inspect tool
    https://www.youtube.com/watch?v=6b0K2883rXA

    How to install the Inspect tool on Windows 10?
    https://stackoverflow.com/questions/...-on-windows-10

  8. #8
    New Member
    Join Date
    Oct 2013
    Posts
    20
    Post Thanks / Like
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Default Re: Using UIAutomationClient to automate the Save As file download in IE11

    Thanks a lot John.

    So you soon with other scenario.

    Cheers!
    Raj

  9. #9
    Board Regular
    Join Date
    Oct 2007
    Posts
    5,857
    Post Thanks / Like
    Mentioned
    8 Post(s)
    Tagged
    2 Thread(s)

    Default Re: Using UIAutomationClient to automate the Save As file download in IE11

    Update

    I have come across some websites where, when a file download is offered, IE11 displays a dialogue asking "What do you want to do with xxxxx.xxx?", instead of the normal Download Notification Bar at the bottom of the window. Here's an example:



    To see this dialogue follow these steps:

    1. In IE, open website https://www.abs.gov.au/Price-Indexes-and-Inflation
    2. Click on link “Consumer Price Index” on that page.
    3. Click on “Download” tab on that page.
    4. Click on any of the green ".xls" links on that page.

    (Thread ref. https://www.mrexcel.com/forum/excel-...st5344650.html)

    See below for my analysis of this issue and why the dialogue is displayed.

    Here is the updated VBA UIAutomation code which handles both this dialogue and the Download Notification Bar.

    Code:
    #If VBA7 Then
    Public Function IE_Download_File_Using_UIAutomation(IEhwnd As LongPtr, ByVal saveInFolder As String, ByVal saveAsFileName As String, ByVal replaceExistingFile As Boolean, ByRef downloadResult As String) As Boolean
    #Else 
    Public Function IE_Download_File_Using_UIAutomation(IEhwnd As Long, ByVal saveInFolder As String, ByVal saveAsFileName As String, ByVal replaceExistingFile As Boolean, ByRef downloadResult As String) As Boolean
    #End  If
    
        'Automate IE11's Download Notification Bar (and 'What do you want to do with xxxx.xx?' dialogue window) in the active tab, by clicking the Save As item,
        'downloading the file and closing the Notification Bar.  The IE option 'Notify when downloads complete' must be enabled.
        '
        'Parameters:
        'IEhwnd                 The handle of the IE window. The Download Notification Bar must be displayed in the active tab.
        '                       If necessary, call IE_Click_Tab_Like to activate the required tab before calling this function.
        'saveInFolder           The folder path where the downloaded file will be saved.  Specify "" to save the file in IE's default download folder.
        'saveAsFileName         The file name which the downloaded file will be given.  Specify "" to use the file name provided by the web site.
        'replaceExistingFile    True to replace the file if it already exists; False to overwrite the file
        'downloadResult         Output string returned to the caller showing whether the file was successfully download or not, including the file name of the
        '                       downloaded file (including its path if saveInFolder was specified).
        '
        'Function return value  True: the file was downloaded; False: the file was not downloaded
        
        Dim UIAutomation As IUIAutomation
        Dim IEmain As IUIAutomationElement
        Dim IEdialogue As IUIAutomationElement
        Dim IEdialogueText As IUIAutomationElement
        Dim IEdialogueSaveAsButton As IUIAutomationElement
        Dim searchSaveAsWindowFrom As IUIAutomationElement
        Dim DesktopRoot As IUIAutomationElement
        Dim NotificationToolbar As IUIAutomationElement
        Dim Button As IUIAutomationElement
        Dim NotificationBarText As IUIAutomationElement
        Dim SplitButtons As IUIAutomationElementArray
        Dim DownArrow As IUIAutomationElement
        Dim InvokePattern As IUIAutomationInvokePattern
        Dim ContextMenu As IUIAutomationElement
        Dim SaveAsMenuItem As IUIAutomationElement
        Dim SaveAsWindow As IUIAutomationElement
        Dim FileNameInput As IUIAutomationElement
        Dim FileNameInputPattern As IUIAutomationValuePattern, FileNameInputPatternLegacy As IUIAutomationLegacyIAccessiblePattern
        Dim ConfirmSaveAsWindow As IUIAutomationElement
        Dim ConfirmSaveAsWindowText As IUIAutomationElement
        Dim SaveAsWarningWindow As IUIAutomationElement, SaveAsWarningText As IUIAutomationElement
        Dim ControlName As IUIAutomationCondition, ControlType As IUIAutomationCondition, NameAndType As IUIAutomationCondition
        Dim IEdialogueCond As IUIAutomationCondition, NotificationToolbarCond As IUIAutomationCondition
        Dim TreeWalker As IUIAutomationTreeWalker
        Dim defaultFileName As String, fullFileName As String
        Dim ConfirmSaveAsWindowTextString As String
        Dim SaveAsWarningTextString As String
        Dim NotificationBarTextString As String, IEdialogueTextString As String, p1 As Long, p2 As Long
        Dim timeout As Date
        Dim downloaded As Boolean
        Dim destCell As Range, numRows As Long
        
        Const DebugMode As Boolean = False
        
        'If debug mode is on then also output UI elements to the "UI debug" sheet, if it exists
        
        Set destCell = Nothing
        If DebugMode Then
            On Error Resume Next
            Set destCell = ThisWorkbook.Worksheets("UI debug").Range("A1")
            On Error GoTo 0
            If Not destCell Is Nothing Then destCell.Parent.Cells.Clear
        End If
        
        IE_Download_File_Using_UIAutomation = True
        downloadResult = ""
        
        'If specified, ensure folder ends with \
        
        If saveInFolder <> "" And Right(saveInFolder, 1) <> "" Then saveInFolder = saveInFolder & ""
        
        'Create main UIAutomation object
        
        Set UIAutomation = New CUIAutomation
        
        'Get the IE automation element from its window handle
        
        Set IEmain = UIAutomation.ElementFromHandle(ByVal IEhwnd)
        If DebugMode Then DumpElement IEmain
        
        'Conditions to find the IE Notification tool bar, a child of the main IE window
        'Name:                  "Notification"
        'ControlType:           UIA_ToolBarControlTypeId
        'LocalizedControlType:  "tool bar"
    
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Notification")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ToolBarControlTypeId)
        Set NotificationToolbarCond = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
        'If the server sends an incorrect response header, for example the misspelling of 'attachment' in:
        '
        '   Content-Disposition: attachement; filename="8d72ee3290adc3d.zip"
        '
        'then IE displays a modal dialogue box instead of the normal Download Notification Bar at the bottom of the IE window:
        '
        '   -------------------------------------------------
        '   Internet Explorer                             [X]
        '
        '   What do you want to do with xxxxx.xxx?
        '
        '   Size: 54.2 MB
        '   From: hostname.com
        '
        '   --> Open
        '       The file won't be saved automatically
        '
        '   --> Save
        '
        '   --> Save as
        '
        '                                            [Cancel]
        '   -------------------------------------------------
        
        'Conditions to find this dialogue, which is a child of the main IE window.
        'Note - the dialogue isn't a true window, so FindWindowEx(IEhwnd, 0, "Internet Explorer", vbNullString) doesn't find the dialogue.
        
        'Name:                  "Internet Explorer"
        'ControlType:           UIA_WindowControlTypeId (0xC370)
        'LocalizedControlType:  "dialogue"
        
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Internet Explorer")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_WindowControlTypeId)
        Set IEdialogueCond = UIAutomation.CreateAndCondition(ControlName, ControlType)
        
        'Wait until either the IE11 Notification tool bar exists or the "What do you want to do with xxxx.xxx?" dialogue exists
        
        Set IEdialogue = Nothing
        Set NotificationToolbar = Nothing
        Do
            'New method of finding notification bar, instead of FindWindowEx
            Set NotificationToolbar = IEmain.FindFirst(TreeScope_Descendants, NotificationToolbarCond)
            If NotificationToolbar Is Nothing Then Set IEdialogue = IEmain.FindFirst(TreeScope_Children, IEdialogueCond)
            DoEvents
            Sleep 200
        Loop While NotificationToolbar Is Nothing And IEdialogue Is Nothing
        
        If Not NotificationToolbar Is Nothing Then
        
            'The Notification tool bar exists
        
            If DebugMode Then
                'DumpElement IEmain
                DumpElement NotificationToolbar
                'Create Tree Walker to recursively traverse the automation elements for debugging purposes
                'Set TreeWalker = UIAutomation.RawViewWalker
                'ListDescendants TreeWalker, IEmain, 0, 0
                'ListDescendants TreeWalker, NotificationToolBar, 0, 0
                If Not destCell Is Nothing Then
                    destCell.Value = "  IEmain children"
                    numRows = UIElements_To_Cells(UIAutomation, IEmain, destCell.Offset(1))
                    Set destCell = destCell.Offset(numRows + 2)
                End If
                If Not destCell Is Nothing Then
                    destCell.Value = "  NotificationToolBar children"
                    numRows = UIElements_To_Cells(UIAutomation, NotificationToolbar, destCell.Offset(1))
                    Set destCell = destCell.Offset(numRows + 2)
                End If
            End If
            
            'Find the Notification tool bar text element and extract the default file name from it
            'Name:          "Notification bar Text"
            'ControlType:   UIA_TextControlTypeId
            'Value.Value:   "Do you want to open or save xxxx.csv from yyyy.com?"
                
            Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Notification bar Text")
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_TextControlTypeId)
            Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            Set NotificationBarText = NotificationToolbar.FindFirst(TreeScope_Children, NameAndType)
            NotificationBarTextString = NotificationBarText.GetCurrentPropertyValue(UIA_ValueValuePropertyId)
            p1 = InStr(NotificationBarTextString, "Do you want to open or save ")
            If p1 = 1 Then
                p1 = p1 + Len("Do you want to open or save ")
                p2 = InStr(p1, NotificationBarTextString, " from ")
                defaultFileName = Mid(NotificationBarTextString, p1, p2 - p1)
            Else
                defaultFileName = ""
            End If
            If DebugMode Then Debug.Print "Default file name = " & defaultFileName
            
            'Get 2nd split button, which is the Down arrow next to Save in the Notification tool bar
            
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_SplitButtonControlTypeId)
            Set SplitButtons = NotificationToolbar.FindAll(TreeScope_Descendants, ControlType) 'TreeScope_Descendants necessary
            Set DownArrow = SplitButtons.GetElement(1)
                
            'When the Down arrow is clicked, 3 items are displayed: Save; Save as; Save and open.  These 3 items are children of an element
            'with the following properties:
            '
            'Name:          "Context"
            'ControlType:   UIA_MenuControlTypeId
            '
            'IMPORTANT - this Context menu is a child of the Desktop element, NOT the Notification tool bar, nor the Down arrow
            
            'Create criteria to find the Context menu
            
            Set DesktopRoot = UIAutomation.GetRootElement
            Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Context")
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_MenuControlTypeId)
            Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
               
            'Click the Down arrow repeatedly, until the Context menu, containing the 3 items (Save; Save as; Save and open) exists.
            'Note - Because the Context menu is a child of the Desktop element, the FindFirst call specifies TreeScope_Children,
            'not TreeScope_Descendants, to reduce the number of elements searched.
            'See https://docs.microsoft.com/en-us/win...ment-findfirst
            
            Set InvokePattern = DownArrow.GetCurrentPattern(UIA_InvokePatternId)
            Do
                DownArrow.SetFocus
                InvokePattern.Invoke
                DoEvents
                Sleep 200
                Set ContextMenu = DesktopRoot.FindFirst(TreeScope_Children, NameAndType)
            Loop While ContextMenu Is Nothing
            
            If DebugMode Then
                If Not destCell Is Nothing Then
                    destCell.Value = "  ContextMenu children"
                    numRows = UIElements_To_Cells(UIAutomation, ContextMenu, destCell.Offset(1))
                    Set destCell = destCell.Offset(numRows + 2)
                End If
            End If
                
            'Find the Save as item in the Context menu
            'Name:          "Save as"
            'ControlType:   UIA_MenuItemControlTypeId
            
            Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Save as")
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_MenuItemControlTypeId)
            Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            Set SaveAsMenuItem = ContextMenu.FindFirst(TreeScope_Children, NameAndType)
                
            'Click the Save as item to display the Save As dialogue window
            
            Set InvokePattern = SaveAsMenuItem.GetCurrentPattern(UIA_InvokePatternId)
            InvokePattern.Invoke
            
            'Search for the Save as window, when it appears, from the Desktop root element
            
            Set searchSaveAsWindowFrom = DesktopRoot
            
        ElseIf Not IEdialogue Is Nothing Then
        
            'The IE dialogue window exists
            
            If DebugMode Then
                'DumpElement IEmain
                DumpElement IEdialogue
                'Create Tree Walker to recursively traverse the automation elements for debugging purposes
                Set TreeWalker = UIAutomation.RawViewWalker
                ListDescendants TreeWalker, IEmain, 0, 0
                ListDescendants TreeWalker, IEdialogue, 0, 0
                If Not destCell Is Nothing Then
                    destCell.Value = "  IEmain children"
                    numRows = UIElements_To_Cells(UIAutomation, IEmain, destCell.Offset(1))
                    Set destCell = destCell.Offset(numRows + 2)
                End If
                If Not destCell Is Nothing Then
                    destCell.Value = "  IEdialogue children"
                    numRows = UIElements_To_Cells(UIAutomation, IEdialogue, destCell.Offset(1))
                    Set destCell = destCell.Offset(numRows + 2)
                End If
            End If
        
            'See if the first child of the dialogue window contains the text "What do you want to do with "
            
            'Name:   "What do you want to do with 8d731f569075f6d.zip?"
            'ControlType:    UIA_TextControlTypeId (0xC364)
            'LocalizedControlType:   "text"
    
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_TextControlTypeId)
            Set IEdialogueText = IEdialogue.FindFirst(TreeScope_Children, ControlType)
            
            If Not IEdialogueText Is Nothing Then
            
                'IEdialogueTextString = IEdialogueText.GetCurrentPropertyValue(UIA_ValueValuePropertyId)  'either of these
                IEdialogueTextString = IEdialogueText.CurrentName
                p1 = InStr(IEdialogueTextString, "What do you want to do with ")
                If p1 = 1 Then
                    p1 = p1 + Len("What do you want to do with ")
                    p2 = InStr(p1, IEdialogueTextString, "?")
                    defaultFileName = Mid(IEdialogueTextString, p1, p2 - p1)
                    p1 = 1
                Else
                    defaultFileName = ""
                End If
                If DebugMode Then Debug.Print "Default file name = " & defaultFileName
            
                'Get the 'Save as' button in the dialogue
                'Name:   "Save as"
                'ControlType:    UIA_ButtonControlTypeId (0xC350)
                'LocalizedControlType:   "button"
    
                Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Save as")
                Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
                Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
                Set IEdialogueSaveAsButton = IEdialogue.FindFirst(TreeScope_Children, NameAndType)
    
                If Not IEdialogueSaveAsButton Is Nothing Then
                
                    'Click the Save as button to display the Save As dialogue window
        
                    Set InvokePattern = IEdialogueSaveAsButton.GetCurrentPattern(UIA_InvokePatternId)
                    InvokePattern.Invoke
                    
                    'Search for the Save as window, when it appears, from the main IE window element
                    
                    Set searchSaveAsWindowFrom = IEmain
                    
                End If
                
            End If
    
        End If
            
        'Find the Save As dialogue window, which is either a child of the Desktop if the Notification Bar was displayed, or a child
        'of the main IE window if the IE dialogue window was displayed, looping until it exists.
        'Again, the FindFirst specifies TreeScope_Children to reduce the number of elements searched.
        'Name:          "Save As"
        'ControlType:   UIA_WindowControlTypeId
        
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Save As")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_WindowControlTypeId)
        Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
        Do
            Set SaveAsWindow = searchSaveAsWindowFrom.FindFirst(TreeScope_Children, NameAndType)
            DoEvents
            Sleep 100
        Loop While SaveAsWindow Is Nothing
                
        If DebugMode Then
            If Not destCell Is Nothing Then
                destCell.Value = "  SaveAsWindow children"
                numRows = UIElements_To_Cells(UIAutomation, SaveAsWindow, destCell.Offset(1))
                Set destCell = destCell.Offset(numRows + 2)
            End If
        End If
                
        'If the caller has specified either the folder or the file name, then populate the file name input box in the Save As window
        
        If saveInFolder <> "" Or saveAsFileName <> "" Then
        
            If saveAsFileName = "" Then
                'The caller has not specified the file name, so use the default file name from the Notification bar
                saveAsFileName = defaultFileName
            Else
                'If the caller has not specified an extension in the file name, append the extension from the default file name
                p1 = InStrRev(saveAsFileName, ".")
                If p1 = 0 Then
                    saveAsFileName = saveAsFileName & Mid(defaultFileName, InStrRev(defaultFileName, "."))
                ElseIf p1 = Len(saveAsFileName) Then
                    saveAsFileName = saveAsFileName & Mid(defaultFileName, InStrRev(defaultFileName, ".") + 1)
                End If
            End If
            
            'Construct the full file name
            
            fullFileName = saveInFolder & saveAsFileName
            
            'Create criteria to find the file name input box, which is a child of the Save As window
            'Name:          "File name:"
            'ControlType:   UIA_EditControlTypeId
        
            Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "File name:")
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_EditControlTypeId)
            Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
            'Find the file name input box
            
            Set FileNameInput = SaveAsWindow.FindFirst(TreeScope_Descendants, NameAndType)
            
            'Put the full file name in the input box, using IUIAutomationValuePattern
    
            Set FileNameInputPattern = FileNameInput.GetCurrentPattern(UIA_ValuePatternId)
            FileNameInput.SetFocus
            FileNameInputPattern.SetValue fullFileName
            
            'Alternative code to put the full file name in the input box using IUIAutomationLegacyIAccessiblePattern
            'Same effect as using UIA_ValuePatternId above.
            '
            'Set FileNameInputPatternLegacy = FileNameInput.GetCurrentPattern(UIA_LegacyIAccessiblePatternId)
            'FileNameInputPatternLegacy.Select 1 '1=SELFLAG_TAKEFOCUS
            'FileNameInputPatternLegacy.SetValue fullFileName
            
            'If the Save button is clicked now, the Save As thinks the default file name is still being used.
            'To overcome this, and use the specified file name, we put a single space at the start of the input box with SendKeys
            
            SendKeys " ", True          'press space key
                 
        Else
        
            'The caller has specified neither the folder nor the file name, so use the default file name provided by the remote site.
            'The file, if downloaded, will be saved in IE's default download folder
            
            fullFileName = defaultFileName
        
        End If
        
        'Create criteria to find the Save button
        'Name:          "Save"
        'ControlType:   UIA_ButtonControlTypeId
        
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Save")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
        Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
        
        'Find the Save button, a child of the Save As window
        
        Set Button = SaveAsWindow.FindFirst(TreeScope_Children, NameAndType)
            
        'Click the Save button
        
        Button.SetFocus
        Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
        InvokePattern.Invoke
        If DebugMode Then Debug.Print Time; "Save clicked"
            
        'Logical steps after clicking the Save button
        '
        'Find the Confirm Save As window, if it exists
        'If the Confirm Save As window was found Then
        '   If replaceExistingFile Then
        '       Click Yes
        '       downloaded = True
        '   Else
        '       Click No
        '       Click Cancel in Notification Bar
        '       downloaded = False
        '   End If
        'Else
        '   downloaded = True
        'End If
        'If downloaded Then
        '   Wait until Notification Bar contains "download has completed"
        '   Extract downloaded file name from Notification Bar
        'End If
        'Close Notification Bar
        
        'Create criteria to find the Confirm Save As dialogue window, if it exists
        'Name:          "Confirm Save As"
        'ControlType:   UIA_WindowControlTypeId
        
        Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Confirm Save As")
        Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_WindowControlTypeId)
        Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
        'Find the Confirm Save As window, a child of the Save As window, waiting a maximum of 3 seconds
        
        timeout = DateAdd("s", 3, Now)
        Do
            Set ConfirmSaveAsWindow = SaveAsWindow.FindFirst(TreeScope_Children, NameAndType)
            DoEvents
            Sleep 200
            If DebugMode Then Debug.Print Time; "Find Confirm Save As"
        Loop While ConfirmSaveAsWindow Is Nothing And Now < timeout
           
        If Not ConfirmSaveAsWindow Is Nothing Then
            
            'The Confirm Save As window exists, so click the Yes or No button depending on the replaceExistingFile flag
        
            If replaceExistingFile Then
            
                'Criteria to find Yes button
                'Name:          "Yes"
                'ControlType:   UIA_ButtonControlTypeId
                
                Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Yes")
                Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
                Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
                'Find the Yes button
                
                Set Button = ConfirmSaveAsWindow.FindFirst(TreeScope_Children, NameAndType)
            
                'Click the Yes button
                
                Button.SetFocus
                Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
                InvokePattern.Invoke
                If DebugMode Then Debug.Print Time; "Yes clicked"
            
                downloaded = True
    
            Else 'replaceExistingFile = False
            
                'Extract the text warning from the Confirm Save As window
                
                Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_TextControlTypeId)
                Set ConfirmSaveAsWindowText = ConfirmSaveAsWindow.FindFirst(TreeScope_Children, ControlType)
                ConfirmSaveAsWindowTextString = ConfirmSaveAsWindowText.GetCurrentPropertyValue(UIA_NamePropertyId)
            
                'Criteria to find No button
                'Name:          "No"
                'ControlType:   UIA_ButtonControlTypeId
                
                Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "No")
                Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
                Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
                'Find the No button, waiting until it exists
                
                Set Button = ConfirmSaveAsWindow.FindFirst(TreeScope_Children, NameAndType)
            
                'Click the No button
                
                Button.SetFocus
                Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
                InvokePattern.Invoke
                If DebugMode Then Debug.Print Time; "No clicked"
                            
                downloadResult = fullFileName & " NOT DOWNLOADED - " & ConfirmSaveAsWindowTextString & " - replaceExistingFile = False"
                IE_Download_File_Using_UIAutomation = False
                
            End If
        
        Else
        
            'The Confirm Save As window doesn't exist.  This means that either the file was downloaded, or a Save As warning is
            'being displayed, giving the reason why it was not downloaded.
            
            'Criteria to find Save As warning window
            'Name:          "Save As"
            'ControlType:   UIA_WindowControlTypeId
            
            Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Save As")
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_WindowControlTypeId)
            Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
    
            'Find the Save As warning window - a child of the main Save As window
    
            Set SaveAsWarningWindow = SaveAsWindow.FindFirst(TreeScope_Children, NameAndType)
            
            If Not SaveAsWarningWindow Is Nothing Then
            
                'The Save As warning window exists, so extract the text warning from it
                
                Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_TextControlTypeId)
                Set SaveAsWarningText = SaveAsWarningWindow.FindFirst(TreeScope_Children, ControlType)
                SaveAsWarningTextString = SaveAsWarningText.GetCurrentPropertyValue(UIA_NamePropertyId)
                
                'Create criteria to find the OK button in the Save As warning window
                'Name:          "OK"
                'ControlType:   UIA_ButtonControlTypeId
                
                Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "OK")
                Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
                Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
                
                'Find the OK button - a child of the Save As warning window
                
                Set Button = SaveAsWarningWindow.FindFirst(TreeScope_Children, NameAndType)
                
                'Click the OK button
                
                Button.SetFocus
                Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
                InvokePattern.Invoke
                If DebugMode Then Debug.Print Time; "OK clicked"
                
                IE_Download_File_Using_UIAutomation = False
                downloadResult = fullFileName & " - NOT DOWNLOADED - " & SaveAsWarningTextString
                
            Else
            
                'The Save As warning window doesn't exist, so the file was downloaded
                
                IE_Download_File_Using_UIAutomation = True
                
            End If
                
        End If
        
        If IE_Download_File_Using_UIAutomation = True Then
        
            If DebugMode Then
                If Not destCell Is Nothing Then
                    destCell.Value = "  FrameNotificationBarPane children"
                    numRows = UIElements_To_Cells(UIAutomation, NotificationToolbar, destCell.Offset(1))
                    Set destCell = destCell.Offset(numRows + 2)
                    End If
            End If
        
            'If the file download was offered via the IE dialogue pane, rather than the normal Frame Notification Bar, then the Notification toolbar
            'is displayed as the download progresses.   Therefore get the Notification toolbar at this point
            
            If NotificationToolbar Is Nothing Then
            
                'Conditions to find the Notification tool bar, a child of the main IE window
                'Name:                  "Notification"
                'ControlType:           UIA_ToolBarControlTypeId
                'LocalizedControlType:  "tool bar"
            
                Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Notification")
                Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ToolBarControlTypeId)
                Set NotificationToolbarCond = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
                Do
                    Set NotificationToolbar = IEmain.FindFirst(TreeScope_Descendants, NotificationToolbarCond)
                    DoEvents
                    Sleep 200
                Loop While NotificationToolbar Is Nothing
            
            End If
            
            'Create criteria to find the "Notification bar Text" element
            'Name:          "Notification bar Text"
            'ControlType:   UIA_TextControlTypeId
            'Value.Value:   The xxxx yyyy.zzz download has completed.
            
            Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Notification bar Text")
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_TextControlTypeId)
            Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
            'Find the Notification bar Text element in the Frame Notification Bar pane and wait until it contains "download has completed"
            
            NotificationBarTextString = ""
            Do
                Set NotificationBarText = NotificationToolbar.FindFirst(TreeScope_Children, NameAndType)
                DoEvents
                Sleep 200
                If Not NotificationBarText Is Nothing Then
                    NotificationBarTextString = NotificationBarText.GetCurrentPropertyValue(UIA_ValueValuePropertyId)
                End If
                If DebugMode Then Debug.Print Time; NotificationBarTextString
            Loop Until InStr(NotificationBarTextString, "download has completed")
    
            'Extract file name from Notification bar text, e.g. "The xxxx yyyy.zzz download has completed."
            
            p1 = InStr(NotificationBarTextString, "The ") + Len("The ")
            p2 = InStr(p1, NotificationBarTextString, " download has completed")
            
            If DebugMode Then
                Debug.Print "Notification Bar downloaded = " & Mid(NotificationBarTextString, p1, p2 - p1)
                Debug.Print "Full file name = " & fullFileName
            End If
            downloadResult = fullFileName & " - SUCCESSFULLY DOWNLOADED"
            
        Else
        
            'Not downloaded, so click the Cancel button in the Save As window
                
            'Create criteria to find the Cancel button in the Save As window
            'Name:          "Cancel"
            'ControlType:   UIA_ButtonControlTypeId
            
            Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Cancel")
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
            Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
            
            'Find the Cancel button, waiting until it exists
            
            Set Button = SaveAsWindow.FindFirst(TreeScope_Children, NameAndType)
            
            'Click the Cancel button
            
            Button.SetFocus
            Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
            InvokePattern.Invoke
            If DebugMode Then Debug.Print Time; "Cancel clicked"
            
            'In this case, does the Notification tool bar pane exist?
    
        End If
                 
        If Not NotificationToolbar Is Nothing Then
        
            'Create criteria to find the Close (X) button on the Notification pane
            'Name:          "Close"
            'ControlType:   UIA_ButtonControlTypeId
            
            Set ControlName = UIAutomation.CreatePropertyCondition(UIA_NamePropertyId, "Close")
            Set ControlType = UIAutomation.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
            Set NameAndType = UIAutomation.CreateAndCondition(ControlName, ControlType)
                
            'Find the Close button in the IE Download Notification Bar
            
            Set Button = NotificationToolbar.FindFirst(TreeScope_Children, NameAndType)
            
            'Click the Close button
            
            Button.SetFocus
            Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
            InvokePattern.Invoke
            If DebugMode Then Debug.Print Time; "Close clicked"
        
        End If
                     
    End Function
    Analysis

    Why does IE11 display the "What do you want to do with xxxxx.xxx?" dialogue when a file download is offered?

    It happens because the website doesn't send a "Content-Disposition" header, or there is a misspelling in the header's value string, or incorrect syntax.

    A well-behaved website (e.g. http://financials.morningstar.com/ba...&culture=en-US) sends the following correct response header with the file download:

    Content-Disposition: attachment;filename="INTC Balance Sheet.csv"

    and the Download Notification Bar is displayed.

    However, https://www.abs.gov.au (https://www.ausstats.abs.gov.au for the actual download) doesn't send the Content-Disposition header. (One of the headers it sends is content-type: application/vnd.ms-excel).

    The dialogue is also displayed if the header's value is misspelt, for example:

    Content-Disposition: attachement;filename="Data.zip"

    Here, attachment is misspelt as "attachement".

    Using Fiddler to fix or reproduce this issue

    By running Fiddler, we can use FiddlerScript to fix or reproduce the issue with the dialogue. To fix the issue for https://www.abs.gov.au, add the following code to the OnPeekAtResponseHeaders function:
    Code:
            if (oSession.HostnameIs("www.ausstats.abs.gov.au") && oSession.oResponse.headers.ExistsAndContains("Content-Type","ms-excel")){
                oSession.oResponse.headers.Add("Content-Disposition", "attachment; filename='Stats_Data.xls'");    
            }
    and click the Save Script button. Fiddler calls the OnPeekAtResponseHeaders function before the response headers are sent to the client, hence the above code adds the Content-Disposition header with a fixed file name to the response headers and therefore IE will display the normal Download Notification Bar instead of the dialogue when a file download is offered.

    To reproduce the issue, add the following code to the OnPeekAtResponseHeaders function:
    Code:
            if (oSession.HostnameIs("your.hostname.com") && oSession.oResponse.headers.ExistsAndContains("Content-Disposition","attachment")){
                oSession.oResponse.headers.Remove("Content-Disposition");
                oSession.oResponse.headers.Add("Content-Disposition", "attachement; filename='Data.zip'");    
            }
    The above code checks to see if the Content-Disposition response header contains "attachment" and if so changes it to the misspelt "attachement" with a fixed file name. With this code, IE will display the "What do you want to do with xxxxx.xxx?" dialogue instead of the normal Download Notification Bar. I think the dialogue is displayed only for binary files (.zip, .xls, etc.) and not text files (.txt, .csv). With text files, IE displays the file data in the browser.
    Last edited by John_w; Oct 7th, 2019 at 10:41 AM.

  10. #10
    Board Regular
    Join Date
    Oct 2007
    Posts
    5,857
    Post Thanks / Like
    Mentioned
    8 Post(s)
    Tagged
    2 Thread(s)

    Default Re: Using UIAutomationClient to automate the Save As file download in IE11

    UPDATE - Here is a list of useful links for UI Automation:

    UI Automation introduction
    https://docs.microsoft.com/en-gb/win...y-uiauto-win32

    UI Automation Fundamentals
    https://docs.microsoft.com/en-us/win...ocore-overview

    UI Automation Client Programmer's Guide
    https://docs.microsoft.com/en-us/win...o-clientportal

    An introduction to UI Automation
    http://blog.functionalfun.net/2009/0...tion-with.html

    Introduction to UIA: Microsoft's Accessibility API, including using Inspect tool
    https://www.youtube.com/watch?v=6b0K2883rXA

    How to install the Inspect tool on Windows 10?
    https://stackoverflow.com/questions/...-on-windows-10

    Using the Inspect tool
    https://docs.microsoft.com/en-us/win...nspect-objects

    Inspect is a legacy tool. Microsoft recommended using Accessibility Insights instead.

    Accessibility Insights
    https://accessibilityinsights.io/

Some videos you may like

User Tag List

Tags for this Thread

Like this thread? Share it with others

Like this thread? Share it with others

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •