『ながっちゃん』のページ

気まぐれ兄ちゃんの独り言

#1[CPP]フォルダ選択のダイアログを表示

Windowsが標準で持っているフォルダ選択のダイアログを表示し、ユーザが選択したフォルダのパスを取得する方法です。

解説

 フォルダ選択のダイアログはWindows APIのSHBrowseForFolder( )を使って表示します。
 サンプルは、ダイアログに関連付けられたクラスの中で呼ばれることを想定しており、関数SelectFolder( )の中でSHBrowseForFolder( )の引数の値を設定しSHBrowseForFolder( )をコールしてフォルダのパスを取得しています。フォルダ選択のダイアログを表示する際、SelectFolder( )の2番目の引数で指定された文字列をフォルダ選択のダイアログ上に表示します。また、コールバック関数BrowseCallbackProc_3( )において、最初に選択されているフォルダを関連とフォルダに設定し、ユーザが選択したフォルダのフルパスをフォルダ選択のダイアログに表示するようにしています。
 SHBrowseForFolder( )は最上位のフォルダを指定することもできます。最上位のフォルダを指定するには、SHGetSpecialFolderLocation( )を使ってPIDL(A pointer to the folder's item identifier list)を取得し、SHBrowseForFolder( )の引数にセットします。サンプルではデスクトップを最上位フォルダに設定しているため、マイコンピュータやネットワーク上の共有フォルダなどアクセス可能なすべてのフォルダを表示して選択することができます。たとえば、マイコンピュータを最上位のフォルダにしてネットワーク上のコンピュータを表示しないようにするには、SHGetSpecialFolderLocation( )の2番目の引数にCSIDL定数の CSIDL_DRIVES を指定します。

サンプル

int CALLBACK BrowseCallbackProc_3( HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData );

BOOL CMyClass::SelectFolder(CString &strPathFolder, CString strTitle)
{
	HWND hWnd = GetSafeHwnd();

	LPMALLOC g_pMalloc; 

	BROWSEINFO bi; 
	LPSTR lpBuffer; 
	LPITEMIDLIST pidlPrograms;  // PIDL for Programs folder 
	LPITEMIDLIST pidlBrowse;    // PIDL selected by user 

	// Get the shell's allocator. 
	if (!SUCCEEDED(SHGetMalloc(&g_pMalloc))) 
		return FALSE;

	// Allocate a buffer to receive browse information. 
	if ((lpBuffer = (LPSTR) g_pMalloc->Alloc( MAX_PATH)) == NULL) 
		return FALSE;
 
	// Get the PIDL for the Programs folder. 
	if (!SUCCEEDED(SHGetSpecialFolderLocation( 
			hWnd, CSIDL_DESKTOP, &pidlPrograms))) { 
		g_pMalloc->Free(lpBuffer); 
		return FALSE;
	} 
 
	// Fill in the BROWSEINFO structure. 
	bi.hwndOwner = hWnd; 
	bi.pidlRoot = pidlPrograms; 
	bi.pszDisplayName = lpBuffer; 
	bi.lpszTitle = (LPCTSTR)strTitle; 
	bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT; 
	bi.lpfn = BrowseCallbackProc_3; 
	bi.lParam = 0; 
 
	// Browse for a folder and return its PIDL. 
	BOOL bRT = TRUE;
	pidlBrowse = SHBrowseForFolder(&bi); 
	if (pidlBrowse == NULL)
		bRT = FALSE;		// キャンセル
	else { 
 
		// Show the display name, title, and file system path. 
		if (!SHGetPathFromIDList( pidlBrowse, lpBuffer )) 
			return FALSE;
		strPathFolder = lpBuffer;
		
		// Free the PIDL returned by SHBrowseForFolder. 
		g_pMalloc->Free( pidlBrowse); 
	} 
 
	// Clean up. 
	g_pMalloc->Free( pidlPrograms); 
	g_pMalloc->Free( lpBuffer); 
	return bRT;
}

// フォルダ選択ダイアログのコールバック関数
int CALLBACK BrowseCallbackProc_3(HWND hwnd,UINT uMsg,LPARAM lp, LPARAM pData)
{
	TCHAR szDir[MAX_PATH];
	
	switch(uMsg) {
	case BFFM_INITIALIZED:	// カレントディレクトリを初期値にする
	{
		if (GetCurrentDirectory(sizeof(szDir)/sizeof(TCHAR),
							  szDir)) {
			// WParam is TRUE since you are passing a path.
			// It would be FALSE if you were passing a pidl.
			SendMessage(hwnd,BFFM_SETSELECTION,TRUE,(LPARAM)szDir);
		}
		break;
	}
	case BFFM_SELCHANGED:	// 選択されたパスを表示する
	{
		// Set the status window to the currently selected path.
		if (SHGetPathFromIDList((LPITEMIDLIST) lp ,szDir)) {
			SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)szDir);
		}
		break;
	}
	default:
		break;
	}
	return 0;
}