第225章 FTP上のテキストファイルを読む


FTP上のファイルをいちいちダウンロードせずに、ちょっと中身を 確かめられると大変便利ですね。今回はFTP上のテキストファイルを ダウンロードせずに表示する機能を追加します。



FTPのリストビューでファイルを選択して右クリック「テキストファイルの読み出し」 をクリックすると左の図のようなテキストビューア(?)が出現します。 これは、単にダイアログボックスにエディットコントロールを張っただけですが 見やすいようにダイアログの大きさを変えることもできます。

FTP上のテキストファイルを読むには次のようにします。

1.FtpOpen関数でファイルをオープンする(戻り値としてHINTERNETハンドルを取得) 2.InternetReadFile関数でファイルを読む 3.1.のハンドルをクローズする

たったこれだけです。

HINTERNET FtpOpenFile( IN HINTERNET hFtpSession, IN LPCSTR lpszFileName, IN DWORD fdwAccess, IN DWORD dwFlags, IN DWORD dwContext );

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

lpszFileNameにはファイル名を指定します。

fdwAccessにはファイルへのアクセス方法を指定します。
GENERIC_READかGENERIC_WRITEのいずれかです。

dwFlagsには転送タイプを次の中から1つを指定します。

FTP_TRANSFER_TYPE_ASCIIアスキー転送法を用います。
FTP_TRANSFER_TYPE_BINARYFTPイメージ転送法を用います。
FTP_TRANSFER_TYPE_UNKNOWNFTP_TRANSFER_TYPE_BINARYと同じ。
INTERNET_FLAG_TRANSFER_ASCIIアスキーとしてファイル転送を行う。
INTERNET_FLAG_TRANSFER_BINARYバイナリーファイルとして転送を行う。

さらにINTERNET_FLAG_**でキャッシュ関係のオプションを選択することもできます。 これは、FtpFindFirstFileのdwFlagsと同じです。 第218章を参照してください。

dwContextはアプリケーション定義データを指定します。状態表示で使います。 今回は特に指定しません。

BOOL InternetReadFile( IN HINTERNET hFile, IN LPVOID lpBuffer, IN DWORD dwNumberOfBytesToRead, OUT LPDWORD lpNumberOfBytesRead );

hFileには、FtpOpenFile関数の戻り値を指定します。

lpBufferには読み出したデータを蓄えるバッファのアドレスを指定します。

dwNumberOfBytesToReadには読み込むバイト数を指定します。

lpNumberOfBytesReadには読み込んだバイト数を受け取る変数のアドレスを指定します。

成功したときはTRUEが返されます。

この関数を使ってHTMLファイルを読み込むときはバッファを大きめに取らないと おかしなことが起こります。

では、プログラムを見てみることにします。

// 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); LRESULT CALLBACK MyTextProc(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); void MyFtpRead(HWND, HWND, INETHANDLE, HWND);

MyTextProc(ダイアログのプロシージャ)とMyFtpRead関数の プロトタイプ宣言が増えました。

// myftp09.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_REMOVEDIR MENUITEM "ファイルの削除...", IDM_DELFILE MENUITEM SEPARATOR MENUITEM "ひとつ上のディレクトリへ", IDM_UPDIRFTP MENUITEM SEPARATOR MENUITEM "テキストファイルの読み出し(&R)...", IDM_READ MENUITEM SEPARATOR MENUITEM "切断(&X)...", IDM_DISCONNECT 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 MENUITEM SEPARATOR MENUITEM "テキストファイルの読み出し(&R)...", IDM_READ 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 MYTEXTDLG DIALOG DISCARDABLE 0, 0, 170, 167 STYLE DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "テキスト表示" FONT 9, "MS Pゴシック" BEGIN EDITTEXT IDC_EDIT1,7,7,155,133,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_OEMCONVERT | ES_READONLY | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL | NOT WS_TABSTOP PUSHBUTTON "閉じる",IDC_BUTTON1,53,144,63,16 END

"MYMENU"および"POPUPMENUFTP"で「テキストファイルの読み出し」(IDM_READ) が増えました。

ダイアログで"MYTEXTDLG"が増えました。最小化、最大化ボタンを有しています。 また、WS_THICKFRAMEスタイルを持っているのでウィンドウの大きさを変えることができます。

// myftp09.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[] = "myftp09"; //ウィンドウクラス BOOL bConnect = FALSE;//インターネットに接続しているかどうか

