※ 修正版をこちらのページにアップしています。将来的にはこのページは削除される可能性があります。
さて、今までプログラムを作ってきましたが、実は、まだ自分のパソコンから外に出ていませんでした。
そうです。このプログラムは、FTPクライアントなのでした。
そこで、今回からFTPの機能を充実することにします。
まず、インターネットの世界に出ていくには、インターネット用のAPIのセットを使う必要があります。
これには、2つほどあり、"WinSock" と、"Wininet" のAPIのセットがあります。
このうち "WinSock" は難しいので、"Wininet"を使って、プログラムを作成していくことにしましょう。
それでは、早速インターネットつなぐことにしますが、FTPプログラムでは、つなぐ先は、もちろんFTPサーバーですね。
これにつなぐにはちょっとややこしいですが、以下のように2段階で行います。
@ InternetOpen() でInternet APIを初期化する
A InternetConnect() でFTPセッションハンドルを取得する
Internet APIを初期化とは何でしょうか?
ローカルファイルを読む場合はたいてい OPEN してハンドルを取得する必要がありますが、インターネットの場合もやっぱり同じで、今から利用するインターネットハンドルを取得しなければなりません。
そして、これを行うのが InternetOpen() です。つまりインターネットにつなぐには、これが必ず必要になります。
HINTERNET InternetOpen( LPCTSTR lpszAgent, // 関数を使用するアプリケーション名を指すポインタ DWORD dwAccessType, // アクセス方法を指定するフラグ LPCTSTR lpszProxyName, // プロキシサーバー名を指すポインタ LPCTSTR lpszProxyBypass, // ホストの名前またはIPアドレスのリストのアドレス DWORD dwFlags // 動作に関するオプションのフラグ );
第1引数は、このプログラム自身の名前を指定します。
第2引数は、INTERNET_OPEN_TYPE_PRECONFIG を指定しておけば大丈夫でしょう。
実を言うと、よくわからないのですが、レジストリに記録されている方法(IEと共通?)でアクセスを行うということで、INTERNET_OPEN_TYPE_PRECONFIG にしています。
第3引数と第4引数には、 NULL を、第5引数には、0 をそれぞれ指定します。
くどいようですが、パラメータに文字列そのものを指定することはできません。
"USER"や"PASS"といった文字列も実は、そのポインタがわたされているのです。
第5引数は、後で使用しますが、ここでは、0 を指定してください。
戻り値として、作成されたインターネットハンドルが返されます。
そしてこのインターネットハンドルを手がかりにFTPの世界へと踏み出すのです!(ちょっと大袈裟!?)
FTPとは、File Transfer Protocol の略で、ネットワーク上のクライアントとサーバーの間でファイル転送をおこなうプロトコルです。プロトコル とは仕組みのことです。
つまり、自分のパソコンから遠く離れた場所にあるサーバーにファイルを送り込んだり、その逆に遠く離れた場所にあるサーバーからファイルをコピーするための仕組みです。
このFTPを使うためには、 InternetConnect() を使用します。
HINTERNET InternetConnect( HINTERNET hInternet, // Internet ハンドル LPCTSTR lpszServerName, // サーバー名を指すポインタもしくはIPアドレス INTERNET_PORT nServerPort, // 接続するサーバーのTCP/IPポート番号 LPCTSTR lpszUsername, // ログオンのユーザー名を指すポインタ LPCTSTR lpszPassword, // ログオンのパスワードを指すポインタ DWORD dwService, // アクセスのタイプ DWORD dwFlags, // 接続モードのフラグ DWORD_PTR dwContext // コールバック関数用のアプリケーション定義値 );
第1引数は、先ほど取得した、インターネットハンドルを指定します。
第2引数は、FTPサーバー名の文字列を指すポインタもしくはIPアドレス、つまり "ftp.geocities.jp" や "202.93.75.222" を指定します。
第3引数は、TCP/IPポート番号ですが、たいていは 21 番ポートを使用します。
21 と記述しても問題ありませんが、定数が用意されているので、INTERNET_DEFAULT_FTP_PORT を使用します。
第4引数と第5引数には、FTPサーバーにログインするためのユーザーとパスワード文字列のポインタを指定します。
第6引数には、アクセスのタイプを指定します。FTPですから、INTERNET_SERVICE_FTP ですね。
第7引数は接続モードを指定しますが、よくわかりません。INTERNET_FLAG_PASSIVE で問題ないようです。
第8引数は、コールバック関数用ですので今は使用しません。0 を指定します。
なんとも引数がたくさんある関数ですね。
戻り値として、作成されたセッションハンドルが返されます。
これは、先ほどのインターネットハンドルとは、別物です。混同しないようにしてくださいね。
この関数が成功して初めて、FTPサーバーに接続されたことになります。
これらの関数を実装する為に、新しく、FtpProc ファイルを作りましょう。
/* ========================================================================== */ /* FILE FTPPROC.CPP */ /* CREATE 2003/04/01 */ /* MODIFY 2006/10/01 */ /* REMARK */ /* COPYRIGHT 2000-2006, Latin. All Rights Reserved */ /* ========================================================================== */ #include <Windows.h> #include <WinInet.h> #include "Common.h" /* -------------------------------------------------------------------------- */ /* グローバル(EXTERN)関数宣言部 */ /* -------------------------------------------------------------------------- */ extern void FTPConnect(HWND); /* -------------------------------------------------------------------------- */ /* PROCEDURE FTPConnect */ /* PARAM */ /* RETURN void */ /* REMARK INetInfoで識別されるインターネットへの接続 */ /* -------------------------------------------------------------------------- */ void FTPConnect(HWND hWnd) { /* 変数宣言部 */ HINTERNET hInternet; HINTERNET hConnect; /* 関数本体部 */ hInternet = InternetOpen("FTPManager", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); if (hInternet == NULL) { MessageBox(hWnd, "インターネットを開けません";, "ERR", MB_OK); InternetCloseHandle(hInternet); return; } hConnect = InternetConnect(hInternet, "ftp.vector.co.jp", INTERNET_DEFAULT_FTP_PORT, "anonymous", "ftp@user", INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0); if (hConnect == NULL) { MessageBox(hWnd, "接続中にエラー発生", "ERR", MB_OK); InternetCloseHandle(hInternet); return; } MessageBox(hWnd, "接続に成功!", "INFO", MB_OK); InternetCloseHandle(hInternet); InternetCloseHandle(hConnect); return; }
インターネット用のAPIのセット "Wininet" を使うには、以下の2点に気をつけてください。
@ WinInet.h をインクルードする。
A WinInet.Lib をリンクする。
@ は簡単ですね。ソースファイルに #include <WinInet.h> と書けば終了です。
A はリストビュウのときに、一度やっていますが、再度確認しましょう。
以下のように、リンカの追加の依存ファイルに設定しましょう。

さて、FTP接続に接続する関数はできましたが、どうやってこの関数を呼び出してやりましょうか?
ここは、久しぶりにメニューを使うことにしましょう。
まずは、リソースエディタでメニュー(IDM_MENUMAIN) を出してください。
ファイル(F)の主メニューのなかに、新規接続(C)を追加してください。
ID は、IDM_NEWCONNECT としました。

Resource.h のヘッダファイルには、IDM_NEWCONNECTに対応する数値を書いてください。
/* ========================================================================== */ /* FILE RESOURCE.H */ /* CREATE 2003/04/01 */ /* MODIFY 2005/04/01 */ /* REMARK */ /* COPYRIGHT 2000-2005, Latin. All Rights Reserved */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* コントロール宣言部 */ /* -------------------------------------------------------------------------- */ #define ID_CBOCLIENT 01002 #define ID_LVWCLIENT 01004 /* -------------------------------------------------------------------------- */ /* メニューアイテム宣言部 */ /* -------------------------------------------------------------------------- */ #define IDM_MENUMAIN 20000 #define IDM_NEWCONNECT 20001 #define IDM_EXIT 20002
新規接続(C)がクリックされたときの処理を追加していきましょう。
メニューの項目がクリックされたとき、Windowsは WM_COMMAND メッセージを発生させるのでした。
これをプロシージャのところで捕まえてやればよいですね。 WinMain ファイルのメッセージ処理を以下のように修正します。
※ 必要部分のみ抜粋です。
/* -------------------------------------------------------------------------- */ /* CALLBACK WndProc */ /* PARAM HWND hWnd : ウィンドウハンドル */ /* UINT uMsg : メッセージ */ /* WPARAM wParam : メッセージの追加情報 */ /* LPARAM lParam : メッセージの追加情報 */ /* RETURN LRESULT */ /* メッセージ処理の結果 */ /* REMARK */ /* -------------------------------------------------------------------------- */ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { /* 関数本体部 */ switch (uMsg) { case WM_COMMAND: switch (LOWORD(wParam)) { case ID_CBOCLIENT: switch (HIWORD(wParam)) { case CBN_SELCHANGE: OnComboBox_SelChange((HWND) lParam); break; default: return (DefWindowProc(hWnd, uMsg, wParam, lParam)); } break; case IDM_NEWCONNECT: OnMenuNewConnect_Click(hWnd); break; case IDM_EXIT: SendMessage(hWnd, WM_CLOSE, 0, 0L); break; default: return (DefWindowProc(hWnd, uMsg, wParam, lParam)); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, uMsg, wParam, lParam)); } return 0L; }
OnMenuNewConnect_Click() という関数はまだありませんが、この関数で、先ほど作成したFTPConnect() 関数をコールすることにします。
Message ファイルに以下の関数を追加します。
/* -------------------------------------------------------------------------- */ /* OnMenuNewConnect_Click */ /* PARAM HWND hWnd : ウインドウハンドル */ /* REMARK */ /* -------------------------------------------------------------------------- */ void OnMenuNewConnect_Click(HWND hWnd) { /* 関数本体部 */ FTPConnect(hWnd); }
さあ、これでFTPサーバーにつながることができるようになりました。
どうですか?なんかちょっと味気ないですが、気にしないでください。
説明を忘れていましたが、FTPConnect()プロシージャの最後で、InternetCloseHandle() を呼び出して、FTPセッションハンドル、インターネットハンドルの順にクローズしましょう。ここら辺も、ファイルのオープン、クローズに似てますね。
本日のソース: FTPManager110(VC8).zip FTPManager110(BCC).zip
さて、FTPサーバーにつないでいますが、今回は、
ftp.vector.co.jp
につないでみました。
通常FTPサイトは、通常はアカウントとパスワードによって保護されています。
これでは、インターネット上に多数存在する公共のソフトウェアやデータを不特定多数に配布するためには不都合です。
このため、アカウント名にanonymous(「匿名」という意味)と入力することで、誰でも利用できるようにしたFTPサイトです。
Anonymous FTP といったりします。
また、ログインする際に自分のメールアドレスをパスワードとして入力する慣例がありますが、メールアドレスがもれてしまうので、あえてメールアドレスを指定するかは個人で判断ください。