## Browsing and Exploring a Folder

#### skill level: intermediate

### © 2003, Alyce Watson

#### Alyce's Restaurant

Browse For Folder --- Explore a Folder --- Sample Program

This article contains two methods. The first shows a "Browse For Folder" dialog. The second method shows how to let the users of your program activate Windows Explorer to investigate the contents of a folder. The two methods are combined in the sample program at the end, but they can be used independently. In fact, it is most likely that you will use them separately!

Browse For Folder Dialog

A Liberty BASIC FILEDIALOG allows the user to select a filename. Sometimes you want to give your users the chance to select a folder. You can do this with the SHBrowseForFolder API call.

The Browse For Folder Dialog looks like this:

This isn't a simple API call, but it isn't difficult to use if you follow the code given here. It is taken apart and explained in the body of the article, and the entire program is included at the bottom.

You must first build a struct to contain information sent to the function.

    STRUCT BrowseInfo,_
        hWndOwner As Long,_
        pIDLRoot As Long,_
        pszDisplayName As Long,_
        lpszTitle$ As ptr,_
        ulFlags As Long,_
        lpfnCallback As Long,_
        lParam As Long,_
        iImage As Long

There is a struct member provided for the text that will display at the top of the Browse Dialog. Here it is set to contain two lines of text:

        crlf$=chr$(13)+chr$(10)

        'set up text to display on the dialog:
        txt1$="This is a Liberty BASIC 3+ capability!" + crlf$
        txt1$=txt1$+"Please choose a folder!"

        'fill the struct item with the text
        BrowseInfo.lpszTitle$.struct = txt1$

You also need to set a flag to tell the function to return directories:

     BIF.RETURNONLYFSDIRS = 1

       'Return only if the user selected a directory
        BrowseInfo.ulFlags.struct = BIF.RETURNONLYFSDIRS

Make the API call to Shell32 DLL like this:

        'Show the 'Browse for folder' dialog
        calldll #shell32, "SHBrowseForFolder",_
            BrowseInfo as struct,_
            lpIDList as long

If the function is successful, the return is a pointer to an ID List. You can retrieve the complete path and name of the folder chosen by setting up a string buffer to hold the name. The buffer must be terminated by chr$(0), to tell Liberty BASIC to pass the address of the buffer so that it can be modified by the API function. Without the null termination, Liberty BASIC passes a copy of the string, which cannot be modified by the function. You then call the SHGetPathFromIDList function, which requires the pointer to the ID List that was returned by the SHBrowseForFolder function. When this function completes its task, the path/foldername chosen by the user is contained in the buffer you set up. It sounds complicated, but it is easy to do using the following code.

        MAX.PATH = 260
        'return > 0 = success, so continue
        If lpIDList>0 Then
            'set up a string buffer:
            sPath$ = space$(MAX.PATH) + chr$(0)
            'Get the path from the IDList
            calldll #shell32, "SHGetPathFromIDList",_
                lpIDList as long,_
                sPath$ as ptr,_
                r as long
         End If
            'the folder name is now in sPath$

You now must free the memory taken by the ID List. This is done with a simple API call that requires the ID of the list.

            open "ole32" for dll as #ole
            'free the block of memory
            calldll #ole, "CoTaskMemFree",_
                lpIDList as long,_
                r as long
            close #ole

The path/foldername chosen by the user is now in sPath$. The name will be terminated by a null character - chr$(0) - so you can check for the placement of a null character in the string to discover the actual length of the path/folder and truncate the string accordingly.

            'check for null char, which
            'signals end of folder name string
            iNull = InStr(sPath$, chr$(0))

            'truncate string at null character
            If iNull Then
                sPath$ = Left$(sPath$, iNull - 1)
            End If

Browse For Folder --- Explore a Folder --- Sample Program

Exploring a Folder

There have been articles in previous newsletters about the ShellExecute API function. Issue #63 dealt with using ShellExecute to open files of various types. Issue #74 discussed printing a text file with ShellExecute. Issue #103 discussed printing graphics with ShellExecute.

