また、状態をステータスバーに表示するようにします。
メニューに「ひとつ上のディレクトリへ」を加えます。その他 にも少し手を加えます。
左の図はFTPのリストビュー上で右クリックしたときに表示される
ボップアップメニューです。これで、少し使いやすくなりました。
左の図のように、途中経過をステータスバーに表示するようにしました。
では、早速プログラムを見てみましょう。
プログラムがちょっと長くなりすぎたので、defineとtypedefと関数プロトタイプ宣言を 独立したヘッダーファイル(myftp.h)にしました。// myftp.h #define ID_LIST 100 #define ID_STATIC 101 #define ID_LISTL 102 #define ID_STATICL 103 #define ID_STATUSBAR 104 #define UP 1 //ソート;昇順 #define DOWN 2 //降順 #define NO_OF_SUBITEM 3 //サブアイテムの数 #define CONTEXT_GETFILE 100 #define CONTEXT_CONNECT 200 #define CONTEXT_PUTFILE 300 typedef struct _tagAccount{ char szUserName[64]; char szPassWord[64]; } ACCOUNT; typedef struct _tagFTPAddress{ char szHost[64]; char szBaseDir[64]; } FTPADDRESS; typedef struct _tagINETHANDLE{ HINTERNET hInternet; HINTERNET hHost; } INETHANDLE; typedef struct _tagFNAME{ char szFName[MAX_PATH]; char szLocalFileName[MAX_PATH]; } FNAME; typedef struct _tagHWNDSET{ HWND hwnd1; HWND hwnd2; } HWNDSET; typedef struct _tagSORTDATA{ HWND hwndList; //リストビューのhwnd int isortSubItem; //ソートするサブアイテムインデックス int iUPDOWN; //昇順か降順か } SORTDATA; typedef struct _tagSTATUSCALLBACK { HWND hwndStatus; DWORD dwFrom; } STATUSCALLBACK; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyAccountProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyFtpAddressProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyGetFNameProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDriveProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyCreateDirProc(HWND, UINT, WPARAM, LPARAM); int CALLBACK MyCompProc(LPARAM, LPARAM, LPARAM); void CALLBACK MyInetCallback(HINTERNET, DWORD, DWORD, LPVOID, DWORD); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL MyConnect(HWND, INETHANDLE *, ACCOUNT, FTPADDRESS, HWND, HWND, HWND); void MyDown(HWND, INETHANDLE, FTPADDRESS, FNAME *, HWND, HWND, HWND, HWND); void SetAccount(HWND, ACCOUNT *); void SetHost(HWND, FTPADDRESS *); void GetAllFiles(HWND, HWND, HWND, INETHANDLE *); void SetMyLocalDir(HWND, HWND, HWND); void ChangeLocalDrive(HWND, HWND, HWND); void MyUp(HWND, INETHANDLE, HWND, HWND, HWND, HWND, HWND); void MyFtpDelFile(HWND, INETHANDLE, HWND, HWND); void MyFtpCreatDir(HWND, INETHANDLE, HWND, HWND); void MyFtpRemoveDir(HWND, INETHANDLE, HWND, HWND); HWND MakeMyList(HWND); void InsertMyColumn(HWND);
クラスメニューの項目が少し増えました。///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)...", IDM_END END POPUP "ftp(&T)" BEGIN MENUITEM "接続(&C)", IDM_CONNECT MENUITEM SEPARATOR MENUITEM "ファイルのダウンロード(&D)...", IDM_DOWNLOAD MENUITEM "ファイルのアップロード(&U)...", IDM_UPLOAD MENUITEM SEPARATOR MENUITEM "ディレクトリの作成...", IDM_CREATEDIR MENUITEM "ディレクトリの削除...", IDM_REMOVEDIR MENUITEM "ファイルの削除...", IDM_DELFILE MENUITEM SEPARATOR MENUITEM "切断(&X)...", IDM_DISCONNECT MENUITEM SEPARATOR MENUITEM "ひとつ上のディレクトリへ", IDM_UPDIRFTP END POPUP "ローカル(&L)" BEGIN MENUITEM "ドライブの変更(&D)...", IDM_LOCALDRIVE MENUITEM SEPARATOR MENUITEM "ひとつ上のディレクトリへ", IDM_UPDIRLOCAL END POPUP "設定(&S)" BEGIN MENUITEM "アカウント設定(&A)...", IDM_ACCOUNT MENUITEM "ホスト設定(&H)...", IDM_GETHOST END END POPUPMENULOCAL MENU DISCARDABLE BEGIN POPUP "ダミーです" BEGIN MENUITEM "アップロード(&U)...", IDM_UPLOAD MENUITEM SEPARATOR MENUITEM "ドライブの変更(&D)...", IDM_LOCALDRIVE MENUITEM SEPARATOR MENUITEM "ひとつ上のディレクトリへ", IDM_UPDIRLOCAL END END POPUPMENUFTP MENU DISCARDABLE BEGIN POPUP "ダミーです" BEGIN MENUITEM "ディレクトリの作成...", IDM_CREATEDIR MENUITEM "ディレクトリの削除...", IDM_REMOVEDIR MENUITEM "ファイルの削除...", IDM_DELFILE MENUITEM SEPARATOR MENUITEM "ダウンロード(&D)...", IDM_DOWNLOAD MENUITEM SEPARATOR MENUITEM "ひとつ上のディレクトリへ", IDM_UPDIRFTP END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYACCOUNT DIALOG DISCARDABLE 0, 0, 143, 67 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "アカウント" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,46,50,14 PUSHBUTTON "キャンセル",IDCANCEL,86,46,50,14 LTEXT "ID",IDC_STATIC,7,7,8,8 LTEXT "パスワード",IDC_STATIC,7,25,32,8 EDITTEXT IDC_ID,43,7,94,13,ES_AUTOHSCROLL EDITTEXT IDC_PASSWORD,43,25,94,13,ES_PASSWORD | ES_AUTOHSCROLL END MYFTPADDRESS DIALOG DISCARDABLE 0, 0, 159, 63 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "ホスト" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,42,50,14 PUSHBUTTON "キャンセル",IDCANCEL,102,42,50,14 LTEXT "FTPアドレス",IDC_STATIC,7,7,36,8 LTEXT "基準となるディレクトリ",IDC_STATIC,7,25,64,8 EDITTEXT IDC_FTPADDRESS,75,7,78,13,ES_AUTOHSCROLL EDITTEXT IDC_BASEDIR,75,25,78,13,ES_AUTOHSCROLL END MYGETFNAME DIALOG DISCARDABLE 0, 0, 187, 67 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "ファイル名入力" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,46,50,14 PUSHBUTTON "キャンセル",IDCANCEL,130,46,50,14 LTEXT "ダウンロードするファイル",IDC_STATIC,7,7,72,8 EDITTEXT IDC_FNAME,88,7,92,12,ES_AUTOHSCROLL LTEXT "ダウンロード先ファイル名",IDC_STATIC,7,31,74,8 EDITTEXT IDC_LOCALFILE,88,27,92,12,ES_AUTOHSCROLL END MYDRIVE DIALOG DISCARDABLE 0, 0, 43, 115 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "ドライブ" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,9,94,24,14 LISTBOX IDC_LIST1,7,7,29,83,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END MYCREATEDIR DIALOG DISCARDABLE 0, 0, 135, 47 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "FTPディレクトリの新規作成" FONT 9, "MS Pゴシック" BEGIN EDITTEXT IDC_EDIT1,7,7,73,13,ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,7,26,50,14 PUSHBUTTON "キャンセル",IDCANCEL,78,26,50,14 LTEXT "を作成します",IDC_STATIC,81,12,39,8 END
また、右クリック用のポップアップメニュー"POPUPMENUFTP", "POPUPMENULOCAL" が増えました。右クリックされる場所によってポップアップメニューを変えています。
ソースファイル本体の最初のほうは大分すっきりしました。 あたりまえですがmyftp.hをインクルードするのを忘れないでください。 また、Comctl32.lib, Wininet.libをリンクするのを忘れないでください。// myftp08.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <wininet.h> #include <windowsx.h> #include <commctrl.h> #include "resource.h" #include "myftp.h" const char szWindowTitle[] = "猫でもわかるFTP"; char szClassName[] = "myftp08"; //ウィンドウクラス BOOL bConnect = FALSE;//インターネットに接続しているかどうか
WinMain, InitApp, InitInstanceの各関数に変更はありません。
WM_CREATEメッセージが来たときにステータスバーを作ります。INITCOMMONCONTROLEX 構造体のdwICCメンバにICC_BAR_CLASSESを加えるのを忘れないでください。また、 ステータスバーの高さをstatic変数に保存しておきます。//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id, i, iIndex; static ACCOUNT myaccount; static FNAME myfname; static FTPADDRESS myftpaddress; static INETHANDLE inet; static HWND hList, hStatic, hListL, hStaticL, hStatus; static HINSTANCE hInst; RECT rc; HDWP hDwp; char szDir[MAX_PATH], szBuf[MAX_PATH]; INITCOMMONCONTROLSEX icc; LPNMHDR lpnmhdr; static int sortsubno[NO_OF_SUBITEM] = {UP}; NMLISTVIEW *pNMLV; SORTDATA SortData; static int isortsubno;//どのサブアイテムでソートされているか int sb_size[] = {100, 200, -1}; static int nStatus_h;//ステータスバーの高さ POINT pt; HMENU hMenu, hSubMenu; switch (msg) { case WM_CREATE: icc.dwSize = sizeof(INITCOMMONCONTROLSEX); icc.dwICC = ICC_LISTVIEW_CLASSES | ICC_BAR_CLASSES; InitCommonControlsEx(&icc); hInst = ((LPCREATESTRUCT)lp)->hInstance; GetClientRect(hWnd, &rc); hList = MakeMyList(hWnd); InsertMyColumn(hList); hListL = MakeMyList(hWnd); InsertMyColumn(hListL); hStatic = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 0, 0, 0, hWnd, (HMENU)ID_STATIC, hInst, NULL); hStaticL = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 0, 0, 0, hWnd, (HMENU)ID_STATICL, hInst, NULL); SetMyLocalDir(hWnd, hListL, hStaticL); SortData.hwndList = hListL; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; ListView_SortItems(hListL, MyCompProc, &SortData); hStatus = CreateStatusWindow(WS_CHILD | WS_VISIBLE, "", hWnd, ID_STATUSBAR); SendMessage(hStatus, SB_SETPARTS, (WPARAM)3, (LPARAM)sb_size); GetWindowRect(hStatus, &rc); nStatus_h = rc.bottom - rc.top; break; case WM_SIZE: hDwp = BeginDeferWindowPos(4); hDwp = DeferWindowPos(hDwp, hStaticL, HWND_TOP, 10, 5, LOWORD(lp) / 2 - 15, 30, SWP_SHOWWINDOW); hDwp = DeferWindowPos(hDwp, hStatic, HWND_TOP, LOWORD(lp) / 2 + 5, 5, LOWORD(lp) / 2 - 15, 30, SWP_SHOWWINDOW); hDwp = DeferWindowPos(hDwp, hListL, HWND_TOP, 10, 40, LOWORD(lp) / 2 - 15, HIWORD(lp) - 50 - nStatus_h, SWP_SHOWWINDOW); hDwp = DeferWindowPos(hDwp, hList, HWND_TOP, LOWORD(lp) / 2 + 5, 40, LOWORD(lp) / 2 - 15, HIWORD(lp) - 50 - nStatus_h, SWP_SHOWWINDOW); EndDeferWindowPos(hDwp); SendMessage(hStatus, WM_SIZE, wp, lp); break; case WM_CONTEXTMENU: pt.x = LOWORD(lp); pt.y = HIWORD(lp); if (wp == (WPARAM)hListL) { hMenu = LoadMenu(hInst, "POPUPMENULOCAL"); hSubMenu = GetSubMenu(hMenu, 0); TrackPopupMenu(hSubMenu, TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, 0, hWnd, NULL); DestroyMenu(hSubMenu); DestroyMenu(hMenu); } if (wp == (WPARAM)hList) { hMenu = LoadMenu(hInst, "POPUPMENUFTP"); hSubMenu = GetSubMenu(hMenu, 0); TrackPopupMenu(hSubMenu, TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, 0, hWnd, NULL); DestroyMenu(hSubMenu); DestroyMenu(hMenu); } if (wp != (WPARAM)hListL && wp != (WPARAM)hList) { MessageBox(hWnd, "範囲外です", "OK", MB_OK); } break; case WM_NOTIFY: lpnmhdr = (LPNMHDR)lp; if (lpnmhdr->hwndFrom == hListL) { switch (lpnmhdr->code) { case NM_DBLCLK: iIndex = ListView_GetNextItem(hListL, -1, LVNI_SELECTED); ListView_GetItemText(hListL, iIndex, 0, szDir, sizeof(szDir)); if (strstr(szDir, "<dir> ") != szDir) { MessageBox(hWnd, "ディレクトリではありません", "注意", MB_OK); break; } for (i =0; i <= lstrlen(szDir) - 5; i++) { szBuf[i] = szDir[i + 6]; } SetCurrentDirectory(szBuf); SetMyLocalDir(hWnd, hListL, hStaticL); SortData.hwndList = hListL; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; ListView_SortItems(hListL, MyCompProc, &SortData); break; case LVN_COLUMNCLICK: pNMLV = (NMLISTVIEW *)lp; isortsubno = pNMLV->iSubItem; if (sortsubno[isortsubno] == UP) sortsubno[isortsubno] = DOWN; else sortsubno[isortsubno] = UP; SortData.hwndList = hListL; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; if(ListView_SortItems(hListL, MyCompProc, &SortData) != TRUE) MessageBox(hWnd, "ソート失敗", "Error", MB_OK); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } } if (lpnmhdr->hwndFrom == hList) { switch (lpnmhdr->code) { case NM_DBLCLK: iIndex = ListView_GetNextItem(hList, -1, LVNI_SELECTED); ListView_GetItemText(hList, iIndex, 0, szDir, sizeof(szDir)); if (strstr(szDir, "<dir> ") != szDir) { MessageBox(hWnd, "ディレクトリではありません", "注意", MB_OK); break; } for (i =0; i <= lstrlen(szDir) - 5; i++) { szBuf[i] = szDir[i + 6]; } FtpSetCurrentDirectory(inet.hHost, szBuf); GetAllFiles(hWnd, hList, hStatic, &inet); SortData.hwndList = hList; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; ListView_SortItems(hList, MyCompProc, &SortData); break; case LVN_COLUMNCLICK: pNMLV = (NMLISTVIEW *)lp; isortsubno = pNMLV->iSubItem; if (sortsubno[isortsubno] == UP) sortsubno[isortsubno] = DOWN; else sortsubno[isortsubno] = UP; SortData.hwndList = hList; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; if(ListView_SortItems(hList, MyCompProc, &SortData) != TRUE) MessageBox(hWnd, "ソート失敗", "Error", MB_OK); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } } break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_LOCALDRIVE: ChangeLocalDrive(hWnd, hListL, hStaticL); SortData.hwndList = hListL; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; ListView_SortItems(hListL, MyCompProc, &SortData); break; case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_CONNECT: bConnect = MyConnect(hWnd, &inet, myaccount, myftpaddress, hList, hStatic, hStatus); SortData.hwndList = hList; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; ListView_SortItems(hList, MyCompProc, &SortData); SendMessage(hStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)""); break; case IDM_DOWNLOAD: MyDown(hWnd, inet, myftpaddress, &myfname, hList, hListL, hStaticL, hStatus); SortData.hwndList = hListL; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; ListView_SortItems(hListL, MyCompProc, &SortData); SendMessage(hStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)""); break; case IDM_UPLOAD: MyUp(hWnd, inet, hList, hStatic, hListL, hStaticL, hStatus); SortData.hwndList = hList; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; ListView_SortItems(hList, MyCompProc, &SortData); SendMessage(hStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)""); break; case IDM_DELFILE: MyFtpDelFile(hWnd, inet, hList, hStatic); SortData.hwndList = hList; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; ListView_SortItems(hList, MyCompProc, &SortData); break; case IDM_CREATEDIR: MyFtpCreatDir(hWnd, inet, hList, hStatic); SortData.hwndList = hList; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; ListView_SortItems(hList, MyCompProc, &SortData); break; case IDM_REMOVEDIR: MyFtpRemoveDir(hWnd, inet, hList, hStatic); SortData.hwndList = hList; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; ListView_SortItems(hList, MyCompProc, &SortData); break; case IDM_UPDIRFTP: if (!bConnect) { MessageBox(hWnd, "インターネットに接続されていません", "失敗", MB_OK); break; } FtpSetCurrentDirectory(inet.hHost, ".."); GetAllFiles(hWnd, hList, hStatic, &inet); SortData.hwndList = hList; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; ListView_SortItems(hList, MyCompProc, &SortData); break; case IDM_UPDIRLOCAL: SetCurrentDirectory(".."); SetMyLocalDir(hWnd, hListL, hStaticL); SortData.hwndList = hListL; SortData.isortSubItem = isortsubno; SortData.iUPDOWN = sortsubno[isortsubno]; ListView_SortItems(hListL, MyCompProc, &SortData); break; case IDM_ACCOUNT: SetAccount(hWnd, &myaccount); break; case IDM_GETHOST: SetHost(hWnd, &myftpaddress); break; case IDM_DISCONNECT: if (!bConnect) { MessageBox(hWnd, "インターネットに接続されていません", "失敗", MB_OK); break; } if (InternetCloseHandle(inet.hHost)) MessageBox(hWnd, "FTPをクローズしました", "OK", MB_OK); if (InternetCloseHandle(inet.hInternet)) MessageBox(hWnd, "インターネットから切り離しました", "OK", MB_OK); bConnect = FALSE; SetWindowText(hWnd, szWindowTitle); break; } break; case WM_CLOSE: if (bConnect) { MessageBox(hWnd, "インターネットの接続を切ってから終了してください", "注意", MB_OK); break; } id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hList); DestroyWindow(hStatic); DestroyWindow(hListL); DestroyWindow(hStaticL); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }
WM_SIZEメッセージが来たら各子供ウィンドウの大きさを調整します。 ここでは、ステータスバーはhDwpでは動かさずにWM_SIZEメッセージをそのまま ステータスバーに送りつけています。あと、ステータスバーの高さだけ、リストビューの 高さを低くするのを忘れないでください。
WM_CONTEXTMENUメッセージについては第115章 を参照してください。
TrackPopupMenu関数については第44章を参照してください。
メニューからIDM_CONNECT, IDM_DOWNLOAD, IDM_UPLOADが選択されたとき、 の処理が今までと少し変更になっています。ひとつは自作関数MyConnect, MyDown, MyUp の引数が変更になって、最後にhStatusが追加されています。 また、リストビューをソート後、ステータスバーの状態表示を消しています。 これを行わないと、最後の状態表示がずっと残ってしまうからです。
今回新しく加わったIDM_REMOVEDIR, IDM_UPDIRFTP, IDM_UPDIRLOCALについても ほとんど同じ処理です。
この関数の引数がひとつ増えています。最後のhStatusがそうです。 今までと中身は大体同じなのですが、STATUSCALLBAC構造体(自作)のhwndStatus メンバにhStaticではなくてhStatusを設定して、InternetConnect関数に渡しています。 状態をステータスバーに表示するためです。BOOL MyConnect(HWND hWnd, INETHANDLE *lpinet, ACCOUNT myact, FTPADDRESS ftpadr, HWND hList, HWND hStatic, HWND hStatus) { char szStr[128], szStr2[128]; STATUSCALLBACK sc; if (bConnect) { MessageBox(hWnd, "すでに接続済みです", "接続済", MB_OK); return TRUE; } if (strcmp(myact.szPassWord, "") == 0 || strcmp(myact.szPassWord, "") ==0) { MessageBox(hWnd, "アカウントが設定されていません", "失敗", MB_OK); return FALSE; } if (strcmp(ftpadr.szHost, "") == 0) { MessageBox(hWnd, "FTPのホスト名が設定されていません", "失敗", MB_OK); return FALSE; } if (strcmp(ftpadr.szBaseDir, "") == 0) { MessageBox(hWnd, "基準となるディレクトリが設定されていません", "失敗", MB_OK); return FALSE; } lpinet->hInternet = InternetOpen("myftp01", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); if (lpinet->hInternet == NULL) { MessageBox(hWnd, "インターネットを開けません", "失敗", MB_OK); InternetCloseHandle(lpinet->hInternet); return FALSE; } if (InternetSetStatusCallback(lpinet->hInternet, MyInetCallback) == INTERNET_INVALID_STATUS_CALLBACK) { MessageBox(hWnd, "コールバックを設定できません", "Error", MB_OK); return FALSE; } sc.dwFrom = CONTEXT_CONNECT; sc.hwndStatus = hStatus; lpinet->hHost = InternetConnect(lpinet->hInternet, ftpadr.szHost, INTERNET_DEFAULT_FTP_PORT, myact.szUserName, myact.szPassWord, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, (DWORD)&sc); if (lpinet->hHost == NULL) { MessageBox(hWnd, "接続中にエラー発生", "OK", MB_OK); InternetCloseHandle(lpinet->hInternet); return FALSE; } if (!FtpSetCurrentDirectory(lpinet->hHost, ftpadr.szBaseDir)) { MessageBox(hWnd, "ディレクトリの設定ができません", "失敗", MB_OK); return FALSE; } SendMessage(hStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)"接続完了"); MessageBox(hWnd, "FTPに接続しました", "接続完了", MB_OK); strcpy(szStr, szWindowTitle); wsprintf(szStr2, " <<%sに接続済み>>", ftpadr.szHost); strcat(szStr, szStr2); SetWindowText(hWnd, szStr); GetAllFiles(hWnd, hList, hStatic, lpinet); return TRUE; }
この関数も引数がひとつ増えました(hStatus)。STATUSCALLBACK構造体の hwndStatusメンバにhStatusを設定してFtpGetFile関数に渡すのはMyConnect関数と同じです。void MyDown(HWND hWnd, INETHANDLE inet, FTPADDRESS ftpadr, FNAME *lpfname, HWND hList, HWND hListL, HWND hStaticL, HWND hStatus) { HINSTANCE hInst; int iIndex; static STATUSCALLBACK sc; if (!bConnect) { MessageBox(hWnd, "インターネットに接続されていません", "失敗", MB_OK); return; } sc.hwndStatus = hStatus; sc.dwFrom = CONTEXT_GETFILE; iIndex = ListView_GetNextItem(hList, -1, LVNI_SELECTED); ListView_GetItemText(hList, iIndex, 0, lpfname->szFName, MAX_PATH); GetWindowText(hStaticL, lpfname->szLocalFileName, sizeof(lpfname->szLocalFileName)); strcat(lpfname->szLocalFileName, "\\"); strcat(lpfname->szLocalFileName, lpfname->szFName); hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); if (DialogBoxParam(hInst, "MYGETFNAME", hWnd, (DLGPROC)MyGetFNameProc, (LPARAM)lpfname) == IDCANCEL) return; if (!FtpGetFile(inet.hHost, //FTPのインターネットハンドル lpfname->szFName, //ダウンロードするファイル lpfname->szLocalFileName, //ダウンロード先のパス付ファイル名 TRUE, //ダウンロード先に同名のファイルがあるときエラーにする(上書き防止) FILE_ATTRIBUTE_NORMAL, //ダウンロード先に作られるファイルのアトリビュート FTP_TRANSFER_TYPE_BINARY, //バイナリファイルとしてダウンロード (DWORD)&sc)) { MessageBox(hWnd, "ダウンロードに失敗しました。", "失敗", MB_OK); return; } SetMyLocalDir(hWnd, hListL, hStaticL); MessageBox(hWnd, "無事ダウンロードできました", "OK", MB_OK); return; }
MyGetFNameProc, SetAccount, MyAccountProc, SetHost, MyFtpAddressProc, GetAllFiles, SetMyLocalDir, ChangeLocalDrive, MyDriveProcの各関数に変更はありません。
この関数も引数が増えました(hStatus)。また、前章では状態表示を行いませんでしたが 今回からアップロード時にも状態表示を行います。ダウンロードのときと要領は同じです。 ソースを眺めてみてください。void MyUp(HWND hWnd, INETHANDLE ih, HWND hList, HWND hStatic, HWND hListL, HWND hStaticL, HWND hStatus) { int iIndex; DWORD dwSize; char szMsg[512], szFile[MAX_PATH], szFTPPath[MAX_PATH]; STATUSCALLBACK sc; if (bConnect == FALSE) { MessageBox(hWnd, "インターネットに接続されていません", "失敗", MB_OK); return; } dwSize = sizeof(szFTPPath); iIndex = ListView_GetNextItem(hListL, -1, LVNI_SELECTED); ListView_GetItemText(hListL, iIndex, 0, szFile, sizeof(szFile)); FtpGetCurrentDirectory(ih.hHost, szFTPPath, &dwSize); wsprintf(szMsg, "「%s」を「%s」にアップロードします。\nよろしいですか。", szFile, szFTPPath); iIndex = MessageBox(hWnd, szMsg, "アップロード", MB_YESNO | MB_ICONQUESTION); if (iIndex == IDNO) return; sc.dwFrom = CONTEXT_PUTFILE; sc.hwndStatus = hStatus; if (!FtpPutFile(ih.hHost, szFile, szFile, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_RELOAD, (DWORD)&sc)) { MessageBox(hWnd, "アップロードに失敗しました", "失敗", MB_OK); return; } MessageBox(hWnd, "無事アップロードできました", "成功", MB_OK); GetAllFiles(hWnd, hList, hStatic, &ih);//ftpカレントディレクトリ再表示 return; }
MyFtpDelFile, MyFtpCreatDir, MyCreateDirProcの各関数に変更はありません。
FTPのディレクトリを削除する関数です。void MyFtpRemoveDir(HWND hWnd, INETHANDLE inet, HWND hList, HWND hStatic) { char szDir[MAX_PATH], szPath[MAX_PATH], szCurPath[MAX_PATH], szStr[MAX_PATH]; int iIndex, iLength, i; DWORD dwSize; if (bConnect == FALSE) { MessageBox(hWnd, "インターネットに接続されていません", "失敗", MB_OK); return; } dwSize = sizeof(szCurPath); iIndex = ListView_GetNextItem(hList, -1, LVNI_SELECTED); ListView_GetItemText(hList, iIndex, 0, szDir, sizeof(szDir)); if (strstr(szDir, "<dir> ") != szDir) { MessageBox(hWnd, "ディレクトリではありません", "失敗", MB_OK); return; } iLength = lstrlen(szDir); for (i = 0; i < lstrlen(szDir) - 5; i++) szPath[i] = szDir[i + 6]; FtpGetCurrentDirectory(inet.hHost, szCurPath, &dwSize); wsprintf(szStr, "「%s」からディレクトリ「%s」を削除してもよろしいですか。", szCurPath, szPath); iIndex = MessageBox(hWnd, szStr, "ディレクトリの削除", MB_YESNO | MB_ICONQUESTION); if (iIndex == IDNO) return; if (FtpRemoveDirectory(inet.hHost, szPath) == FALSE) { MessageBox(hWnd, "ディレクトリ削除に失敗しました。\n" "ディレクトリ内にファイルが存在しないか確認してください", "失敗", MB_OK); return; } GetAllFiles(hWnd, hList, hStatic, &inet); return; }
FTPサーバー上のディレクトリを削除します。BOOL FtpRemoveDirectory( IN HINTERNET hFtpSession, IN LPCSTR lpszDirectory );
hFtpSessionには、FTPセッションのハンドルを指定します。
lpszDirectoryには、削除するディレクトリの名前を指定します。
ディレクトリ中にファイルが存在するとこの関数は失敗します。
MakeMyList, InsertMyColumn, MyCompProcの各関数に変更はありません。
状態表示用のコールバック関数です。 状態をスタティックコントロールに表示していたのを、ステータスバーに表示するように変更しました。 アップロード時の状態も表示するようにしました。 また、ダウンロード時のdwTemp変数を廃止して受信バイト数をそのまま表示するようにしました。void CALLBACK MyInetCallback(HINTERNET hInet, DWORD dwContx, DWORD dwStatus, LPVOID lpvStatus, DWORD dwLength) { char str[1024]; LPDWORD lpdwByte; STATUSCALLBACK *lpsc; lpsc = (STATUSCALLBACK *)dwContx; switch (lpsc->dwFrom) { case CONTEXT_GETFILE: switch (dwStatus) { case INTERNET_STATUS_SENDING_REQUEST: SendMessage(lpsc->hwndStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)"サーバーに要求を送信しています"); break; case INTERNET_STATUS_RESPONSE_RECEIVED: lpdwByte = (LPDWORD)lpvStatus; wsprintf(str, "%dバイト受信しました", *lpdwByte); SendMessage(lpsc->hwndStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)str); break; case INTERNET_STATUS_HANDLE_CREATED: SendMessage(lpsc->hwndStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)"FTPセッションハンドルが作られました"); break; } break; case CONTEXT_PUTFILE: switch (dwStatus) { case INTERNET_STATUS_SENDING_REQUEST: SendMessage(lpsc->hwndStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)"サーバーに要求を送信しています"); break; case INTERNET_STATUS_REQUEST_SENT: lpdwByte = (LPDWORD)lpvStatus; wsprintf(str, "%dバイト送信しました", *lpdwByte); SendMessage(lpsc->hwndStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)str); break; case INTERNET_STATUS_RESPONSE_RECEIVED: lpdwByte = (LPDWORD)lpvStatus; wsprintf(str, "%dバイト受信しました", *lpdwByte); SendMessage(lpsc->hwndStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)str); break; case INTERNET_STATUS_RECEIVING_RESPONSE: SendMessage(lpsc->hwndStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)"サーバーの反応を待っています"); break; case INTERNET_STATUS_HANDLE_CREATED: SendMessage(lpsc->hwndStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)"FTPセッションハンドルが作られました"); break; } break; case CONTEXT_CONNECT: switch (dwStatus) { case INTERNET_STATUS_CONNECTING_TO_SERVER: wsprintf(str, "ソケットアドレス%sに接続中", lpvStatus); SendMessage(lpsc->hwndStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)str); break; case INTERNET_STATUS_CONNECTED_TO_SERVER: wsprintf(str, "ソケットアドレス%sに接続しました", lpvStatus); SendMessage(lpsc->hwndStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)str); break; case INTERNET_STATUS_CONNECTION_CLOSED: strcpy(str, "サーバーからの接続をクローズしました"); SendMessage(lpsc->hwndStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)str); break; case INTERNET_STATUS_RECEIVING_RESPONSE: SendMessage(lpsc->hwndStatus, SB_SETTEXT, (WPARAM)2 | 0, (LPARAM)"サーバーからの応答を待っています"); break; } break; } return; }
だんだんプログラムが長くなってきて面倒そうに見えますが、一つ一つを見ていくと 大して難しくはありません。あと、改良点はまだまだあります。不満な点を列挙してみて 改善を試みてください。
Update 30/Aug/1999 By Y.Kumei