FTP サーバーのディレクトリを表示する

Network Object Class を使って FTP サーバーサイドのディレクトリを列挙して表示します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの設定

  1. 自分の開発マシンに構築した FTP サーバー機能を起動して下さい。
    または FTP サーバーが使える環境で実行して下さい。
  2. 新規プロジェクトを作成して objlist.cpp をプロジェクトに追加します。
    ダウンロードするファイル名と格納するフォルダーを設定する DialogBox を作成して下さい。
    /////////////////////////////////////////////////////////////////////////////
    // Dialog
    
    IDD_DIALOG1 DIALOG DISCARDABLE  0, 0, 225, 65
    STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
    CAPTION "ダイアログ"
    FONT 9, "MS Pゴシック"
    BEGIN
        DEFPUSHBUTTON   "OK",IDOK,39,44,50,14
        PUSHBUTTON      "キャンセル",IDCANCEL,122,44,50,14
        LTEXT           "ダウンロードファイル名",IDC_STATIC,7,7,67,8
        LTEXT           "格納先ファイル名",IDC_STATIC,7,28,52,8
        EDITTEXT        IDC_EDIT1,77,7,141,14,ES_AUTOHSCROLL
        EDITTEXT        IDC_EDIT2,77,25,141,14,ES_AUTOHSCROLL
    END
    
  3. メニューを作成して下さい。
    /////////////////////////////////////////////////////////////////////////////
    // Menu
    
    IDR_MENU1 MENU DISCARDABLE 
    BEGIN
        POPUP "File(&X)"
        BEGIN
            MENUITEM "終了(&X)",                    IDM_END
        END
        POPUP "FTP(&T)"
        BEGIN
            MENUITEM "ダウンロード(&D)",            IDM_DOWNLOAD
        END
    END
    
  4. 次の領域に文字列を設定して下さい。
        char        szUserName[64]=         "プロバイダから指定されたID";
        char        szPassWord[64]=         "パスワード";
        char        szHost[64]=             "FTP アドレス";
        char        szBaseDir[64]=          "基準ディレクトリ";
        char        szFName[MAX_PATH]=      "Download するファイル名";
        char        szLocalFile[MAX_PATH]=  "格納するフォルダーとファイル名";
        
  5. ビルドから実行すると FTP サーバーに接続されて、サーバーサイドのディレクトリ一覧が表示されます。
    フォルダーをダブルクリックすると FTP サーバーのフォルダーが切り替わります。
  6. メニューから [FTP(T)][ダウンロード(D)] を選ぶと DialogBox が表示されます。
    ファイル名と格納するフォルダーを指定して OK をクリックするとダウンロードされます。

