〜 ファイル 〜
フォルダ選択ダイアログを表示 (要SHELL32.DLL, OLE32.DLL)

標準命令にフォルダを選択するダイアログは用意されていません。
APISHBrowseForFolderを呼び出すことで簡単に使うことができるのですが、
ダイアログ表示時に選択する初期フォルダを指定するにはコールバック関数が必要となり、
HSPで対応するにはマシン語の埋め込み等が必要なので難易度は一気に上がります。
コールバック関数が必要なダイアログは別の機会にするとして、
ココでは初期フォルダをマイコンピュータに限定した簡易版を利用する例を紹介します。

APISHBrowseForFolderに渡すのは、ダイアログボックスのオプションを示すBROWSEINFO構造体1つだけ。
Type BROWSEINFO {
DWORDhOwner, // ウィンドウハンドル
DWORDpRoot, // ルートフォルダ
LPTSTRpSelPath, // 選択フォルダの受取先
LPCTSTRpTitle, // メッセージテキスト
UINTuFlags, // オプションフラグ
BFFCALLBACKlpFn, // コールバック関数
LPARAMlParam, // コールバック関数へ渡すパラメータ
intimgListNo// 選択フォルダのイメージリストインデクス
};
1つだけといっても、BROWSEINFO構造体自体の指定項目が複数あり、 メンバ1にはオーナーを表すウィンドウハンドル、 メンバ2にはルートフォルダを表すIDリストへのポインタ、 メンバ3にはダイアログボックスで選択されたフォルダを格納する変数のポインタ、 メンバ4にはダイアログボックスに表示するメッセージテキストを格納したアドレス、 メンバ5には動作方法を表す後述の定数組み合わせ、 メンバ6には今回省略することを書いたコールバック関数へのポインタ、 メンバ7にはコールバック関数に渡されるアプリケーション定義値、 メンバ8にはダイアログボックスで選択されたフォルダと関連付けられたイメージリスト内インデクスを それぞれ指定しなければなりません。 ウィンドウハンドルはhwndまたはHSP2だとBMSCR構造体の13番を、 IDリストへのポインタはginfo関数の説明の時に紹介したCSIDLが利用できます。 指定を省略すればCSIDL_DESKTOP=(0x0001)の指定と同じになりますので全フォルダが対象となり、 それ以外を指定すると対象のフォルダ以下のサブフォルダしか選択ができなくなります。 選択フォルダを格納する変数は受取先の変数アドレスをll_getptr命令なりvarptr関数なりで指定しましょう。 ダイアログに表示するテキストは利用者にコメントするテキストのこと。 「以下のフォルダから選択してください」等のヒント的メッセージを書いてあげると良いでしょう。 動作方法は以下から意味のある定数値を組み合わせて指定します。
定数コード内容
BIF_RETURNONLYFSDIRS0x0001フォルダのみ利用可
BIF_DONTGOBELOWDOMAIN0x0002ネットワークで繋がっているコンピュータを利用不可
BIF_STATUSTEXT0x0004ダイアログボックス内のステータス文字列を表示
BIF_RETURNFSANCESTORS0x0008ルートフォルダ配下のフォルダのみ利用可
BIF_EDITBOX0x0010アイテム名を書き込める入力ボックスを配置 (4.71〜)
BIF_VALIDATE0x0020入力ボックスに無効な名前が入力された時にコールバック関数を呼び出す (4.71〜)
BIF_NEWDIALOGSTYLE0x0040リサイズ可能、新しいフォルダ作成ボタン、ヘルプ以外のコンテキストメニュー追加、
D&D対応機能を追加した新しいUIのダイアログボックスを使用 (5.0〜)
BIF_USENEWUI0x0050BIF_EDITBOX+BIF_NEWDIALOGSTYLEのこと。 (5.0〜)
BIF_BROWSEINCLUDEURLS0x0080条件付でURLの表示・選択が可能 (5.0〜)
BIF_UAHINT0x0100入力ボックス配置に代わり、用法ヒントを表示 (6.0〜)
BIF_NONEWFOLDERBUTTON0x0200BIF_NEWDIALOGSTYLE指定時の新しいフォルダ作成ボタンを配置しない (6.0〜)
BIF_NOTRANSLATETARGETS0x0400ショートカットファイル選択時にショートカットファイル自体のPIDLを返す (6.0〜)
BIF_BROWSEFORCOMPUTER0x1000ネットワーク内のコンピュータのみ利用可
BIF_BROWSEFORPRINTER0x2000プリンタのみ利用可
BIF_BROWSEINCLUDEFILES0x4000フォルダとファイルを表示 (4.71〜)
BIF_SHAREABLE0x8000ネットワーク内の共有リソースも利用可 (5.0〜)
コールバック関数とコールバック関数に渡すパラメータを使わない時には0を指定すればOK。 選択されたフォルダに関連付けられたイメージリストのインデクスと言うのは、 プログラマに代わり、イメージのコレクションを配列で管理するリストの要素番号のこと。 使い道がイマイチわかりませんので調べてません。0を指定すればOKです。 以上のBROWSEINFO構造体を指定したAPISHBrowseForFolderが無事に成功すれば、 選択されたフォルダパスを表すアイテムIDリストへのポインタPIDLが受け取れます。 BROWSEINFO構造体のメンバ3に入るのはフォルダのパスではなくフォルダの名前だけであまり使えないので、 APISHBrowseForFolderの戻り値であるアイテムIDリストを使い、 アイテムIDリストからフォルダパスに変換するAPISHGetPathFromIDListを使います。 APISHGetPathFromIDListに指定するのは変換対象のPIDL値、変換後のパスを入れる変数ポインタ。 無駄…というより、わかりにくい項目がないので、コレは説明しなくてもすんなり行くことでしょう。 コレで無事に選択したフォルダのパスを取得できるわけですが、 COMインタフェイス使用後のお約束として、ole32.dllのCoTaskMemFreeも使います。 コレも指定するのは解放対象のPIDL値、APISHBrowseForFolderの戻り値だけなので簡単です。

