第224章 右クリックメニューとステータスバーを付ける


今回は、今まで作ったプログラムを少し手直しします。 ひとつは、リストビューからマウスで選択したファイルや ディレクトリに対して右クリックで操作を選択できるようにします。

また、状態をステータスバーに表示するようにします。

メニューに「ひとつ上のディレクトリへ」を加えます。その他 にも少し手を加えます。



左の図はFTPのリストビュー上で右クリックしたときに表示される ボップアップメニューです。これで、少し使いやすくなりました。



左の図のように、途中経過をステータスバーに表示するようにしました。



では、早速プログラムを見てみましょう。

// 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);

プログラムがちょっと長くなりすぎたので、defineとtypedefと関数プロトタイプ宣言を 独立したヘッダーファイル(myftp.h)にしました。

///////////////////////////////////////////////////////////////////////////// // // 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" が増えました。右クリックされる場所によってポップアップメニューを変えています。

// 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;//インターネットに接続しているかどうか

ソースファイル本体の最初のほうは大分すっきりしました。 あたりまえですがmyftp.hをインクルードするのを忘れないでください。 また、Comctl32.lib, Wininet.libをリンクするのを忘れないでください。

WinMain, InitApp, InitInstanceの各関数に変更はありません。

//ウィンドウプロシージャ 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_CREATEメッセージが来たときにステータスバーを作ります。INITCOMMONCONTROLEX 構造体のdwICCメンバにICC_BAR_CLASSESを加えるのを忘れないでください。また、 ステータスバーの高さをstatic変数に保存しておきます。

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についても ほとんど同じ処理です。

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がそうです。 今までと中身は大体同じなのですが、STATUSCALLBAC構造体(自作)のhwndStatus メンバにhStaticではなくてhStatusを設定して、InternetConnect関数に渡しています。 状態をステータスバーに表示するためです。

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; }

この関数も引数がひとつ増えました(hStatus)。STATUSCALLBACK構造体の hwndStatusメンバにhStatusを設定してFtpGetFile関数に渡すのはMyConnect関数と同じです。

MyGetFNameProc, SetAccount, MyAccountProc, SetHost, MyFtpAddressProc, GetAllFiles, SetMyLocalDir, ChangeLocalDrive, MyDriveProcの各関数に変更はありません。

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; }

この関数も引数が増えました(hStatus)。また、前章では状態表示を行いませんでしたが 今回からアップロード時にも状態表示を行います。ダウンロードのときと要領は同じです。 ソースを眺めてみてください。

MyFtpDelFile, MyFtpCreatDir, MyCreateDirProcの各関数に変更はありません。

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 );

FTPサーバー上のディレクトリを削除します。

hFtpSessionには、FTPセッションのハンドルを指定します。

lpszDirectoryには、削除するディレクトリの名前を指定します。

ディレクトリ中にファイルが存在するとこの関数は失敗します。

MakeMyList, InsertMyColumn, MyCompProcの各関数に変更はありません。

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; }

状態表示用のコールバック関数です。 状態をスタティックコントロールに表示していたのを、ステータスバーに表示するように変更しました。 アップロード時の状態も表示するようにしました。 また、ダウンロード時のdwTemp変数を廃止して受信バイト数をそのまま表示するようにしました。

だんだんプログラムが長くなってきて面倒そうに見えますが、一つ一つを見ていくと 大して難しくはありません。あと、改良点はまだまだあります。不満な点を列挙してみて 改善を試みてください。


[SDK第3部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 30/Aug/1999 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。