Загрузите файл с индикатором выполнения в VBA

Я нашел множество примеров для этого на нескольких языках, но ни один из них не является спецификацией VBA. Этот вопрос, Как загрузить несколько файлов в VB6 с индикатором выполнения?, обращается к трем различным подходам, чтобы сделать это в VB6.

  • Используйте свойство ASyncRead объектов VB6 UserControl/UserDocument
  • Использовать библиотеку типов olelib.tlb и интерфейс IBindStatusCallback
  • Используйте wininet.dll, чтобы написать собственную загрузку в функцию файла.

Ни один из этих подходов не работает для меня, потому что:

  • Объекты UserControl/UserDocument недоступны из VBA
  • Я бы предпочел не поддерживать и распространять большую внешнюю зависимость
  • Я не видел очевидного способа получить текущий ход загрузки файла.

Число 2 выше показалось наиболее перспективным. Мне интересно, могу ли я создать интерфейс IBindStatusCallback, используя модуль класса из моего проекта VBA?

Или, может быть, есть свойства/методы, доступные с помощью номера 3 выше, который обеспечит текущий прогресс. Любая помощь очень ценится.

Ответ 1

Я сделал это, используя функции wininet.dll. К сожалению, я не могу вставить свой код, поскольку он принадлежит моему работодателю.

Используйте InternetOpen и InternetOpenUrl для запуска загрузки, HttpQueryInfoLong, чтобы получить длину содержимого, а затем повторно вызовите InternetReadFile для чтения данных в буфер (я использую буфер 128k), записывая данные в файл и обновляя индикатор выполнения, поскольку вы перейти.

Объявления, чтобы вы начали:

Private Declare Function InternetOpen Lib "wininet.dll" Alias "InternetOpenA" (ByVal sAgent As String, ByVal lAccessType As Long, ByVal sProxyName As String, ByVal sProxyBypass As String, ByVal lFlags As Long) As Long
Private Declare Function HttpQueryInfo Lib "wininet.dll" Alias "HttpQueryInfoA" (ByVal hHttpRequest As Long, ByVal lInfoLevel As Long, ByRef sBuffer As Any, ByRef lBufferLength As Long, ByRef lIndex As Long) As Long
Private Declare Function InternetCloseHandle Lib "wininet.dll" (ByVal hInet As Long) As Integer
Private Declare Function InternetReadFile Lib "wininet.dll" (ByVal hFile As Long, ByRef Buffer As Any, ByVal lNumberOfBytesToRead As Long, lNumberOfBytesRead As Long) As Integer
Private Declare Function InternetOpenUrl Lib "wininet.dll" Alias "InternetOpenUrlA" (ByVal hInternet As Long, ByVal lpszUrl As String, ByVal lpszHeaders As String, ByVal dwHeadersLength As Long, ByVal dwFlags As Long, ByVal dwContext As Long) As Long

Private Const INTERNET_OPEN_TYPE_PRECONFIG = 0
Private Const INTERNET_FLAG_RELOAD = &H80000000
Private Const INTERNET_FLAG_KEEP_CONNECTION = &H400000 ' use keep-alive semantics - required for NTLM proxy authentication
Private Const HTTP_QUERY_CONTENT_LENGTH = 5
Private Const HTTP_QUERY_FLAG_NUMBER = &H20000000

Если вам нужно разъяснение, отправьте комментарий.

Ответ 2

Вам нужен индикатор выполнения в VBA, не работает ли один из этих подходов?

Индикатор выполнения в VBA Excel

Кажется намного проще, чем делать это, как вы описываете, или я не понимаю?

ОК, попробуйте это. Получите заголовки из URL-адреса и проанализируйте их для Content-Length. Затем вы можете соответствующим образом установить свой индикатор выполнения.

Function GetFileSize(URL As String) As Long

Dim xml As Object ' MSXML2.XMLHTTP60
Dim result As String

Set xml = CreateObject("MSXML2.XMLHTTP.6.0")

With xml
  ' get headers only
  .Open "HEAD", URL, False
  .send
End With

result = xml.getResponseHeader("Content-Length")

GetFileSize = CLng(result)

End Function

Теперь просто вызовите функцию с URL-адресом файла, который вы хотите загрузить. Он должен предоставить вам количество байтов файла.