第277章 フォルダ選択ダイアログを使う


今回は実際にフォルダ選択ダイアログを使ってみます。


// unlha05.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "書庫の新規作成(&N)...", IDM_NEW MENUITEM "書庫を開く(&O)...", IDM_OPEN MENUITEM SEPARATOR MENUITEM "書庫にファイルを追加(&A)...", IDM_ADD MENUITEM "書庫からファイルを削除(&D)...", IDM_DEL MENUITEM SEPARATOR MENUITEM "解凍(&E)...", IDM_EXTRACT MENUITEM SEPARATOR MENUITEM "自己解凍書庫の作成(&S)...", IDM_SFX MENUITEM SEPARATOR MENUITEM "終了(&X)...", IDM_END END POPUP "表示(&V)" BEGIN MENUITEM "ツールバー(&T)", IDM_TOOL, CHECKED MENUITEM "ステータスバー(&S)", IDM_STATUS, CHECKED END END ///////////////////////////////////////////////////////////////////////////// // // Toolbar // MYTOOLBAR TOOLBAR DISCARDABLE 16, 15 BEGIN BUTTON IDM_ADD BUTTON IDM_EXTRACT BUTTON IDM_SFX END ///////////////////////////////////////////////////////////////////////////// // // Bitmap // MYTOOLBAR BITMAP DISCARDABLE "bmp00001.bmp" ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE DISCARDABLE BEGIN IDS_NEW "新規の書庫を作ります" IDS_OPEN "書庫を開きます" IDS_DELETE "書庫からファイルを削除します" IDS_ADD "書庫にファイルを追加します" IDS_EXTRACT "書庫からファイルを解凍します" IDS_SFX "自己解凍書庫を作ります" END

当然ですが、MYDIRDLGダイアログボックスのリソース・スクリプトが無くなりました。

// unlha05.cpp #ifndef STRICT #define STRICT #endif #define ID_LISTVIEW 100 #define ID_TOOLBAR 101 #define ID_REBAR 102 #define ID_STATIC 103 #define ID_TOOLMENU 104 #define ID_STATUSBAR 105 // unlha32.hでtime_tを使うためtime.hが必要です #include <time.h> // sprintf()を使う関係上stdio.hが必要です #include <stdio.h> #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include <winnetwk.h> #include <shlobj.h> #include "unlha32.h" #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int CALLBACK SHMyProc(HWND, UINT, LPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); BOOL MyAdd(HWND, int); BOOL MyOpen(HWND, int); BOOL MySetColumn(HWND); BOOL MyExtract(HWND); BOOL MyDel(HWND hWnd); BOOL MySFX(HWND hWnd); char szClassName[] = "unlha05"; //ウィンドウクラス char szWindowTitle[] = "猫でもわかるアーカイバ [%s]"; HINSTANCE hInst; char szCmdLine[1024]; char szLZHFile[MAX_PATH], szOrgFile[1024 * 10], szTitle[MAX_PATH]; char szDir[MAX_PATH]; HWND hList, hTool, hRb; BOOL bTool = TRUE, bStatus = TRUE; //Toolbar, Statusbarを表示するかどうか TBBUTTON tbBtn[] = { {STD_FILENEW, IDM_NEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_FILEOPEN, IDM_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_DELETE, IDM_DEL, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0} }; TBBUTTON tbLHA[] = { {0, IDM_ADD, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {1, IDM_EXTRACT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {2, IDM_SFX, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0} };

winnetwk.h, shlobj.hのインクルードが増えました。フォルダ選択のためのダイアログボックス (旧式)はなくなったのでMyDirProcプロシージャもなくなりました。 代わりにSHMyProcプロシージャが増えました。

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

