
こんにちは、サポート部の Yama-chan です。Sybase の時代から、FTP 通信には 「Windows 標準の WinInet API である wininet.dll」を利用している方も多いのではないでしょうか。この API は、追加ライブラリを導入せずに Windows 環境で安定したファイル転送を実現できるため、業務アプリケーションでも長年活用されてきました。
今回の記事では、最新の PowerBuilder 2022 R3 でも引き続き利用可能な WinInet API を使って、FTP でファイルをアップロード・ダウンロードする方法を紹介します。具体的には、FtpPutFileW を用いたアップロード処理と、FtpGetFileW を用いたダウンロード処理の実装例を取り上げ、サンプルコードを交えながら解説します。既存資産を活かしつつ最新環境で安心して運用できるようになるでしょう。
WinInet(Windows Internet API)は、Microsoft が提供するインターネット通信用の API 群で、HTTP(HTTPSを含む)や FTP などのプロトコルをサポートしています。PowerBuilder からは External Function を使ってこれらの API を定義して呼び出すことができます。
このブログで使用する API 一覧
| 関数名 | 説明 |
| InternetOpenW | 通信セッションの初期化 |
| InternetConnectW | FTP サーバーへの接続 |
| FtpPutFileW | ローカル→サーバーへのファイル送信 |
| FtpGetFileW | サーバー→ローカルへのファイル取得 |
| InternetCloseHandle | ハンドルの解放 |
PowerBuilder で外部 DLL を利用するためには、最初に外部関数として宣言を追加する必要があります。グローバル外部関数として宣言することで、アプリケーション全体からその関数を呼び出せるようになり、コードの再利用性や保守性が向上します。以下のようにグローバル外部関数 (Global External Functions) で宣言を追加します。
FUNCTION longptr InternetOpenW(string lpszAgent, long dwAccessType, string lpszProxyName, string lpszProxyBypass, long dwFlags) LIBRARY "wininet.dll" FUNCTION longptr InternetConnectW(longptr hInternetSession, string lpszServerName, long nServerPort, string lpszUsername, string lpszPassword, long dwService, long dwFlags, long dwContext) LIBRARY "wininet.dll" FUNCTION boolean FtpPutFileW(longptr hConnect, string lpszLocalFile, string lpszNewRemoteFile, long dwFlags, long dwContext) LIBRARY "wininet.dll" FUNCTION boolean FtpGetFileW(longptr hConnect, string lpszRemoteFile, string lpszNewFile, boolean fFailIfExists, long dwFlagsAndAttributes, long dwFlags, long dwContext) LIBRARY "wininet.dll" FUNCTION boolean InternetCloseHandle(longptr hInternet) LIBRARY "wininet.dll"
外部関数の使い方については、エイタさんの「外部関数を使ってかゆい背中を掻く」ブログで詳しく紹介しているので、そちらの記事もご確認ください。
以下のサンプルコードは PowerBuilder から Windows API を呼び出して FTP サーバーにファイルをアップロードします。
longptr hSession, hConnect boolean bResult hSession = InternetOpenW("PBFTP", 1, "", "", 0) hConnect = InternetConnectW(hSession, "ftp.example.com", 21, "username", "password", 1, 0, 0) IF hConnect <> 0 THEN bResult = FtpPutFileW(hConnect, "C:\local\file.txt", "remote_file.txt", 0, 0) IF bResult THEN MessageBox("成功", "アップロード完了") ELSE MessageBox("失敗", "アップロード失敗") END IF InternetCloseHandle(hConnect) END IF InternetCloseHandle(hSession)
InternetOpenW(“PBFTP”, 1, “”, “”, 0) を呼び出し、インターネット接続用のセッションハンドルを取得します。”PBFTP” はアプリケーション名、”1″ はダイレクト接続を意味します。
次に、InternetConnectW 関数を使って、FTP サーバーの ftp.example.com のポート 21 に接続します。また、ユーザー名 “username” とパスワード “password” を使って認証します。成功すると接続ハンドル hConnect が返されます。
接続が成功した場合、FtpPutFileW 関数を呼び出してローカルファイル “C:\local\file.txt” をサーバー上に “remote_file.txt” という名前でアップロードします。
最後に InternetCloseHandle で接続セッションを終了します。
なお、Windows API の使用方法およびパラメーターの詳細については、Microsoft社の各 API のリファレンスをご参照ください。
以下のサンプルコードは PowerBuilder から Windows API を呼び出して FTP サーバーからファイルをダウンロードします。
longptr hSession, hConnect boolean bResult hSession = InternetOpenW("PBFTP", 1, "", "", 0) hConnect = InternetConnectW(hSession, "ftp.example.com", 21, "username", "password", 1, 0, 0) IF hConnect <> 0 THEN bResult = FtpGetFileW(hConnect, "remote_file.txt", "C:\local\file.txt", FALSE, 0, 0, 0) IF bResult THEN MessageBox("成功", "ダウンロード完了") ELSE MessageBox("失敗", "ダウンロード失敗") END IF InternetCloseHandle(hConnect) END IF InternetCloseHandle(hSession)
ファイルのアップロードとほとんど同じですが、ファイルをダウンロードするので、FtpPutFileW 関数の代わりに FtpGetFileW 関数を利用しています。
セキュリティを重視するなら、暗号化された通信を行う SFTP を利用するのが有効ですが、Windows 標準の API ではそのような機能が提供されていません。外部のツールを利用することで実装することが可能です。無料の WinSCP を使うことで、GUI 操作やコマンドライン経由で安全にファイル転送が可能です。PowerBuilder から利用するには、Run 関数で Winscp.com を実行するのが便利です。
たとえば、ローカルにある localfile.txt をリモートの /remote/path に送信するには以下のように Run 関数で Winscp.com を実行します。
Run ('winscp.com /command "open sftp://user:password@host/" "put localfile.txt /remote/path/" "exit"')
PowerBuilder 2022 R3 でも、従来通り WinInet API を使って FTP 通信が可能です。WinInet API を利用することで、ファイルのアップロードまたはダウンロード操作など基本的な FTP 機能を簡潔に実装可能です。PowerBuilder のネイティブコードから直接呼び出せるため、追加の外部ライブラリを導入せずに済むケースも多いです。しかしながら、WinInet は古くからある API のため、最新のセキュリティ要件や暗号化通信には対応が限定的です。
今後は、よりセキュアな通信が求められる場面も増えるため、SFTP や FTPS 対応のライブラリへの移行も視野に入れておくとよいでしょう。
以上、Yama-chan でした。