今回はFTPのカレントディレクトリに対して新規にサブディレクトリを
作るダイアログを出します。
ダイアログボックスの名前を"MYCREATEDIR"とします。
今回必要な関数はFtpPutFile, FtpCreateDirectory, FtpDeleteFileです。
FTPサーバーにファイルをおきます。BOOL FtpPutFile( IN HINTERNET hFtpSession, IN LPCSTR lpszLocalFile, IN LPCSTR lpszNewRemoteFile, IN DWORD dwFlags, IN DWORD dwContext );
hFtpSessionは、FTPセッションのハンドルです。
lpszLocalFileはローカルシステムより送られるファイル名です。
lpszNewRemoteFileは、リモートシステムに作られるファイル名です。
dwFlagsは、INTERNET_FLAG_***を指定します。FtpGetFile関数の キャッシュ関係の指定と同じです。 (第216章参照)
dwContextには、アプリケーション定義の値を指定します。
FTPサーバーに新しいディレクトリを作ります。BOOL FtpCreateDirectory( IN HINTERNET hFtpSession, IN LPCSTR lpszDirectory );
hFtpSessionは、FTPセッションのハンドルを指定します。
lpszDirectoryには、新しく作るディレクトリの名前を指定します。
FTPサーバー上のファイルを削除します。成功したらTRUEが返されます。BOOL FtpDeleteFile( IN HINTERNET hFtpSession, IN LPCSTR lpszFileName );
hFtpSessionには、FTPセッションのハンドルを指定します。
lpszFileNameには、削除するファイルの名前を指定します。
では、プログラムを見てみましょう。
「ファイルのアップロード」「ディレクトリの作成」「ファイルの削除」などの メニュー項目が増えました。また、直ちに実行されない項目の後ろに 「...」をつけました。// myftp04.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // 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_DELFILE MENUITEM SEPARATOR MENUITEM "切断(&X)", IDM_DISCONNECT END POPUP "ローカル(&L)" BEGIN MENUITEM "ドライブの変更(&D)...", IDM_LOCALDRIVE END POPUP "設定(&S)" BEGIN MENUITEM "アカウント設定(&A)...", IDM_ACCOUNT MENUITEM "ホスト設定(&H)...", IDM_GETHOST 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
「FTPディレクトリの新規作成」ダイアログ("MYCREATEDIR")が増えました。
FTPの新規ディレクトリ作成ダイアログのプロシージャの宣言が 増えました。(MyCreateDirProc)// myftp04.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <wininet.h> #include <windowsx.h> #include "resource.h" #define ID_LIST 100 #define ID_STATIC 101 #define ID_LISTL 102 #define ID_STATICL 103 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; 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); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL MyConnect(HWND, INETHANDLE *, ACCOUNT, FTPADDRESS, HWND, HWND); void MyDown(HWND, INETHANDLE, FTPADDRESS, FNAME *, 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); void MyFtpDelFile(HWND, INETHANDLE, HWND, HWND); void MyFtpCreatDir(HWND, INETHANDLE, HWND, HWND); const char szWindowTitle[] = "猫でもわかるFTP"; char szClassName[] = "myftp04"; //ウィンドウクラス BOOL bConnect = FALSE;//インターネットに接続しているかどうか
MyDown関数(FTPからファイルをダウンロードする)の引数を 変更しました。これは、ダウンロード後ローカルのディレクトリ表示 をやり直すためです。(後述)
MyUp, MyFtpDelFile, MyFtpCreateDir関数を新規に作成します。
WinMain, InitApp, InitInstanceの各関数に変更はありません。
メニューから「ftp」「ファイルのダウンロード」(IDM_DOWNLOAD)が選択されたとき MyDown関数を呼びますが、これの引数が変更になっています。//ウィンドウプロシージャ 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; static HINSTANCE hInst; RECT rc; HDWP hDwp; char szDir[MAX_PATH], szBuf[MAX_PATH]; switch (msg) { case WM_CREATE: hInst = ((LPCREATESTRUCT)lp)->hInstance; GetClientRect(hWnd, &rc); hList = CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | LBS_SORT | LBS_NOTIFY, 0, 0, 0, 0, hWnd, (HMENU)ID_LIST, hInst,NULL); hListL = CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | LBS_SORT | LBS_NOTIFY, 0, 0, 0, 0, hWnd, (HMENU)ID_LISTL, hInst, NULL); 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); 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, SWP_SHOWWINDOW); hDwp = DeferWindowPos(hDwp, hList, HWND_TOP, LOWORD(lp) / 2 + 5, 40, LOWORD(lp) / 2 - 15, HIWORD(lp) - 50, SWP_SHOWWINDOW); EndDeferWindowPos(hDwp); break; case WM_COMMAND: switch (LOWORD(wp)) { case ID_LIST: if (HIWORD(wp) == LBN_DBLCLK) { iIndex = ListBox_GetCurSel(hList); ListBox_GetText(hList, iIndex, szDir); for (i = 0; i <= lstrlen(szDir) -5 ; i++) { szBuf[i] = szDir[i + 6]; } FtpSetCurrentDirectory(inet.hHost, szBuf); GetAllFiles(hWnd, hList, hStatic, &inet); } break; case ID_LISTL: if (HIWORD(wp) == LBN_DBLCLK) { iIndex = ListBox_GetCurSel(hListL); ListBox_GetText(hListL, iIndex, szDir); for (i = 0; i <= lstrlen(szDir) - 5; i++) { szBuf[i] = szDir[i + 6]; } SetCurrentDirectory(szBuf); SetMyLocalDir(hWnd, hListL, hStaticL); } break; case IDM_LOCALDRIVE: ChangeLocalDrive(hWnd, hListL, hStaticL); break; case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_CONNECT: bConnect = MyConnect(hWnd, &inet, myaccount, myftpaddress, hList, hStatic); break; case IDM_DOWNLOAD: MyDown(hWnd, inet, myftpaddress, &myfname, hList, hListL, hStaticL); break; case IDM_UPLOAD: MyUp(hWnd, inet, hList, hStatic, hListL, hStaticL); break; case IDM_DELFILE: MyFtpDelFile(hWnd, inet, hList, hStatic); break; case IDM_CREATEDIR: MyFtpCreatDir(hWnd, inet, hList, hStatic); 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; }
あと、IDM_UPLOAD, IDM_DELFILE, IDM_CREATEDIRが選択されたとき それぞれ必要な関数を呼んでいます。
MyConnect関数に変更はありません。
ダウンロード後ローカルのファイル表示を更新するため最後にSetMyLocalDir関数を 呼んでいます。これを呼ぶためにMyDown関数の引数も変更しました。void MyDown(HWND hWnd, INETHANDLE inet, FTPADDRESS ftpadr, FNAME *lpfname, HWND hList, HWND hListL, HWND hStaticL) { HINSTANCE hInst; int iIndex; if (!bConnect) { MessageBox(hWnd, "インターネットに接続されていません", "失敗", MB_OK); return; } iIndex = ListBox_GetCurSel(hList); ListBox_GetText(hList, iIndex, lpfname->szFName); 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, //バイナリファイルとしてダウンロード 0 )) { MessageBox(hWnd, "ダウンロードに失敗しました。", "失敗", MB_OK); return; } SetMyLocalDir(hWnd, hListL, hStaticL); MessageBox(hWnd, "無事ダウンロードできました", "OK", MB_OK); return; }
MyGetFNameProc, SetAccount, MyAccountProc, SetHost, MyFtpAddressProc, GetAllFiles, SetMyLocalDir, ChangeLocalDrive, MyDriveProcの各関数に変更はありません。
ローカルのリストボックスからファイルを選択しておいてメニューの「ファイルのアップロード」 を選択するとこの関数が呼ばれます。簡単のためアップ後のファイル名は、ローカルのそれと 同じにしました。アップ後GetAllFiles関数を呼んでFTPのリストボックスを更新します。void MyUp(HWND hWnd, INETHANDLE ih, HWND hList, HWND hStatic, HWND hListL, HWND hStaticL) { int iIndex; DWORD dwSize; char szMsg[512], szFile[MAX_PATH], szFTPPath[MAX_PATH]; if (bConnect == FALSE) { MessageBox(hWnd, "インターネットに接続されていません", "失敗", MB_OK); return; } dwSize = sizeof(szFTPPath); iIndex = ListBox_GetCurSel(hListL); ListBox_GetText(hListL, iIndex, 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; if (!FtpPutFile(ih.hHost, szFile, szFile, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_RELOAD, 0)) { MessageBox(hWnd, "アップロードに失敗しました", "失敗", MB_OK); return; } MessageBox(hWnd, "無事アップロードできました", "成功", MB_OK); GetAllFiles(hWnd, hList, hStatic, &ih);//ftpカレントディレクトリ再表示 return; }
FTPのリストボックスで選択されているファイルを削除します。削除後GetAllFiles関数を 呼んでリストボックスの内容を更新します。void MyFtpDelFile(HWND hWnd, INETHANDLE inet, HWND hList, HWND hStatic) { int iIndex; char szFile[MAX_PATH], szStr[MAX_PATH], szFTPPATH[MAX_PATH]; DWORD dwSize; if (bConnect == FALSE) { MessageBox(hWnd, "インターネットに接続されていません", "失敗", MB_OK); return; } iIndex = ListBox_GetCurSel(hList); ListBox_GetText(hList, iIndex, szFile); dwSize = sizeof(szFTPPATH); FtpGetCurrentDirectory(inet.hHost, szFTPPATH, &dwSize); wsprintf(szStr, "「%s」から「%s」を削除してもよろしいですか", szFTPPATH, szFile); iIndex = MessageBox(hWnd, szStr, "ファイル削除", MB_YESNO | MB_ICONQUESTION); if (iIndex == IDNO) return; FtpDeleteFile(inet.hHost, szFile); GetAllFiles(hWnd, hList, hStatic, &inet);//ftpカレントディレクトリ再表示 return; }
FTPに新規ディレクトリを作る関数です。DialogBoxParam関数で ダイアログを出してディレクトリ名をユーザーに入力してもらいます。 なるべくグローバル変数を使いたくないという主旨で、ディレクトリ名 を格納するszDirのアドレスをLPRAMとしてプロシージャに渡しています。 ダイアログボックスで「キャンセル」ボタンが押されたときは何もせずに 戻ります。そうでないときはFtpCreateDirectory関数でFTPにディレクトリを作ります。 その後GetAllFiles関数を呼んでFTPのリストボックスを更新します。void MyFtpCreatDir(HWND hWnd, INETHANDLE inet, HWND hList, HWND hStatic) { char szDir[MAX_PATH]; HINSTANCE hInst; int iIndex; if (bConnect == FALSE) { MessageBox(hWnd, "インターネットに接続されていません", "失敗", MB_OK); return; } hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); iIndex = DialogBoxParam(hInst, "MYCREATEDIR", hWnd, (DLGPROC)MyCreateDirProc, (LPARAM)szDir); if (iIndex == IDCANCEL) return; FtpCreateDirectory(inet.hHost, szDir); GetAllFiles(hWnd, hList, hStatic, &inet); return; }
WM_INITDIALOGが来たらLPARAMから新規ディレクトリ名を格納する 文字列へのポインタをもらいます。LRESULT CALLBACK MyCreateDirProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static char *lpDirName; static HWND hEdit; switch (msg) { case WM_INITDIALOG: lpDirName = (char *)lp; hEdit = GetDlgItem(hDlg, IDC_EDIT1); return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: Edit_GetText(hEdit, lpDirName, MAX_PATH); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } return FALSE; }
OKボタンが押されたらユーザーが入力したディレクトリ名を取得します。
今回は簡単でした。
Update 08/Aug/1999 By Y.Kumei