It is also possible to use the ShellExecuteA function to explore a specified folder on disk. To do it, the "operation" parameter is "explore" and the "filename" parameter is a null, or empty string. The "directory" parameter is the folder to explore with Windows Explorer. If the "directory" parameter is a null string, it is likely that the program's DefaultDir$ will be called up in Windows Explorer. The "window handle" parameter can be the handle of a program window, or it can be 0. The "showflag" parameter is set to "_SW_SHOWNA", which shows the Windows Explorer window at its normal size (not minimized, maximized or hidden). The following small demo causes Windows Explorer to open in the program's DefaultDir$.

        hWnd = 0                   'window handle, can be 0
        lpszOp$ =  "explore"       'operation to perform
        lpszFile$ = ""             'filename, null here
        lpszParams$=""             'extra info
        lpszDir$ = DefaultDir$     'directory
        showflag = _SW_SHOWNA      'show normal

        CallDLL #shell32, "ShellExecuteA",_
        hWnd As long,_
        lpszOp$ As ptr,_
        lpszFile$ As ptr,_
        lpszParams$ As ptr,_
        lpszDir$ As ptr,_
        showflag As long,_
        result As long

        end

The sample demo combines the two methods discussed in this article. It allows a user to select a folder with the SHBrowseForFolder function and it then calls Windows Explorer with the ShellExecuteA API call to explore the folder. Either method can be used separately as detailed above.

Browse For Folder --- Explore a Folder --- Sample Program

Sample Program

    'set up constants for api calls
    BIF.RETURNONLYFSDIRS = 1
    MAX.PATH = 260
    crlf$=chr$(13)+chr$(10)

    'create struct for api call
    STRUCT BrowseInfo,_
        hWndOwner As Long,_
        pIDLRoot As Long,_
        pszDisplayName As Long,_
        lpszTitle$ As ptr,_
        ulFlags As Long,_
        lpfnCallback As Long,_
        lParam As Long,_
        iImage As Long

        'Set the owner window, optional
        BrowseInfo.hWndOwner.struct = 0

        'set up text to display on the dialog:
        txt1$="This is a Liberty BASIC 3+ capability!" + crlf$
        txt1$=txt1$+"Please choose a folder!"

        'fill the struct item with the text
        BrowseInfo.lpszTitle$.struct = txt1$

        'Return only if the user selected a directory
        BrowseInfo.ulFlags.struct = BIF.RETURNONLYFSDIRS

        'Show the 'Browse for folder' dialog
        calldll #shell32, "SHBrowseForFolder",_
            BrowseInfo as struct,_
            lpIDList as long

        'return > 0 = success, so continue
        If lpIDList>0 Then
    		'set up a string buffer:
           sPath$ = space$(MAX.PATH) + chr$(0)
            'Get the path from the IDList
            calldll #shell32, "SHGetPathFromIDList",_
                lpIDList as long,_
                sPath$ as ptr,_
                r as long

            'the folder name is now in sPath$

            open "ole32" for dll as #ole
            'free the block of memory
            calldll #ole, "CoTaskMemFree",_
                lpIDList as long,_
                r as long
            close #ole

            'check for null char, which
            'signals end of folder name string
            iNull = InStr(sPath$, chr$(0))

            'truncate string at null character
            If iNull Then
                sPath$ = Left$(sPath$, iNull - 1)
            End If
        End If

        'if user cancelled, sPath$ is empty
        if sPath$="" then sPath$="Cancelled"

        print "Folder chosen is "
        print sPath$

        if sPath$="Cancelled" then end

    'now cause Explorer to open in that folder
    call ShellExecute 0, sPath$,_SW_SHOWNA, "explore"

    end

    Sub ShellExecute hWnd, file$, parameter, lpszOp$
        ' _SW_SHOWNA      show normal
        ' _SW_HIDE        hide window
        ' _SW_MINIMIZE    minimize window
        ' lpszOp$ =  "open" or "print" or "explore"
        lpszFile$ = file$
        lpszDir$ = DefaultDir$
        lpszParams$=""
        CallDLL #shell32, "ShellExecuteA", hWnd As long,_
        lpszOp$ As ptr,lpszFile$ As ptr,_
        lpszParams$ As ptr,lpszDir$ As ptr,_
        parameter As long, result As long
        End Sub