2

I'm trying to get VBA to automate saving a file from IE. Thanks to various posts on these forums, I can login, navigate pages, and click the download link. The Save prompt appears at the bottom of IE, then I'm stuck:

IE11 Save Dialogue

I've been trying to use the code samples from https://www.mrexcel.com/forum/excel-questions/502298-need-help-regarding-ie-automation-using-vba-post3272730.html#post3272730, but the second FindWindow always returns 0:

hWnd = FindWindowEx(hWnd, 0, "DUIViewWndClassName", vbNullString) 

I'm using VBA 7.0 in Excel 14, and IE11.

There is advice at the top of the original post:

'Note - IE may block the download, displaying its Information Bar at the top of the tab, and preventing this program from 'automatically downloading the file. To prevent this, add NRLDC to IE's Trusted sites (Tools - Internet Options - 'Security - Trusted sites - Sites)

I can't access the trusted sites list due to IT policy, but the download prompt appears, so I don't think this is the issue.

The code I've taken is from Doongie's reply, which indicates it's updated for Windows 7:

Private Sub File_Download_Click_Save()

    Dim hWnd As Long
    Dim timeout As Date

    Debug.Print "File_Download_Click_Save"

    'Find the File Download window, waiting a maximum of 30 seconds for it to appear

    timeout = Now + TimeValue("00:00:30")
    Do
        hWnd = FindWindow("#32770", "") 'returns various numbers on different runs: 20001h 10440h
        DoEvents
        Sleep 200
    Loop Until hWnd Or Now > timeout

    Debug.Print "   File Download window "; Hex(hWnd)

    If hWnd Then
        SetForegroundWindow hWnd

        'Find the child DUIViewWndClassName window
        hWnd = FindWindowEx(hWnd, 0, "DUIViewWndClassName", vbNullString)    'always returns 0
        Debug.Print "   DUIViewWndClassName "; Hex(hWnd)
    End If

    If hWnd Then
        'Find the child DirectUIHWND window
        hWnd = FindWindowEx(hWnd, 0, "DirectUIHWND", "")
        Debug.Print "   DirectUIHWND "; Hex(hWnd)
    End If

    If hWnd Then
        'Find the child FloatNotifySink window
        hWnd = FindWindowEx(hWnd, 0, "FloatNotifySink", "")
        Debug.Print "   FloatNotifySink "; Hex(hWnd)
    End If

    If hWnd Then
        'Find the child ComboBox window
        hWnd = FindWindowEx(hWnd, 0, "ComboBox", "")
        Debug.Print "   ComboBox "; Hex(hWnd)
    End If

    If hWnd Then
        SetForegroundWindow hWnd

        'Find the child Edit window
        hWnd = FindWindowEx(hWnd, 0, "Edit", "")
        Debug.Print "   Edit "; Hex(hWnd)
    End If

    If hWnd Then        
        'Click the Save button
        SetForegroundWindow hWnd
        Sleep 600  'this sleep is required and 600 milliseconds seems to be the minimum that works
        SendMessage hWnd, BM_CLICK, 0, 0
    End If

End Sub