dirdlg 受取先, タイトル
受取先選択したフォルダパスを格納する変数を指定する。
尚、キャンセルするとstatに0、選択すると1が入る。
タイトルタイトル部に表示するメッセージを指定する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
	ll_libload ole, "ole32.dll"
	ll_getproc CoTaskMemFree, "CoTaskMemFree", ole
	ll_libload shell, "shell32.dll"
	ll_getproc SHBrowseForFolder, "SHBrowseForFolder", shell
	ll_getproc SHGetPathFromIDList, "SHGetPathFromIDList", shell

#module
#deffunc dirdlg val, str
	mref dirpath, 24 : mref ttl, 33 : mref stt, 64
	mref bmscr, 67
	prm = bmscr.13, 0, 0, 0, 0x0001, 0, 0, 0
	ll_getptr dirpath : ll_ret prm.2
	ll_getptr ttl : ll_ret prm.3
	ll_getptr prm : ll_ret prm.7
	ll_callfunc prm.7, 1, SHBrowseForFolder@
	ll_ret h
	if h {
		prm = h, prm.2
		ll_callfunc prm, 2, SHGetPathFromIDList@
		ll_callfunc h, 1, CoTaskMemFree@
	}
	stt = h ! 0
	return
#global

	sdim dir, 260
	dirdlg dir, "フォルダを選択してください"
	if stat {
		dialog dir, , "選択フォルダ"
	} else {
		dialog "フォルダは選択されませんでした"
	}
	end

dirdlg 受取先, タイトル
受取先選択したフォルダパスを格納する変数を指定する。
尚、キャンセルするとstatに0、選択すると1が入る。
タイトルタイトル部に表示するメッセージを指定する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#uselib "ole32.dll"
#func	global CoTaskMemFree "CoTaskMemFree" int
#uselib "shell32.dll"
#cfunc	global SHBrowseForFolder "SHBrowseForFolder" var
#func	global SHGetPathFromIDList "SHGetPathFromIDList" int, var

#module
#deffunc seldir var dirpath, str msg, local h, local ttl, local binfo
	sdim ttl, strlen(msg) + 1
	ttl = msg
	binfo = hwnd, 0, varptr(dirpath), varptr(ttl), 0x0001, 0, 0, 0
	h = SHBrowseForFolder(binfo)
	if h = 0 : return 0
	SHGetPathFromIDList h, dirpath
	CoTaskMemFree h
	return 1
#global

	sdim dir, 260
	seldir dir, "フォルダを選択してください"
	if stat {
		dialog dir, , "選択フォルダ"
	} else {
		dialog "フォルダは選択されませんでした"
	}
	end