ウィンドウクラス名がmyftp09になった以外同じです。

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

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { ...省略 case WM_COMMAND: switch (LOWORD(wp)) { ...省略 case IDM_READ: MyFtpRead(hWnd, hList, inet, hStatus); break; ...省略

WM_COMMANDの中にIDM_READが増えただけです。

その他の関数は前章と変更はありません。

void MyFtpRead(HWND hWnd, HWND hList, INETHANDLE inet, HWND hStatus) { int id; DWORD dwRead = 0; char szFName[MAX_PATH], szStr[MAX_PATH], szSize[16], *lpszBuf; HINTERNET hFile; DWORD dwSize; HGLOBAL hGlobal; HINSTANCE hInst; if (!bConnect) { MessageBox(hWnd, "インターネットに接続されていません", "失敗", MB_OK); return; } id = ListView_GetNextItem(hList, -1, LVNI_SELECTED); ListView_GetItemText(hList, id, 0, szFName, sizeof(szFName)); if (strstr(szFName, "<dir> ") == szFName) { wsprintf(szStr, "%sはファイルではありません", szFName); MessageBox(hWnd, szStr, "Error", MB_OK); return; } ListView_GetItemText(hList, id, 1, szSize, sizeof(szSize)); dwSize = atoi(szSize); //ファイルサイズより大きめにメモリを確保 hGlobal = GlobalAlloc(GHND, dwSize + 2048); if (hGlobal == NULL) { MessageBox(hWnd, "メモリ確保に失敗しました", "Error", MB_OK); return; } lpszBuf = (char *)GlobalLock(hGlobal); hFile = FtpOpenFile(inet.hHost, szFName, GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0); if (hFile == NULL) { MessageBox(hWnd, "FtpOpenFile失敗です", "Error", MB_OK); return; } if (InternetReadFile(hFile, lpszBuf, dwSize + 2048, &dwRead) != TRUE) { MessageBox(hWnd, "読み出し失敗", "Error", MB_OK); GlobalUnlock(hGlobal); GlobalFree(hGlobal); InternetCloseHandle(hFile); return; } hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); DialogBoxParam(hInst, "MYTEXTDLG", hWnd, (DLGPROC)MyTextProc, (LPARAM)lpszBuf); GlobalUnlock(hGlobal); GlobalFree(hGlobal); InternetCloseHandle(hFile); return; }

FTP上のテキストファイルを読み出す関数です。

FtpOpneFile関数で転送タイプをバイナリにすると、エディットコントロールで 改行がうまく表示されません。また、用意するバッファは余裕を持たせてください。 読み込むサイズも多めにしておきます。バッファに内容を読み込んでから DialogBoxParam関数でダイアログを出します。このとき最後の引数に バッファのアドレスを指定しておけば、バッファをグローバル変数にする 必要がありません。

LRESULT CALLBACK MyTextProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hEdit, hBut; static int wx, wy; //ボタンの大きさ char *lpbuf; RECT rc; switch (msg) { case WM_INITDIALOG: lpbuf = (char *)lp; hEdit = GetDlgItem(hDlg, IDC_EDIT1); Edit_SetText(hEdit, lpbuf); hBut = GetDlgItem(hDlg, IDC_BUTTON1); GetWindowRect(hBut, &rc); wx = rc.right - rc.left; wy = rc.bottom - rc.top; return TRUE; case WM_SIZE: MoveWindow(hEdit, 7, 7, LOWORD(lp) - 14, HIWORD(lp) - 50, TRUE); MoveWindow(hBut, (LOWORD(lp) - wx) / 2, HIWORD(lp) - 43 + (43 - wy) / 2, wx, wy, TRUE); return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDCANCEL: case IDC_BUTTON1: EndDialog(hDlg, IDOK); return TRUE; } return FALSE; } return FALSE; }

ダイアログのプロシージャです。

WM_INITDIALOGメッセージが来たとき、lpにテキストを読み込んだバッファの アドレスが入っています。

ダイアログの大きさが変化したら、エディットコントロールの大きさとボタンの 位置を調整します。一般のウィンドウと異なり最初にダイアログが現れたときには WM_SIZEメッセージは来ません。ユーザーがダイアログの大きさを変えたときだけです。 また、当たり前ですがダイアログのスタイルにWS_THICKFRAMEが入っていないと WM_SIZEメッセージは一度も来ません。

今回は簡単でした。それにしてもこのプログラムは立ち上げるたびに FTPのアドレスやら基準になるディレクトリなどを入力しなくてはならず 面倒です。INIファイルかレジストリに基本設定を保存するようにしてみてください。


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

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