11.FTPで接続する

 

※ 修正版をこちらのページにアップしています。将来的にはこのページは削除される可能性があります。

 


1.やっとこさFTP

さて、今までプログラムを作ってきましたが、実は、まだ自分のパソコンから外に出ていませんでした。
そうです。このプログラムは、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の世界へと踏み出すのです!(ちょっと大袈裟!?)

 

2.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

 

3.メッセージを処理する

新規接続(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 といったりします。
また、ログインする際に自分のメールアドレスをパスワードとして入力する慣例がありますが、メールアドレスがもれてしまうので、あえてメールアドレスを指定するかは個人で判断ください。


Last Update 2014/02/24 21:25
[Index] [Prev] [Next]