如何让VBA开始下载文件,而不是等到文件完成后再继续下一行代码

如何让VBA开始下载文件,而不是等到文件完成后再继续下一行代码,vba,download,Vba,Download,我正在尝试优化生成报告的VBA应用程序 此报表要求应用程序下载并嵌入多个图像。 我认为这是应用程序中最大的瓶颈 我的第一次尝试是让VBA执行Powershell命令,该命令将在生成报告的早期下载图像,然后应用程序将在处理完数据后从HD嵌入图像。 我的工作环境阻止VBA执行shell脚本 在几次不重要的失败尝试之后(尝试用一个新的excel应用程序打开另一个/xlsm工作簿,独立于我的vba线程,并使用一个on open执行和它的变体),我来到这里征求建议 如何使用vba开始下载映像(使用任何本机

我正在尝试优化生成报告的VBA应用程序

此报表要求应用程序下载并嵌入多个图像。 我认为这是应用程序中最大的瓶颈

我的第一次尝试是让VBA执行Powershell命令,该命令将在生成报告的早期下载图像,然后应用程序将在处理完数据后从HD嵌入图像。 我的工作环境阻止VBA执行shell脚本

在几次不重要的失败尝试之后(尝试用一个新的excel应用程序打开另一个/xlsm工作簿,独立于我的vba线程,并使用一个on open执行和它的变体),我来到这里征求建议

如何使用vba开始下载映像(使用任何本机windows 10应用程序/命令/进程/…),而不是等到下载完成后再转到下一行代码

稍后在应用程序中,我将使用代码扫描目标目录,以确定文件是否已下载完毕,否则将休眠并在失败之前重复x次

更新:根据评论,我认为我非常接近解决方案。我已经在这个更新的底部包含了我目前正在使用的代码。现在的问题是,只要我之前至少向同一个url发出过一次请求,它就会快速下载该文件。 在第一个请求中,它挂起“oXMLHTTP.send”的时间比我预期的通过浏览器下载文件所需的时间稍长,然后出于某种原因调整自身大小

有谁能帮我解决这个悬而未决的问题和/或解释一下为什么这段代码调用“Workbook\u WindowResize”

这在我的工作中时有发生。看着Fiddler,我可以看出只有两个请求发出

结果200: 结果200:

结果和代码

在一个全新的工作簿中,我粘贴了更新结束时找到的代码。 这是我在即时窗口中看到的

A took: 33375milliseconds
Pre DoEvents
Workbook_WindowResized
Post DoEvents
B took: 593milliseconds
Pre DoEvents
Post DoEvents
C took: 33797milliseconds
Pre DoEvents
Workbook_WindowResized
Post DoEvents
Do work
Pre DoEvents
Post DoEvents
a done
b done
c done
此工作簿代码

Private mlngStart As Long
Private Declare Function GetTickCount Lib "kernel32" () As Long

Public Sub StartTimer()
    mlngStart = GetTickCount
End Sub

Public Function EndTimer() As Long
    EndTimer = (GetTickCount - mlngStart)
End Function

Function StartDownload(ByVal vWebFile As String, sPath As String) As Object
    Dim oXHTTP As Object
    Dim oStream As Object


    Set oXHTTP = CreateObject("MSXML2.XMLHTTP.3.0")
    Set oStream = CreateObject("ADODB.Stream")
    Application.StatusBar = "Fetching " & vWebFile & " as " & sPath
    oXHTTP.Open "GET", vWebFile, False
    oXHTTP.send
    With oStream
        .Type = 1 'adTypeBinary
        .Open
        .Write oXHTTP.responseBody
        .SaveToFile sPath, 2 'adSaveCreateOverWrite
        .Close
    End With
    Set StartDownload = oXHTTP
    Set oStream = Nothing
    Application.StatusBar = False

End Function

Sub FinishDownload(ByRef oXMLHTTP, ByVal vLocalFile As String)

    'Wait for request to finish
    Do While oXMLHTTP.readyState <> 4
        DoEvents
    Loop
End Sub
Function foo()
    Dim dest As String
    dest = "C:\sandbox\"
    Dim a, b, c As Object
    DoEvents
    Url = "http://ipv4.download.thinkbroadband.com/50MB.zip?randomizer=ff" & Str(Math.Round(Math.Rnd(12) * 1000, 0))
    Call StartTimer
    Set a = StartDownload(Url, dest & "a.zip")
    Debug.Print "A took: " & EndTimer & "milliseconds"
    
    Debug.Print "Pre DoEvents"
    DoEvents
    Debug.Print "Post DoEvents"
    
    Call StartTimer
    Set b = StartDownload(Url, dest & "b.zip")
    Debug.Print "B took: " & EndTimer & "milliseconds"
    
    Debug.Print "Pre DoEvents"
    DoEvents
    Debug.Print "Post DoEvents"
    
    Url = "http://ipv4.download.thinkbroadband.com/50MB.zip?randomizer=ee" & Str(Math.Round(Math.Rnd(12) * 1000, 0))
    
    Call StartTimer
    Set c = StartDownload(Url, dest & "c.zip")
    Debug.Print "C took: " & EndTimer & "milliseconds"
    
    Debug.Print "Pre DoEvents"
    DoEvents
    Debug.Print "Post DoEvents"
    
    Debug.Print ("Do work")
    Call bar
        
    Debug.Print "Pre DoEvents"
    DoEvents
    Debug.Print "Post DoEvents"
    
    Call FinishDownload(a, dest & "a.zip")
    Debug.Print ("a done")
    Call FinishDownload(b, dest & "b.zip")
    Debug.Print ("b done")
    Call FinishDownload(c, dest & "c.zip")
    Debug.Print ("c done")
End Function

Function Download_File(ByVal vWebFile As String, ByVal vLocalFile As String) As Boolean
    Dim oXMLHTTP As Object, i As Long, vFF As Long, oResp() As Byte

    'You can also set a ref. to Microsoft XML, and Dim oXMLHTTP as MSXML2.XMLHTTP
    Set oXMLHTTP = CreateObject("MSXML2.XMLHTTP")
    oXMLHTTP.Open "GET", vWebFile, False 'Open socket to get the website
    oXMLHTTP.send 'send request

    'Wait for request to finish
    Do While oXMLHTTP.readyState <> 4
    DoEvents
    Loop

    oResp = oXMLHTTP.responseBody 'Returns the results as a byte array

    'Create local file and save results to it
    vFF = FreeFile
    If Dir(vLocalFile) <> "" Then Kill vLocalFile
    Open vLocalFile For Binary As #vFF
    Put #vFF, , oResp
    Close #vFF

    'Clear memory
    Set oXMLHTTP = Nothing
End Function

Sub bar()
    Dim F As Integer
    F = FreeFile
    Open "C:\sandbox\" & "\example.txt" For Output As F
    Close #F
End Sub


Private Sub Workbook_WindowResize(ByVal Wn As Window)
    Debug.Print "Workbook_WindowResized"
End Sub
Private mlngStart尽可能长
私有声明函数GetTickCount Lib“kernel32”()的长度为
公共子StartTimer()
mlngStart=GetTickCount
端接头
公共函数EndTimer()的长度为
EndTimer=(GetTickCount-mlngStart)
端函数
函数StartDownload(ByVal vWebFile作为字符串,sPath作为字符串)作为对象
Dim oXHTTP作为对象
作为对象的暗淡光束
设置oXHTTP=CreateObject(“MSXML2.XMLHTTP.3.0”)
设置oStream=CreateObject(“ADODB.Stream”)
Application.StatusBar=“Fetching”&vWebFile&“as”&sPath
oXHTTP.Open“GET”,vWebFile,False
oXHTTP.send
与奥斯特雷姆
.Type=1'adTypeBinary
打开
.Write-oXHTTP.responseBody
.SaveToFile sPath,2'adSaveCreateOverWrite
.结束
以
设置StartDownload=oXHTTP
设置oStream=Nothing
Application.StatusBar=False
端函数
Sub FinishDownload(ByRef-oXMLHTTP,ByVal-vLocalFile作为字符串)
'等待请求完成
执行oXMLHTTP.readyState 4时
多芬特
环
端接头
函数foo()
将dest变暗为字符串
dest=“C:\sandbox\”
作为对象的尺寸a、b、c
多芬特
Url=”http://ipv4.download.thinkbroadband.com/50MB.zip?randomizer=ff&Str(数学圆整(数学圆整(12)*1000,0))
打电话给StartTimer
设置a=StartDownload(Url、dest和“a.zip”)
Debug.Print“A take:&EndTimer&“毫秒”
调试。打印“前置事件”
多芬特
调试。打印“Post DoEvents”
打电话给StartTimer
设置b=StartDownload(Url、dest和“b.zip”)
Debug.Print“B take:”&EndTimer&“毫秒”
调试。打印“前置事件”
多芬特
调试。打印“Post DoEvents”
Url=”http://ipv4.download.thinkbroadband.com/50MB.zip?randomizer=ee&Str(数学圆整(数学圆整(12)*1000,0))
打电话给StartTimer
设置c=StartDownload(Url、dest和“c.zip”)
Debug.Print“C take:”&EndTimer&“毫秒”
调试。打印“前置事件”
多芬特
调试。打印“Post DoEvents”
Debug.Print(“做工作”)
呼叫栏
调试。打印“前置事件”
多芬特
调试。打印“Post DoEvents”
调用FinishDownload(a、dest和“a.zip”)
Debug.Print(“完成”)
调用FinishDownload(b、dest和“b.zip”)
调试。打印(“b完成”)
调用FinishDownload(c、dest和“c.zip”)
调试打印(“c完成”)
端函数
函数下载_文件(ByVal vWebFile作为字符串,ByVal vLocalFile作为字符串)作为布尔值
Dim-oXMLHTTP作为对象,i作为长,vFF作为长,oResp()作为字节
'您还可以将引用设置为Microsoft XML,并将oXMLHTTP设置为MSXML2.XMLHTTP
设置oXMLHTTP=CreateObject(“MSXML2.XMLHTTP”)
打开“GET”,vWebFile,False“打开套接字以获取网站
oXMLHTTP.send“发送请求
'等待请求完成
执行oXMLHTTP.readyState 4时
多芬特
环
oResp=oXMLHTTP.responseBody'将结果作为字节数组返回
'创建本地文件并将结果保存到其中
vFF=自由文件
如果Dir(vLocalFile)“,则杀死vLocalFile
打开二进制文件作为#vFF的vLocalFile
放#vFF,oResp
关闭#vFF
“清除内存
设置oXMLHTTP=Nothing
端函数
子栏()
作为整数的Dim F
F=自由文件
打开“C:\sandbox\”&“\example.txt”作为F输出
关闭#F
端接头
专用子工作簿\u窗口大小调整(ByVal Wn作为窗口)
调试。打印“工作簿\u窗口大小调整”
端接头

来自@Tim Williams在我创建的评论中提供的链接,它很有效

Function StartDownload(ByVal vWebFile As String) As Object
    Dim oXMLHTTP As Object, i As Long, vFF As Long, oResp() As Byte

    'You can also set a ref. to Microsoft XML, and Dim oXMLHTTP as MSXML2.XMLHTTP
    Set oXMLHTTP = CreateObject("MSXML2.XMLHTTP")
    oXMLHTTP.Open "GET", vWebFile, True'Open socket to get the website
    oXMLHTTP.Send 'send request
    Set StartDownload = oXMLHTTP
End Function

Sub FinishDownload(ByRef oXMLHTTP, ByVal vLocalFile As String)

    'Wait for request to finish
    Do While oXMLHTTP.readyState <> 4
    DoEvents
    Loop

    oResp = oXMLHTTP.responseBody 'Returns the results as a byte array

    'Create local file and save results to it
    vFF = FreeFile
    If Dir(vLocalFile) <> "" Then Kill vLocalFile
    Open vLocalFile For Binary As #vFF
    Put #vFF, , oResp
    Close #vFF

    'Clear memory
    Set oXMLHTTP = Nothing
End Sub
Function foo()
    Dim dest As String
    dest = "C:\sandbox\"
    url = "http://ipv4.download.thinkbroadband.com/200MB.zip"
    Dim a, b, c As Object
    DoEvents
    Set a = DownloadManager.StartDownload(url)
    DoEvents
    Set b = DownloadManager.StartDownload(url)
    DoEvents
    Set c = DownloadManager.StartDownload(url)
    DoEvents
    Debug.Print ("Do Something")
    
    Call FinishDownload(a, dest & "a.zip")
    Debug.Print ("a done")
    
    Call FinishDownload(b, dest & "b.zip")
    Debug.Print ("b done")
    Call FinishDownload(c, dest & "c.zip")
    Debug.Print ("c done")
End Function
函数StartDownload(ByVal vWebFile作为字符串)作为对象
Dim-oXMLHTTP作为对象,i作为长,vFF作为长,oResp()作为字节
'您还可以将引用设置为Microsoft XML,并将oXMLHTTP设置为MSXML2.XMLHTTP
设置oXMLHTTP=CreateObject(“MSXML2.XM