问题
I am using Internet Explorer to click on a file.
I get to a point where an Internet Explorer pop-up appears saying "Do you want to open or save the file?":
I want to write a VBA code that clicks on the save button.
I realized it is not possible to right click and "inspect element" in order to show the HTML page because the pop-up is not part of the internet explorer webpage.
So I tried the sendKeys method even though it is not reliable. I tried different options such as :
Application.SendKeys "%S"
Application.SendKeys "%s"
Application.SendKeys "%{S}"
Application.SendKeys "%{s}"
SendKeys ("%S")
SendKeys ("%s")
SendKeys ("%{S}")
SendKeys ("%{s}")
Application.SendKeys "%{S}"
When I run the code, none of them save the file.
Where is my error?
Are there other propositions to click on that "Save" button?
Maybe the object to which I am applying SendKeys should not be "Application"?
回答1:
If you wish to use the UIAutomationCore.dll and reference it, you can do something like:
Public Function AutoSave() As Boolean
On Error Goto handler
Dim sysAuto As New UIAutomationClient.CUIAutomation
Dim ieWindow As UIAutomationClient.IUIAutomationElement
Dim cond As IUIAutomationCondition
Set cond = sysAuto.CreateAndCondition(sysAuto.CreatePropertyCondition(UIA_NamePropertyId, "Notification"), _
sysAuto.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ToolBarControlTypeId))
Set ieWindow = sysAuto.GetRootElement.FindFirst(TreeScope_Descendants, cond)
Dim tField As UIAutomationClient.IUIAutomationElement
Dim tFieldCond As IUIAutomationCondition
Set tFieldCond = sysAuto.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_SplitButtonControlTypeId)
Set tField = ieWindow.FindFirst(TreeScope_Descendants, tFieldCond)
Dim invPattern As UIAutomationClient.IUIAutomationInvokePattern
Set invPattern = tField.GetCurrentPattern(UIA_InvokePatternId)
invPattern.Invoke
AutoSave = True
Exit Function
handler:
End Function
And call that routine after clicking on the item - perhaps give it a Hard Wait to allow the Notification bar to show.
EDIT
To invoke the Close Button:
Set cond = sysAuto.CreateAndCondition(sysAuto.CreatePropertyCondition(UIA_NamePropertyId, "Close"), _
sysAuto.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_ButtonControlTypeId))
Dim closeButton As IUIAutomationElement
Set closeButton = WaitForElement(ieWindow, cond, 10)
If closeButton Is Nothing Then Exit Sub
Dim clickButtonPattern As IUIAutomationInvokePattern
Set clickButtonPattern = closeButton.GetCurrentPattern(UIA_InvokePatternId)
clickButtonPattern.Invoke
........
Helper function:
Function WaitForElement(rootElement As IUIAutomationElement, condition As IUIAutomationCondition, timeout As Long) As IUIAutomationElement
Dim startTime As Date
startTime = Now
Dim element As IUIAutomationElement
Set element = rootElement.FindFirst(TreeScope_Descendants, condition)
While element Is Nothing And 100000 * (Now - startTime) < timeout
Application.Wait Now + TimeValue("00:00:01")
Set element = rootElement.FindFirst(TreeScope_Descendants, condition)
Wend
Set WaitForElement = element
End Function
You would typically wait until the 'Notification bar Text' element text had changed to have "download has completed" at the end.
This can be done with a couple of helper functions:
Function WaitForTextValue(textElement As IUIAutomationElement, text As String, timeout As Long, Optional exactMatch As Boolean = False) As Boolean
Dim startTime As Date
startTime = Now
Dim result As String
result = ReadValue(textElement)
Dim isMatch As Boolean
If exactMatch Then
isMatch = result = text
Else
isMatch = InStr(1, result, text, vbTextCompare) > 0
End If
'keep reading the element until we have a match, or the timeout has expired
While Not isMatch And 100000 * (Now - startTime) < timeout
Application.Wait Now + TimeValue("00:00:01")
result = ReadValue(textElement)
If exactMatch Then
isMatch = result = text
Else
isMatch = InStr(1, result, text, vbTextCompare) > 0
End If
Wend
WaitForTextValue = isMatch
End Function
Function ReadValue(element As IUIAutomationElement) As String
Dim valPattern As IUIAutomationValuePattern
Set valPattern = element.GetCurrentPattern(UIA_ValuePatternId)
If Not valPattern Is Nothing Then
ReadValue = element.GetCurrentPropertyValue(UIA_ValueValuePropertyId)
Else
' raise error here if element's value cannot be read - err.Raise
End If
End Function
And you would call this check after clicking the 'Save' button like so:
Set cond = sysAuto.CreateAndCondition(sysAuto.CreatePropertyCondition(UIA_NamePropertyId, "Notification bar Text"), _
sysAuto.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_TextControlTypeId))
Dim barText As IUIAutomationElement
Set barText = WaitForElement(ieWindow, cond, 10)
If barText Is Nothing Then Exit Sub
If Not WaitForTextValue(barText, "download has completed", 30, False) Then Exit Sub
'if we get to here, then text has changed, and we can go ahead and click close button
回答2:
Reproduce your problem on my side, it seems that before clicking the Save button, we need time to display the popup file download prompt. So, please try to use the Application.Wait method to wait the prompt display.
Code like this:
Sub Test()
Dim ie As Object
Dim Rank As Object
Set ie = CreateObject("InternetExplorer.application")
ie.Visible = True
ie.Navigate ("http://localhost:54382/HtmlPage47.html")
Do
If ie.ReadyState = 4 Then
Exit Do
Else
End If
Loop
Set doc = ie.document
doc.getElementsByTagName("tr")(1).getElementsByTagName("td")(5).getElementsByTagName("a")(0).Click
Application.Wait (Now + TimeValue("0:00:02"))
Application.SendKeys "%{S}"
End Sub
The screenshot as below:
来源:https://stackoverflow.com/questions/56894341/how-to-click-on-the-save-button-when-pop-up-appears