2023/08/19

HTTP でファイルをダウンロード(いにしえの呪文)

前回、Notes 10.x 以降、LotusScript の NotesHTTPRequest クラスを使用したファイルのダウンロード方法を紹介しました。ただ、このメソッドは、64 KB 以上のファイルがダウンロードできない問題がありました。今回はその回避策の一つを紹介します。

その方法は、Windows API の一つである、Windows インターネット(WinINet API)を使用する方法です。


Windows インターネット(WinINet API)とは?

Microsft Learn によると、Microsoft Windows インターネット (WinINet) アプリケーション プログラミング インターフェイス (API) を使用すると、アプリケーションは FTP や HTTP などの標準インターネット プロトコルにアクセスできるとのことです。

実行の要件としては、Windows NT 4.0 以降、または Windows Me/98/95 が必要となっています。いにしえの呪文である理由がわかりますね。

詳しくは以下のサイトを参照ください。

Windows インターネット


サンプルプログラム(スクリプトライブラリ)

まず、WinINet API をコールする部分をまとめたスクリプトライブラリ lsHttpDownload を作成します。

以下は、(Declarations) に記述する API 関数の定義です。使用している API 関数は4つです。

'WinINet API関数の定義
Declare Function InternetReadFile Lib "wininet.dll" (
      Byval hFile As Long, lpBuffer As Any,
      Byval lNumBytesToRead As Long, lNumberOfBytesRead As Long) As Integer
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
Declare Function InternetOpenUrl Lib "wininet.dll" Alias "InternetOpenUrlA" (
      Byval hInternetSession As Long, Byval sUrl As String,
      Byval sHeaders As String, Byval lHeadersLength As Long,
      Byval lFlags As Long, Byval lContext As Long) As Long
Declare Function InternetCloseHandle Lib "wininet.dll" (
      Byval hInet As Long) As Integer

続いて、同じく (Declarations) に記述する定数の宣言です。

'User_agent
Private Const WI_AGENT_NAME = "WinINetNotes"

'Proxy設定はデフォルトを使用
Private Const WI_PROXY = ""

'レジストリの設定を使う
Private Const WI_ACCESSTYPE = 0

'INTERNET_FLAG_RELOAD( 0x80000000 )
Private Const WI_FLAGS = &H80000000

'InternetReadFile で一度に読み込むサイズ
Private Const WI_READ_BUFFSIZE = 1024

そして、ダウンロードする関数の本体は次の通りです。

Public Function HttpDownload(Byval vsUrl As String, Byval vsFileName As String) As Long
   Dim abyRecvData() As Byte
   Dim lInetHandle As Long 'インターネットハンドル
   Dim lUrlHandle As Long 'URLハンドル
   Dim iReturn As Integer 'InternetReadFile の戻り値
   Dim lReadSum As Long '受信したデータの総サイズ 兼 バッファへのポインタ
   Dim lReadSize As Long '受信したデータのサイズ(1回分)
   Dim iFP As Integer
   Dim i As Integer

   On Error Goto ErrProc

   '入力チェック
   If vsUrl = "" Then Exit Function
   If vsFileName = "" Then Exit Function
   
   'インターネットハンドルを作成
   lInetHandle = InternetOpen(WI_AGENT_NAME, WI_ACCESSTYPE, WI_PROXY, "", 0)
   If lInetHandle = 0 Then Exit Function

   'URLハンドルを作成
   lUrlHandle = InternetOpenUrl(lInetHandle, vsUrl, "", 0, WI_FLAGS, 0)
   If lUrlHandle = 0 Then Error 9000, "INetハンドルが取得できませんでした。"
   
   '書き込むファイルの準備
   iFP = Freefile()
   Open vsFileName For Binary Access Write As iFP

   'ファイルのダウンロード
   Do
      'バッファエリア確保 & 初期化
      Redim abyRecvData(WI_READ_BUFFSIZE-1)

      iReturn = InternetReadFile(lUrlHandle, abyRecvData(0), WI_READ_BUFFSIZE, lReadSize)
      lReadSum = lReadSum + lReadSize

      '終了判断
      If (lReadSize = 0) Or (iReturn = 0) Then Exit Do

      'サイズ調整
      If lReadSize <  WI_READ_BUFFSIZE Then
         ReDim Preserve abyRecvData(lReadSize - 1)
      End If 

      'ファイルに書き込み
      For i = Lbound(abyRecvData) To Ubound(abyRecvData)
         Put #iFP, ,abyRecvData(i)
      Next
   Loop
   Close #iFP

ExitProc:
   If lUrlHandle <> 0 Then InternetCloseHandle(lUrlHandle)
   If lInetHandle <> 0 Then InternetCloseHandle(lInetHandle)

   HttpDownload = lReadSum
Exit Function

ErrProc:
   Print Err & ":" & Error$ & " (line:" & Erl & ")"
   Resume ExitProc
End Function


郵便番号データのダウンロード

それでは、このライブラリを使用したメインルーチンです。前回ダウンロードでエラーが出た全国版のデータでテストします。

Option Declare

Use "lsHttpDownload"

Sub Initialize
   Dim sFileName As String
   Dim sURL As String

   'パラメータの設定
   sFileName = "ken_all.zip"
   sURL = "https://www.post.japanpost.jp/zipcode/dl/oogaki/zip/" & sFileName

   'ダウンロードの実行
   Call HttpDownload(sURL, "c:\lotus\" & sFileName)
End Sub

実行すると、次のようにファイルが作成されます。64 KB を越えるファイルですが、正常にダウンロードできており、zip 圧縮の回答できました。


まとめ

Windows インターネット(WinINet API)を使用する方法は、64 KB 以上のファイルがダウンロードできない問題の暫定的な解決策として紹介しました。

今回の方法では、LotusScript から直接 API をコールしました。よって、ロケーションで行うプロキシ設定など、ノーツクライアントのインターネットの接続設定をすっ飛ばして接続します。ブラウザからは接続できるけど、Notes 経由では接続できない場合でも利用できます。

そもそも、このような状況に陥ることが問題ではあるのですが...

0 件のコメント:

コメントを投稿