フォルダ指定ダイアログを表示する

※フォルダ選択が行われない不具合が発生していたため、サンプル&解説をを修正しました。(2004/2/26)

コモンダイアログのフォルダ指定ダイアログを表示するテクニックです。
また、表示時に指定したフォルダを選択している状態にもしています。

※VB6から追加されたAddressOfを指定しているので下記サンプルは旧VBでは動作しません。
旧VBでの動作については「
旧VBでの使用について」をご覧ください。

サンプル(32bit) ダウンロード

' フォルダ指定ダイアログを表示するAPI
Public Declare Function SHBrowseForFolder Lib "shell32.dll" (lpBrowseInfo As BROWSEINFO) As Long
' アイテム識別子のリストをシステムパスへ変換するAPI
Public Declare Function SHGetPathFromIDList Lib "shell32.dll" (ByVal pidl As Long, ByVal pszPath As String) As Long
' メッセージの送信API
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Type BROWSEINFO
    hwndOwner      As Long
    pidlRoot       As Long
    pszDisplayName As String
    lpszTitle      As String
    ulFlags        As Long
    lpfn           As Long
    lParam         As String
    iImage         As Long
End Type

Public Const MAX_PATH               As Long = 260

Public Const BIF_RETURNONLYFSDIRS   As Long = &H1
Public Const BIF_DONTGOBELOWDOMAIN  As Long = &H2
Public Const BIF_STATUSTEXT         As Long = &H4
Public Const BIF_RETURNFSANCESTORS  As Long = &H8
Public Const BIF_EDITBOX            As Long = &H10
Public Const BIF_VALIDATE           As Long = &H20
Public Const BIF_BROWSEFORCOMPUTER  As Long = &H1000
Public Const BIF_BROWSEFORPRINTER   As Long = &H2000
Public Const BIF_BROWSEINCLUDEFILES As Long = &H4000

Public Const WM_USER = &H400
Public Const BFFM_INITIALIZED = 1
Public Const BFFM_SETSELECTIONA = (WM_USER + 102)

Public Function GetPointer(lngAddressOf As Long) As Long
    
    'コールバック関数のアドレスを返す
    GetPointer = lngAddressOf
    
End Function

Public Function BFFCallback(ByVal hwnd As Long, ByVal uMsg As Long, ByVal lParam As Long, ByVal lpData As Long) As Long
    
    'フォルダを指定のメッセージをダイアログへ送信
    If uMsg = BFFM_INITIALIZED Then
        Call SendMessage(hwnd, BFFM_SETSELECTIONA, True, ByVal lpData)
    End If
    
End Function

'==================================================================================================
'  概要   : フォルダ選択ダイアログの表示
'  引数   : hwnd : 呼び出すフォームのハンドル
'       : strTitle : フォルダ選択ダイアログのウィンドタイトル
'       : strPath : 初期選択フォルダ名
'  戻値   : [OK]クリック時:指定されたフォルダ名 [キャンセル]クリック時:strPathと同じ内容
'==================================================================================================
Public Function ShowFolders(hwnd As Long, strTitle As String, strPath As String) As String
    
    'BROWSEINFO構造体
    Dim udtBrows  As BROWSEINFO
    Dim nRC As Long
    Dim DataPath As String
    
    'とりあえず指定されたフォルダを戻り値にセット
    ShowFolders = strPath
    
    'BROWSEINFO構造体設定
    With udtBrows
        .hwndOwner = hwnd
        .pidlRoot = 0
        .pszDisplayName = String(MAX_PATH, vbNullChar)
        .lpszTitle = strTitle
        .ulFlags = BIF_RETURNONLYFSDIRS
        .lpfn = GetPointer(AddressOf BFFCallback)
        .lParam = strPath & vbNullChar
        .iImage = 0
    End With
    
    'フォルダ選択ダイアログ表示
    nRC = SHBrowseForFolder(udtBrows)
    
    'キャンセルされた場合は終了
    If nRC = 0 Then
        Exit Function
    End If
    
    'システムパスへ変換
    DataPath = String(MAX_PATH, vbNullChar)
    Call SHGetPathFromIDList(nRC, DataPath)
    
    'NUll除去
    DataPath = Left(DataPath, InStr(DataPath, vbNullChar) - 1)
    
    'フォルダ名を戻り値にセット
    ShowFolders = DataPath