プログラムの説明

  1. "Network.h" をインクルードして Network.lib をリンクして下さい。
    App は Network Object Class の定義です。
        #define     NAME    "FTP Directry List"
        #include    <windows.h>
        #include    "Network.h"
        #include    "resource.h"
    
        #pragma     once
        #pragma     comment(lib,"wininet.lib")
        #pragma     comment(lib,"Network.lib")
    
        #define     ID_LIST     100
        #define     ID_STATIC   101
    
        Network     *App= NULL;             //Network Object Class
        HINSTANCE   g_hInst;
        HWND        g_hWnd;
        HWND        hList, hStatic;
    
        char        szUserName[64]=         "maeda";
        char        szPassWord[64]=         "password";
        char        szHost[64]=             "127.0.0.1";
        char        szBaseDir[64]=          "./";
        char        szFName[MAX_PATH]=      "index.html";
        char        szLocalName[MAX_PATH]=  "c:\\index.html";
        
  2. WinMain() では通常のウインドウを生成してメニューを表示します。
  3. WM_CREATE で Network Object Class を生成して、ウインドウに LISTBOX と STATIC を設定します。
    MyConnect() でサーバーに接続します。
        case WM_CREATE:
            App= new Network(hWnd);
            GetClientRect(hWnd, &rc);
            hList= CreateWindowEx(WS_EX_WINDOWEDGE, "LISTBOX", "",
                WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | LBS_SORT | LBS_NOTIFY,
                10, 40, rc.right - rc.left - 20, rc.bottom - rc.top - 50,
                hWnd, (HMENU)ID_LIST, g_hInst, NULL);
            hStatic= CreateWindowEx(0, "STATIC", "",
                WS_CHILD | WS_VISIBLE | WS_BORDER,
                10, 5, rc.right - rc.left -20, 30,
                hWnd, (HMENU)ID_STATIC,
                g_hInst, NULL);
            MyConnect(hWnd, hList, hStatic);
            break;
        
  4. LISTBOX のフォルダーがダブルクリックされたときは App->FTPFiles() でフォルダーを切り替えます。
        case WM_COMMAND:
            switch(LOWORD(wParam))
            {   case ID_LIST:
                    if (HIWORD(wParam) == LBN_DBLCLK)
                    {   iIndex = ListBox_GetCurSel(hList);
                        ListBox_GetText(hList,iIndex,szDir);
                        for (i = 0; i <= lstrlen(szDir) -5 ; i++)
                        {   szBuf[i] = szDir[i + 6];
                        }
                        App->FTPFiles(hList,szBuf);
                    }
                    break;
        
  5. メニューからダウンロードを選ぶと MyDown() でファイルがダウンロードされます。
                case IDM_DOWNLOAD:
                    MyDown();
                    break;
                case IDM_END:
                    SendMessage(hWnd, WM_CLOSE, 0, 0);
                    break;
        
  6. WM_CLOSE では Network Object Class を開放して下さい。
        case WM_CLOSE:
            SAFE_DELETE(App);
            MessageBox(hWnd,"インターネットから切り離しました","OK",MB_OK);
            DestroyWindow(hList);
            DestroyWindow(hWnd);
            break;
        
  7. FTP サーバーに接続する MyConnect() 関数です。
    App->FTPOpen() で FTP をオープンして、App->FTPFiles() で FTP サーバーサイドのディレクトリを列挙します。
        BOOL MyConnect(HWND hWnd, HWND hList, HWND hStatic)
        {   BOOL    rc;
            char    szStr[128];
    
            rc= App->FTPOpen(szHost,szUserName,szPassWord,szBaseDir);
            if (rc==FALSE)  return FALSE;
            MessageBox(hWnd, "FTPに接続しました", "接続完了", MB_OK);
            wsprintf(szStr, " <<%sに接続済み>>", szHost);
            SetWindowText(hWnd, szStr);
            if (App->FTPFiles(hList,szBaseDir)==TRUE)
                SetWindowText(hStatic,szBaseDir);
            return TRUE;
        }
        
  8. ファイルを Download する MyDown() 関数です。
    DialogBox からファイル名と格納するフォルダーを取得して App->FTPGet() でダウンロードします。
        void MyDown()
        {
            if (DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG1),g_hWnd,(DLGPROC)DlgProc)==IDCANCEL)
                return;
            if (App->FTPDown(szFName,szLocalName)==TRUE)
                MessageBox(g_hWnd, "無事ダウンロードできました", "OK", MB_OK);
            return;
        }
        
  9. DialogBox のCALLBACK 関数では、ファイル名と格納するフォルダーを取得して、szFName と szLocalName に格納します。
        LRESULT CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
        {   static  HWND  hFName, hLocalFName;
    
            switch(msg)
            {   case WM_INITDIALOG:
                    hFName = GetDlgItem(hDlg,IDC_EDIT1);
                    hLocalFName = GetDlgItem(hDlg, IDC_EDIT2);
                    Edit_SetText(hFName, szFName);
                    Edit_SetText(hLocalFName, szLocalName);
                    SetFocus(hFName);
                    break;
                case WM_COMMAND:
                    switch(LOWORD(wp))
                    {   case IDOK:
                            Edit_GetText(hFName, szFName, sizeof(szFName));
                            Edit_GetText(hLocalFName, szLocalName, sizeof(szLocalName));
                            EndDialog(hDlg, IDOK);
                            return TRUE;
                        case IDCANCEL:
                            EndDialog(hDlg, IDCANCEL);
                            return TRUE;
                    }
                    return FALSE;
            }
            return FALSE;
        }
        
  10. FTP サーバーのディレクトリを切り替える関数です。
        if (!FtpSetCurrentDirectory(hHost,szDir))
        {   MessageBox(hWnd, "ディレクトリの設定ができません", "失敗", MB_OK);
            ReleaseCapture();
            SetCursor(LoadCursor(NULL,IDC_ARROW));
            return FALSE;
        }
        
  11. FTP サーバーのディレクトリから最初のファイルを検索する関数です。
        hFindHandle = FtpFindFirstFile(hHost,"*.*",&FindFileData,INTERNET_FLAG_RELOAD,0);
        if (hFindHandle == NULL)
        {   if (GetLastError() == ERROR_NO_MORE_FILES)
                MessageBox(hWnd,"ファイルはありません","Error",MB_OK);
            else
            {   MessageBox(hWnd,"深刻なエラーが発生しました","Error",MB_OK);
                FTPClose();
            }
            return FALSE;
        }
        
  12. ディレクトリの次のファイルを検索する関数です。
        while(InternetFindNextFile(hFindHandle, &FindFileData))
        {   if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            {   strcpy(fname, "<dir> ");
                strcat(fname, FindFileData.cFileName);
            }
            else    strcpy(fname, FindFileData.cFileName);
            ListBox_AddString(hList, fname);
        }
        

超初心者のプログラム入門(Win32API C++)