BOOL MyExtract(HWND hWnd) { int nItem = -1; char szName[MAX_PATH], szBuf[1024]; BOOL bDir = FALSE; BROWSEINFO bi; ITEMIDLIST *lpid; HRESULT hr; LPMALLOC pMalloc = NULL;//IMallocへのポインタ if (ListView_GetSelectedCount(hList) == 0) { MessageBox(hWnd, "解凍するファイルが選択されていません", "Error", MB_OK); return FALSE; } if (MessageBox(hWnd, "解凍先ディレクトリを指定しますか", "ディレクトリ確認", MB_YESNO | MB_ICONQUESTION) == IDYES) { memset(&bi, 0, sizeof(BROWSEINFO)); bi.hwndOwner = hWnd; bi.lpfn = SHMyProc; bi.ulFlags = BIF_EDITBOX | BIF_STATUSTEXT | BIF_VALIDATE; bi.lpszTitle = "解凍先ディレクトリ指定"; lpid = SHBrowseForFolder(&bi); if (lpid == NULL) { return FALSE; } else { hr = SHGetMalloc(&pMalloc); if (hr == E_FAIL) { MessageBox(hWnd, "SHGetMalloc Error", "Error", MB_OK); return FALSE; } SHGetPathFromIDList(lpid, szDir); if (szDir[strlen(szDir) - 1] != '\\') strcat(szDir, "\\"); pMalloc->Free(lpid); pMalloc->Release(); bDir = TRUE; } } strcpy(szCmdLine, "e "); strcat(szCmdLine, szLZHFile); if (bDir) { strcat(szCmdLine, " "); strcat(szCmdLine, "\""); strcat(szCmdLine, szDir); strcat(szCmdLine, "\""); } while ((nItem = ListView_GetNextItem(hList, nItem, LVNI_SELECTED)) != -1) { ListView_GetItemText(hList, nItem, 0, szName, sizeof(szName)); strcat(szCmdLine, " "); strcat(szCmdLine, szName); } if(Unlha(hWnd, szCmdLine, szBuf, sizeof(szBuf))) { MessageBox(hWnd, "エラーが発生しました", "Error", MB_OK); return FALSE; } MessageBox(hWnd, szBuf, "OK", MB_OK); MessageBox(hWnd, "解凍が完了しました", "完了", MB_OK); return TRUE; }

「解凍先ディレクトリを指定しますか」の問いに「はい」と答えるとフォルダ選択ダイアログを出します。

まず、BROWSEINFO構造体のメンバをセットします。
lpfnメンバを設定することにより、このダイアログのプロシージャを書くことができます。

ulFlagsメンバにBIF_VALIDATEを加えることにより、ユーザーがエディットボックスに間違った フォルダ名を書き込んだときに、プロシージャにBFFM_VALIDATEFAILEDメッセージを送るようにします。 プロシージャではこのメッセージに応答します。

SHBrowseForFolder関数を呼ぶことによりダイアログを出します。 この時の戻り値がITEMIDLIST構造体へのポインタとなります。これがNULLであればユーザーは フォルダを選択しなかったことになります。

ITEMIDLIST構造体のポインタからユーザーが選択したフォルダを知るにはSHGetPathFromIDList 関数を使うことになります。

BOOL SHGetPathFromIDList( LPCITEMIDLIST pidl, LPSTR pszPath );

pidlはITEMIDLIST構造体へのポインタです。

pszPathは、パスを受け取るバッファのアドレスです。

さてシステムで確保した、pidlは解放しなくてはなりません。 これは、まずIMallocインターフェイスのポインタ(pMalloc)を取得して

pMalloc->Free(pidl);

としなくてはいけません。

IMalloc::Free void Free( void * pv );

pvは解放されるメモリブロックです。

次に参照カウンタを1減らします。これは

IUnknown::Release ULONG Release(void);

すべてのCOMインターフェイスはIUnknownインターフェイスから継承されています。 インターフェイスはC++のクラスと似ていますが、クラスとは異なります。

pMalloc->Release();

で参照カウンターを1つ減らすことができます。

なお、ここではCOMについてはこれ以上深く言及しません。

MyDel, MySFX関数に変更はありません。

int CALLBACK SHMyProc(HWND hWnd, UINT msg, LPARAM lp1, LPARAM lp2) { char szFolder[MAX_PATH]; char szBuf[1024]; ITEMIDLIST *lpid; switch (msg) { case BFFM_SELCHANGED: lpid = (ITEMIDLIST *)lp1; SHGetPathFromIDList(lpid, szFolder); wsprintf(szBuf, "現在「%s」が選択されています", szFolder); SendMessage(hWnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)szBuf); return 0; case BFFM_VALIDATEFAILED: MessageBox(hWnd, "不正なフォルダです", "Error", MB_OK); return 1; } return 0; }

フォルダ選択ダイアログのプロシージャです。

BFFM_SELCHANGEDメッセージが来たら(選択されているフォルダが変化したら) 現在選択されているフォルダをステータス行に表示します。このメッセージが来たとき lp1は、ITEMIDLIST構造体へのポインタです。

BFFM_VALIDATEFAILEDは、ユーザーがエディットボックスに誤ったフォルダ名を入力したときに やってきます。この時lp1はその名前のポインタです。また、0以外を返すとダイアログは表示を 維持し、0を返すと消えます。

さて、このプログラムではフォルダ選択ダイアログが出てきたときには、 ステータス行に「現在「」が選択されています」と表示されます。 これは、ちょっと格好が悪いですね。初期状態で何かフォルダを選択させておくか もしくはステータス行に表示する文字列を変えておく必要があります。


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

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