End Function

サンプル解説

ShowFoldersプロシージャでフォルダ指定ダイアログを表示しています。

フォルダ指定ダイアログはSHBrowseForFolder関数にBROWSEINFO構造体を渡して表示します。

BROWSEINFO構造体の内容は次の通りです。

メンバー I/O 説明
hwndOwner In 表示するウィンドウのハンドル
pidlRoot In アイテム識別子リストのルートフォルダIDのポインタを指定します。指定するとそのフォルダ以下が表示されます。
サンプルでは0を指定してデスクトップを指定しています。
pszDisplayName I/O ユーザが選択したフォルダ名を受け取るバッファ(ココに入ってくるのはフルパスではありません)
lpszTitle In フォルダ指定ダイアログのタイトル
ulFlags In 動作フラグ。
サンプルではBIF_RETURNONLYFSDIRSを指定してファイルシステムのディレクトリのみを返すように指定しています。
lpfn In フォルダ指定ダイアログでイベントが起きたときに実行するコールバック関数のポインタを指定します。
lParam In lpfnへのパラメータ。サンプルでは選択するフォルダを指定しています。
iImage In ユーザが選択したフォルダに関連するイメージを受け取る変数のポインタを指定します。
サンプルでは必要がないので0を指定しています。

ここでミソになるのが、lpfnとlParamです。
この2つはフォルダ指定ダイアログ表示時に指定されたフォルダを選択状態にする「初期選択フォルダ指定機能」を実現するためのものです。

lpfnにはフォルダ指定ダイアログでイベントが起きたときに実行するコールバック関数のポインタを指定していますが、実際にコールバック関数として動くのはBFFCallback関数です。
この、BFFCallback関数を示すポインタをlpfnにセットする訳ですが・・・関数のポインタ(アドレス)なんて分かるわけがありません。
そこで、VB6で追加されたAddressOfを使用してBFFCallback関数を示すポインタを取得します。
しかしAddressOfは引数リスト内しか使えないのでダミーの関数GetPointerを中継してセットしています。
(AddressOfを使用しているため各関数はパブリックとなります)

そしてlParamにはBFFCallback関数に渡すパラメータをセットします。
パラメータには選択状態にしたいフォルダ名(フルパス)をセットしているんですが、Nullでタミネートしないと空白を含むフォルダ名の場合、正常に動作しません。
そのため、サンプルでは、末尾にNullを追加しています。

ちなみにコールバック関数のBFFCallback関数の内容ですがフォルダ指定ダイアログの初期化が完了したらパラメータにセットされているフォルダ名をを選択するようにフォルダ指定ダイアログにメッセージを送っています。

SHBrowseForFolder関数の戻り値ですが、ユーザが[キャンセル]ボタンをクリックした場合はゼロが返ってきます。
逆にユーザがフォルダを選択した場合はアイテム識別子のリストのポインタが返ってきます。
このままでは選択されたフォルダ名が分かりませんので、SHGetPathFromIDList関数でアイテム識別子のリストから選択したフォルダ(フルパス)を取得しています。

取得したフォルダ名の末尾にはNullがセットされているのでLeft関数で除去しています。

 

旧VBでの使用について

AddressOfはVB6で追加された演算子のため旧バージョンのVBでは実行できません。

しかし、初期選択フォルダ指定の機能さえ削れば旧VBでも使用できます。

具体的にはBROWSEINFO構造体の「lpfn」にゼロ、「lParam」に長さゼロの文字列を指定すればOKです。
同時にGetPointer関数・BFFCallback関数は使用しなくなるのでコーディングする必要はありません。


[ Window Close ]