● ファイルを開くダイアログで複数選択の結果を取得する ●

ファイルを開くダイアログの複数選択ってあんまり使わないんだけどね。

さて、ファイルを複数選択できるようにするには、こちらのGetOpenFilePath 関数を次のように変更すればよい。

    .flags = OFN_PATHMUSTEXIST Or OFN_FILEMUSTEXIST Or _
                OFN_HIDEREADONLY Or OFN_ALLOWMULTISELECT Or _
                OFN_EXPLORER  'フラグを指定する

If ret Then GetOpenFilePath = udtOpenFile.lpstrFile Else GetOpenFilePath = "" End If

ファイルが複数選択された場合、

  ディレクトリのパス Chr$(0) ファイル名 Chr$(0) ファイル名 Chr$(0) ファイル名 …

という形式の文字列として取得する。この文字列のバッファサイズ決まっており、多分260バイトだと思う。だって、MAX_PATH の値って260だもんね。バッファを超えるほどファイルを選択したらエラー。逆に納まれば、最後のファイル名以降は Chr$(0) で埋められる。

ちなみに、エラートラップをしたければ、

    Private Declare Function CommDlgExtendedError Lib "comdlg32.dll" () As Long

というAPIを使えばよい。エラーが発生すると、 CommDlgExtendedError 関数は0以外の値を返す。余裕があれば処理に組み込んでみてね。とりあえず、こんだけ前知識があればOKでしょう。んじゃぁ、下の関数を書いてね。

'---------------------------------------------------------------------------
'  関数名: SplitFileNames
'  機能  : OpenGetFilePathOrName で選択されたファイルパスをふるいわけする
'  引数  : (in) srcPath … OpenGetFilePathOrNameで得た返り値
'           (in/out) trsFilePath() … ふるいわけされたファイルパス(配列)
'  返り値: 取得したファイル数
'---------------------------------------------------------------------------
Public Function SplitFileNames(ByVal srcPath As String, ByRef trsFilePath() As String) As Integer

    Dim i As Integer
    Dim NullNum As Integer ' Nullの数
    Dim Filename As String ' 抽出したファイル名
    Dim DirPath As String  ' ディレクトリのパス
    Dim FilePath As String ' 編集後の文字列
    Dim strTemp As String  ' 作業用、一時バッファ

    On Error GoTo ErrHandler

    'Nullの個数を取得
    For i = 1 To Len(srcPath) - 1
        '現時点のポインタが指す文字が Chr$(0)で
        '次のポインタが指す文字が Chr$(0)でない
        '即ち、Chr$(0)が連続していないなら、カウンタをインクリメント
        If Mid$(srcPath, i, 1) = Chr$(0) And Mid$(srcPath, i + 1, 1) <> Chr$(0) Then
            NullNum = NullNum + 1
        End If
    Next i

    'ファイルを1つしか選択しなかった場合
    'NullNum=0 となるので NullNum=1 と帳尻をあわせてやる
    'これをしないと、下の Redim ステートメントでエラーとなる
    If NullNum = 0 Then NullNum = 1

    'メモリ初期化
    ReDim trsFilePath(NullNum - 1) As String

    'ディレクトリのパスを取得する
    DirPath = strNullCut(srcPath)

    'ファイルを1つしか選択しなかった場合の処理
    If NullNum = 1 Then
        SplitFileNames = 1
        trsFilePath(0) = DirPath
        Exit Function
    End If

    '必要な部分を取得
    strTemp = Right$(srcPath, Len(srcPath) - (Len(DirPath) + 1))

    'ファイル名取得
    Filename = Left$(strTemp, InStr(strTemp, Chr$(0)) - 1)

    'フルパスを取得
    FilePath = DirPath & "\" & Filename

    trsFilePath(0) = FilePath

    '必要な部分を取得
    strTemp = Right$(strTemp, Len(strTemp) - (Len(Filename) + 1))

    For i = 1 To NullNum - 1
        'ファイル名取得
        Filename = strNullCut(strTemp)

        'フルパスを取得
        FilePath = DirPath & "\" & Filename

        '配列に格納
        trsFilePath(i) = FilePath

        '余った文字列取得
        strTemp = Right$(strTemp, Len(strTemp) - (Len(Filename) + 1))
    Next i

    'ファイル数を返す
    SplitFileNames = NullNum

    Exit Function

  ErrHandler:
    Call MsgBox("エラーNo." & Err.Number & vbCrLf & vbCrLf & _
                Err.Description, vbExclamation, "文字列ふるいわけ - エラー")

    SplitFileNames = 0
End Function


'---------------------------------------------------------------
'  関数名: strNullCut
'   機能 : 文字列を Chr$(0)[=vbNullChar] まで取得する
'   引数 : (in) srcStr … 対象文字列
'  返り値 :編集された文字列
'---------------------------------------------------------------

Public Function strNullCut(ByVal srcStr As String) As String

    Dim NullCharPos As Integer

    NullCharPos = InStr(srcStr, Chr$(0))

    If NullCharPos = 0 Then
        strNullCut = srcStr
        Exit Function
    End If

    strNullCut = Left$(srcStr, NullCharPos - 1)

End Function

下のコードで試してね。

Private Sub Command1_Click()

    Dim gFileName As String      'ダイアログより取得したファイル名列挙文字列
    Dim FileNameArray() As String  'ふるいわけされたファイル名
    Dim FileNum As Integer      '取得したファイルの数
    Dim i As Integer              'ループ用作業変数
    Dim strTemp As String      '作業用文字列変数

    gFileName = GetOpenFilePath(Me.hwnd, 0, , , "ファイルを開く(複数選択可能)")

    If gFileName <> "" Then
        'ファイル列挙文字列をふるいわけし、選択したファイルの数を取得
        FileNum = SplitFileNames(gFileName, FileNameArray())

        '取得した数分ループ
        For i = 0 To FileNum - 1
            Debug.Print FileNameArray(i)
        Next i
    End If

End Sub

戻る