Is there any way (that won't get me in trouble with IT!) that I can inspect the handle numbers of the IE elements? Code inspector only shows me the page code, not IE dialogues.

Is there a list of possible element names for lpsz1 defined somewhere, as they apply to elements of IE?

Public Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
    (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
TylerH
  • 20,799
  • 66
  • 75
  • 101
Scott
  • 161
  • 5
  • 13
  • You mention "Excel 14" - do you mean the Office14 version, aka Office/Excel 2010? Or do you mean Office/Excel 2013? – TylerH Jul 19 '18 at 14:43
  • It's Office 2010, in the "About" section it states Version:14.0.7208.5000 – Scott Jul 20 '18 at 15:56

3 Answers3

1

Have you tried the dreaded sendkeys?

Application.SendKeys "%{S}"
Application.SendKeys "%{O}"
QHarr
  • 83,427
  • 12
  • 54
  • 101
  • Any feedback please? – QHarr Jul 19 '18 at 15:39
  • **~~shudder~~** – Scott Jul 19 '18 at 16:13
  • So far, I've got: Application.SendKeys "{TAB}{TAB}{TAB}{DOWN}{DOWN}{ENTER}" 'jump to the save-as Application.SendKeys "{^A}{^C}" 'copy the current filename Dim clip As DataObject Set clip = New DataObject filename = clip.GetFromClipboard Application.SendKeys "{HOME}" SavePath = "C:\Users\me\Documents\Knowledgebase\MS Office\Download Test" & WorkbookFunction.Format(Now(), "YYYY-DD-MM HHMM ") clip.SetText SavePath clip.PutInClipboard Application.SendKeys "{^V}{TAB}~" 'jump to the save button and press enter ... and I can't step the code, or it send the keys to VBA! – Scott Jul 19 '18 at 16:14
  • I can't read that in the comments but I can tell you that you would put the two lines of my code at the point you expect the pop-up to appear. You cannot be debugging at the time or it will send to the VBE. – QHarr Jul 19 '18 at 16:17
  • I'm trying to use save as, and change the target name, which takes 13 keys and a string paste, and I can't step the code. The proper window interfaces sound like a much safer method, if I knew the correct handles to use. Several forums and tutorials state **Use SendKeys as a last resort only** – Scott Jul 19 '18 at 16:23
  • it is not ideal, I will admit. But are you sure there isn't a download URL in the associated HTML? – QHarr Jul 19 '18 at 16:28
  • Nope, generated by a javascript. I've broken the the filenames down, they're linux timestamps. So even if I could figure out a URL that would get me to it, it doesn't exist until the java is invoked to create the file, and I'd need sub-milli-second time sync with the server. :/ Thanks for the suggestion, but I need a solution that pushes that button and reacts to the save file prompt. – Scott Jul 20 '18 at 12:10
0

In my IE Automation used below code to save file from IE. Below code requires VBA reference to UIAutomationCore.dll and can be found at

%windir%/sysWow64/UIAutomationCore.dll

and enable trust access to vba by

File -> Options -> Trust Center -> Trust Center Settings -> Macro Settings -> Check Trust access to the VBA

Private Sub InvokeSaveButton(IEHwnd As Long)
Dim o As IUIAutomation
Dim e As IUIAutomationElement
Set o = New CUIAutomation
Dim h As Long
h = IEHwnd
h = FindWindowEx(h, 0, "Frame Notification Bar", vbNullString)
If h = 0 Then Exit Sub

Set e = o.ElementFromHandle(ByVal h)
Dim iCnd As IUIAutomationCondition
Set iCnd = o.CreatePropertyCondition(UIA_NamePropertyId, "Save")

Dim Button As IUIAutomationElement
Set Button = e.FindFirst(TreeScope_Subtree, iCnd)
Dim InvokePattern As IUIAutomationInvokePattern
Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
InvokePattern.Invoke
End Sub
nagarajannd
  • 715
  • 5
  • 11
  • Hi Nagarajannd, thanks for the look-in. I had found that method in the forums and tried to use it, firstly I found that I had to declare h as a variant, when I left it as long, the line 'h = ieApp.hWnd' failed on Type Mismatch. Now when I run that code, it crashes XL at 'Set e = o.ElementFromHandle(ByVal h)'. I get that the crash might be caused by sending a variant instead of a long. [https://msdn.microsoft.com/en-us/library/bb268219%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396] indicates hWnd should be long, so why do I get a Type Mismatch...? :/ – Scott Jul 19 '18 at 12:27
  • Ok, Try declaring h as LongPtr. – nagarajannd Jul 19 '18 at 12:42
  • Nope, now I get Type Mismatch at `h = FindWindowEx(**h**, 0, "Frame Notification Bar", vbNullString)` – Scott Jul 19 '18 at 13:35
0

You could try the urlmon library. Change the url and file name + extension to what you need to.

It will probably not work on a website where you have to log in to get to the file.

Public Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" (ByVal pCaller As Long, _
    ByVal szURL As String, ByVal szFileName As String, ByVal dwReserved As Long, _
    ByVal lpfnCB As Long) As Long
Public Function DownloadFile(URL As String, LocalFilename As String) As Boolean
    Dim errValue As Long
    errValue = URLDownloadToFile(0, URL, LocalFilename, 0, 0)
    If errValue = 0 Then
        MsgBox "Download Completed, saved at: " & LocalFilename
    Else
        MsgBox "There was an error downloading the file"
    End If
End Function
Sub DoIt()
    DownloadFile "http://www.blahblahblah.com/somefolder/somefiles.xlsx", "C:\Users\Public\Documents\SavedFile.xlsx"
End Sub
Ricardo A
  • 1,752
  • 1
  • 10
  • 16
  • Yeah, direct download to a file is simple, been doing it for years. This application requires a login to the page, then the download is generated by javascript, it's not a hard link - hence the section to find the button called Download and click it. – Scott Jul 19 '18 at 16:16