Directory Browse 
Author Message
 Directory Browse

The following is copied from the Win32.hlp file and I don't understand
how to get the 'free the returned item identifier' (see notice below).

I've got the code working as far as display, selection and return are
concerned but with the absence of the freeing portion I may be creating a
memory leak that I'd rather avoid. <grin>

Any suggestions?

--
C'ya,

  Don Schullian
www.DASoftVSS.com
www.basicguru.com

Displays a dialog box that enables the user to select a shell folder.

WINSHELLAPI LPITEMIDLIST WINAPI SHBrowseForFolder(

    LPBROWSEINFO lpbi  
   );  
Parameters

lpbi

Pointer to a BROWSEINFO structure that contains information used to display
the dialog box.

Return Values

Returns a pointer to an item identifier list that specifies the location of
the selected folder relative to the root of the name space. If the user
chooses the Cancel button in the dialog box, the return value is NULL.

********************************************************************
The calling application is responsible for freeing the returned item
identifier list using the shells task allocator.
********************************************************************

See Also

BROWSEINFO



Fri, 14 Nov 2003 21:43:04 GMT  
 Directory Browse

Quote:
> ********************************************************************
> The calling application is responsible for freeing the returned item
> identifier list using the shell's task allocator.
> ********************************************************************

Don, there's an excellent example of this from POFFs which I have adapted,
added the callback to change the dialog and put into the little demo program
below. (and like you can't tell I used this program to test what all the
"%BIFF_xxxx" flags do). (This is DDT style using PB/DLL 6.0)

The "free the returned item" is the call to  CoTaskMemFree  you will find in
the GetFolder procedure

MCM

'---------------------------------------------------------------------------
----
'
'   BRfolder.bas PB/DLL
'   MCM's DDT (non-SDK) Skeleton Program
''  code courstsy: Borje Hagsten
'---------------------------------------------------------------------------
----

#COMPILE EXE
#DEBUG ERROR ON
#REGISTER NONE
' some variables may not be register variables, so we will make this the
default.
' can be overidden procedure-by-procedure

#INCLUDE "WIN32API.INC"
' #RESOURCE "HELLOWIN.PBR"
'--------------------------------------------
' Declares for the "Browse for Folder" dialog
'--------------------------------------------
%BIF_RETURNONLYFSDIRS  = &H0001
%BIF_DONTGOBELOWDOMAIN = &H0002
%BIF_STATUSTEXT        = &H0004
%BIF_RETURNFSANCESTORS = &H0008
%BIF_BROWSEFORCOMPUTER = &H1000
%BIF_BROWSEFORPRINTER  = &H2000
%BIF_BROWSEINCLUDEFILES = &H4000  ' browses for files as well as folders
%BIF_EDITBOX            = &H0010  ' provides user edit box to enter a
folder/file
%BIF_VALIDATE           = &H0020  ' only valid with %BIF_EDITBOX
                                  ' sends BFFM_VALIDATEFAILED to callback if
edit box entry is invalid/

%BFFM_INITIALIZED      = 1&
%BFFM_SETSELECTIONA    = %WM_USER + 102&
%BFFM_SELCHANGED       = 2&
%BFFM_VALIDATEFAILEDA  =   3&   '// lParam:szPath ret:1(cont),0(EndDialog)
%BFFM_VALIDATEFAILEDW  =   4&   '// lParam:wzPath ret:1(cont),0(EndDialog)
%BFFM_SETSTATUSTEXTA   = %WM_USER + 100&

'DECLARE FUNCTION APIBeep LIB "Kernel32.DLL" ALIAS "XBeep" (BYVAL dwFreq AS
DWORD, BYVAL dwDurationms AS DWORD) AS LONG
' already in Win32APIINC API 32.inc as "WinBeep"
#IF 0
      CONSTANTS FOR CALLBACK TO Browse FOR Folder
      ON BFFM_INTITIALIZED, SEND message BFFM_SETSECTIONA (WITH ASCII) TO
the window

      INT CALLBACK
      BrowseCallbackProc(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;
      }

// message FROM browser
#define BFFM_INITIALIZED        1
#define BFFM_SELCHANGED         2
#define BFFM_VALIDATEFAILEDA    3   // lParam:szPath
ret:1(cont),0(EndDialog)
#define BFFM_VALIDATEFAILEDW    4   // lParam:wzPath
ret:1(cont),0(EndDialog)

// messages TO browser
#define BFFM_SETSTATUSTEXTA     (WM_USER + 100)
#define BFFM_ENABLEOK           (WM_USER + 101)
#define BFFM_SETSELECTIONA      (WM_USER + 102)
#define BFFM_SETSELECTIONW      (WM_USER + 103)
#define BFFM_SETSTATUSTEXTW     (WM_USER + 104)

#ENDIF

DECLARE FUNCTION GetFolder(BYVAL hWndModal AS LONG, szTitle AS ASCIIZ * 60)
AS STRING
DECLARE SUB CoTaskMemFree LIB "ole32.dll" ALIAS "CoTaskMemFree" (BYVAL hMem
AS LONG)

DECLARE FUNCTION PathCompactPathEx LIB "SHLWAPI.DLL" ALIAS
"PathCompactPathExA" (szOut AS ASCIIZ, szIN AS ASCIIZ, BYVAL sizeout AS
LONG, BYVAL Flags AS DWORD) AS LONG
' constants for this program
$AppTitle = "Browse For Folder"
' control IDs
%ID_TEXTBOX  = 101&
%ID_BUTTON   = 102&
%ID_LABEL    = 103&

' GLOBALS
 GLOBAL ghDlg AS LONG

'---------------------------------------------------------------------------
---

'DECLARE  FUNCTION GetFolder(BYVAL hWndModal AS LONG) AS STRING

CALLBACK FUNCTION FolderBrowseProc () AS LONG

   LOCAL Stat AS LONG, Folder AS ASCIIZ * %MAX_PATH, TextLine AS ASCIIZ *
200
   LOCAL CompactPath AS ASCIIZ * 33, szTitle AS ASCIIZ * 60

   szTitle = "Select Output Folder"  ' this ffoes below Caption, above
folder window!
                                     ' STATUS area just above edit box/view
area, below this

   'MSGBOX "Entered Callback CBCTL=" & STR$(CBCTL) & "CBCTLMSG=" &
STR$(CBCTLMSG) & " CBMSG=" & STR$(CBMSG)

   IF CBMSG = %WM_COMMAND AND CBCTL = %ID_BUTTON AND CBCTLMSG=%BN_CLICKED
THEN
      Folder  = GetFolder (ghDlg, szTitle)
      IF LEN (Folder) THEN
         TextLine = Folder
      ELSE
         TextLine = "No Folder Returned"
      END IF
      IF LEN(TextLine) > SIZEOF(CompactPath) THEN
          PathCompactPathEx CompactPath, TextLine, SIZEOF(CompactPath) -1,
%NULL
          TextLine = CompactPath
      END IF
          ' DECLARE FUNCTION PathCompactPathEx LIB "SHLWAPI.DLL" ALIAS
"PathCompactExA" (szOut AS ASCIIZ, szIN AS ASCIIZ, BYVAL sizeout AS LONG,
BYVAL Flags AS DWORD) AS LONG
      CONTROL SET TEXT gHDlg, %ID_LABEL, TextLine
      DIALOG DOEVENTS
   ELSEIF CBMSG = %WM_COMMAND AND CBCTL = %IDCANCEL AND CBCTLMSG=%BN_CLICKED
THEN
      DIALOG END ghDlg
   END IF

END FUNCTION
FUNCTION GetFolder(BYVAL hWndModal AS LONG, szTitle AS ASCIIZ * 60) AS
STRING
      LOCAL bInf AS BROWSEINFO
      LOCAL RetPath AS STRING
      LOCAL RetVal  AS LONG, PathID  AS LONG

      'Set some properties of the folder dialog
      bInf.hWndOwner = hWndModal
      bInf.ulFlags = %BIF_RETURNONLYFSDIRS OR %BIF_DONTGOBELOWDOMAIN OR
%BIF_BROWSEINCLUDEFILES OR %BIF_STATUSTEXT OR %BIF_EDITBOX OR %BIF_VALIDATE

      bInf.lpfnCallback=CODEPTR (BrowseForFolderCallBack)
      bInf.lpszTitle = VARPTR (szTitle)

      'Show the Browse-For-Folder dialog
      PathID = SHBrowseForFolder(bInf)

      IF PathID THEN
         RetPath = SPACE$(%MAX_PATH)
         RetVal = SHGetPathFromIDList(BYVAL PathID, BYVAL STRPTR(RetPath))
      END IF

      IF RetVal THEN
           FUNCTION = RTRIM$(RetPath, CHR$(0))
           'Free allocated memory
           CoTaskMemFree PathID
      ELSE
           FUNCTION = ""
      END IF

END FUNCTION

FUNCTION WINMAIN (BYVAL hInstance     AS LONG, _
                  BYVAL hPrevInstance AS LONG, _
                  lpCmdLine           AS ASCIIZ PTR, _
                  BYVAL iCmdShow      AS LONG) AS LONG

    LOCAL  hDlg AS LONG

    ' Create our primary GUI
    DIALOG NEW 0, $AppTitle, 77, 22, 400, 267, _
        %DS_CENTER OR %WS_CAPTION OR %WS_SYSMENU, 0 TO hDlg

    ' Abort if the dialog could not be created
    IF hDlg = 0 THEN EXIT FUNCTION  ' Error occurred

    ' Save the handle for global access
    ghDlg = hDlg

    ' Now we create our controls.  We create the static control immediately
before the
    ' real control so that the keyboard accelerators switch focus to the
real control

    ' a button to do the search
    CONTROL ADD BUTTON,   hDlg, %id_button, "&Browse",  10, 10,  40,  14,
CALL FolderBrowseProc
    ' a label to show the result in

    CONTROL ADD LABEL,    hDlg, %ID_LABEL, "", 10, 30,  300,  14, %SS_LEFT

    CONTROL ADD BUTTON,    hDlg, %IDCANCEL, "Quit",350,220,40,14, CALL
FolderBrowseProc

    ' Start up our GUI, and run until the user quits
    DIALOG SHOW MODAL hDlg

    ' The return value of success!
    FUNCTION = 0

END FUNCTION

FUNCTION BrowseForFolderCallBack (BYVAL hwnd AS LONG,BYVAL uMsg AS
DWORD,BYVAL LPARAM AS LONG, BYVAL pdata AS LONG) EXPORT AS LONG
 LOCAL PathtoPass AS ASCIIZ * %MAX_PATH
 LOCAL CurrentPath AS ASCIIZ * %MAX_PATH
 STATIC Counter AS LONG, StatusMEssage AS ASCIIZ * 60
 LOCAL zP AS ASCIIZ PTR

     PathToPass = "C:\My Documents\Work"
     SELECT CASE uMSG
            CASE %BFFM_INITIALIZED
                 SendMessage hWnd, %BFFM_SETSELECTIONA, %TRUE, BYVAL
VARPTR(PathToPass)
            CASE %BFFM_SELCHANGED
                 INCR Counter
                 StatusMessage = "STATUS:Trip#" & STR$(Counter)
                 SendMessage hWnd, %BFFM_SETSTATUSTEXTA, %FALSE, BYVAL
VARPTR(StatusMessage)
                 ' can't see a difference between wparam = true or false
            CASE %BFFM_VALIDATEFAILEDA    '// lParam:szPath
ret:1(cont),0(EndDialog)
                 zP = lParam

                 WINBEEP 440, 1000
                 SendMessage hWnd, %BFFM_SETSTATUSTEXTA, %TRUE, BYVAL
VARPTR(StatusMessage)

                 FUNCTION = 1: EXIT FUNCTION
     END SELECT

END FUNCTION

 === ENDS ===



Sat, 15 Nov 2003 00:09:06 GMT  
 Directory Browse


Quote:
>> ********************************************************************
>> The calling application is responsible for freeing the returned item
>> identifier list using the shell's task allocator.
>> ********************************************************************

>Don, there's an excellent example of this from POFFs which I have adapted,
>added the callback to change the dialog and put into the little demo program
>below. (and like you can't tell I used this program to test what all the
>"%BIFF_xxxx" flags do). (This is DDT style using PB/DLL 6.0)

>The "free the returned item" is the call to  CoTaskMemFree  you will find in
>the GetFolder procedure

Thanks Michael but, <<if>> I'm reading the 'help' files correctly
CoTaskMemFree isn't what we're looking for! It may, in fact, work but there is
no mention of the "item identifer list" in this SUB's write-up.

Here's the code I had come up with.

--
C'ya,

  Don Schullian
www.DASoftVSS.com
www.basicguru.com

DECLARE FUNCTION fDirectoryBrowse (BYVAL Title AS STRING) AS STRING

#IF 1

#INCLUDE "WIN32API.INC"

FUNCTION PBMAIN ()

  MSGBOX ">>" & fDirectoryBrowse("Just Testing") & "<<"

END FUNCTION

#ENDIF

FUNCTION fDirectoryBrowse ( BYVAL Title AS STRING ) AS STRING

  DIM tB       AS LOCAL BrowseInfo
  DIM lpIDList AS LOCAL LONG
  DIM Buffer   AS LOCAL ASCIIZ * %MAX_PATH

  IF LEN(Title) = 0 THEN Title = "Select Directory"

  tB.lpszTitle = STRPTR(Title)
  tB.hWndOwner = 0
  tB.ulFlags   = %BIF_ReturnOnlyFSdirs + %BIF_DontGoBelowDomain
  lpIDList     = SHBrowseForFolder(tB)

  IF lpIDList <> 0 THEN
    IF SHGetPathFromIDList(BYVAL lpIDList, Buffer) <> 0 THEN
      IF RIGHT$(Buffer,1) <> "\" THEN Buffer = Buffer & "\"
    END IF
  END IF

' Free up item identifier list here

  FUNCTION = Buffer

END FUNCTION    



Sat, 15 Nov 2003 21:46:07 GMT  
 Directory Browse
Here some VB code from the MSDN CD which shows on what the PB function was
based.

The SHBrowseForFolder function does the allocation; the using program must
clean up. If you dig through the MSDN doc, you'll find CoTaskMemFree invokes
IMalloc:Free, which is what all the "C++" documentation says to call to free
the resources allocated by the Shell function.

MCM

' --------------------------------------------------
 ' // Browse for folders and returns the full
 ' // path name as a string.
 ' --------------------------------------------------
 Function BrowseForFolderEx( ByVal hWnd As Long, _
   ByVal title As String, ByVal options As Long, _
   Optional root As Variant ) As String

     Dim bi As BROWSEINFO
     Dim lpIdList As Long
     Dim sFolderName As String

     ' initializes the BROWSEINFO structure
     bi.hwndOwner = hWnd
     bi.lpszTitle = title
     bi.ulFlags = options

     ' defaults the missing argument to the DESKTOP
     If IsMissing( root ) Then
         bi.pidlRoot = 0
     Else
         bi.pidlRoot = root
     End If

     ' calls the API function
     lpIdList = SHBrowseForFolder( bi )

     ' converts the PIDL to a path name
     If lpIdList Then
        sFolderName = String(MAX_PATH, 0)
        SHGetPathFromIDList lpIdList, sFolderName
        BrowseForFolderEx = sFolderName
        CoTaskMemFree lpIdList
     End If
 End Function


Quote:
> On Mon, 28 May 2001 16:09:06 GMT, "Michael Mattias"


Quote:

> >> ********************************************************************
> >> The calling application is responsible for freeing the returned item
> >> identifier list using the shell's task allocator.
> >> ********************************************************************

> >The "free the returned item" is the call to  CoTaskMemFree  you will find
in
> >the GetFolder procedure

> Thanks Michael but, <<if>> I'm reading the 'help' files correctly
> CoTaskMemFree isn't what we're looking for! It may, in fact, work but
there is
> no mention of the "item identifer list" in this SUB's write-up.



Sun, 16 Nov 2003 02:37:48 GMT  
 Directory Browse


Quote:
>Here some VB code from the MSDN CD which shows on what the PB function was
>based.

>The SHBrowseForFolder function does the allocation; the using program must
>clean up. If you dig through the MSDN doc, you'll find CoTaskMemFree invokes
>IMalloc:Free, which is what all the "C++" documentation says to call to free
>the resources allocated by the Shell function.

Far be it from me to EVER doubt M$oft's word!! <grin>

Thanks....

--
C'ya,

  Don Schullian
www.DASoftVSS.com
www.basicguru.com



Sun, 16 Nov 2003 22:15:28 GMT  
 Directory Browse


<snip>

Quote:
>Don, there's an excellent example of this from POFFs which I have
>adapted, added the callback to change the dialog and put into the little
>demo program below. (and like you can't tell I used this program to test
>what all the "%BIFF_xxxx" flags do). (This is DDT style using PB/DLL
>6.0)

<snip>

Quote:
>MCM

<code snipped>

Quote:
>FUNCTION GetFolder(BYVAL hWndModal AS LONG, szTitle AS ASCIIZ * 60) AS
>STRING
>      LOCAL bInf AS BROWSEINFO

I get an undefined type error on BROWSEINFO.  I copied your code exactly.
 What am I missing here?

--
ATB

Charles Kincaid



Sun, 16 Nov 2003 23:13:24 GMT  
 Directory Browse

Quote:

> >The SHBrowseForFolder function does the allocation; the using program
must
> >clean up. If you dig through the MSDN doc, you'll find CoTaskMemFree
invokes
> >IMalloc:Free, which is what all the "C++" documentation says to call to
free
> >the resources allocated by the Shell function.

> Far be it from me to EVER doubt M$oft's word!! <grin>

> Thanks....

This is the function I have been using for a couple of months and have had
no problems with it. I freely admit I appropriated it from Borje Hagsten's
code in POFFS. (Hell, that's why he posted it, right?)

MCM



Mon, 17 Nov 2003 02:14:40 GMT  
 Directory Browse
did you #INCLUDE "win32api.inc" ?

And if so, is it the correct version?

--
Michael Mattias
Tal Systems
Racine WI USA


Quote:




> <snip>

> >Don, there's an excellent example of this from POFFs which I have
> >adapted, added the callback to change the dialog and put into the little
> >demo program below. (and like you can't tell I used this program to test
> >what all the "%BIFF_xxxx" flags do). (This is DDT style using PB/DLL
> >6.0)

> <snip>
> >MCM

> <code snipped>
> >FUNCTION GetFolder(BYVAL hWndModal AS LONG, szTitle AS ASCIIZ * 60) AS
> >STRING
> >      LOCAL bInf AS BROWSEINFO

> I get an undefined type error on BROWSEINFO.  I copied your code exactly.
>  What am I missing here?

> --
> ATB

> Charles Kincaid



Mon, 17 Nov 2003 02:50:01 GMT  
 Directory Browse


Quote:

><code snipped>
>>FUNCTION GetFolder(BYVAL hWndModal AS LONG, szTitle AS ASCIIZ * 60) AS
>>STRING
>>      LOCAL bInf AS BROWSEINFO

>I get an undefined type error on BROWSEINFO.  I copied your code exactly.
> What am I missing here?

Hmmm... Michael's code worked ok for me. Here's what I was playing around
with. Want to try it?

DECLARE FUNCTION fDirectoryBrowse (BYVAL Title AS STRING) AS STRING
DECLARE SUB CoTaskMemFree LIB "OLE32.DLL" ALIAS "CoTaskMemFree" (BYVAL h&)

#IF 1

#INCLUDE "WIN32API.INC"

FUNCTION PBMAIN ()

  MSGBOX fDirectoryBrowse("Just Testing")

END FUNCTION

#ENDIF

FUNCTION fDirectoryBrowse ( BYVAL Title AS STRING ) AS STRING

  DIM tB       AS LOCAL BrowseInfo
  DIM lpIDList AS LOCAL LONG
  DIM Buffer   AS LOCAL ASCIIZ * %MAX_PATH

  IF LEN(Title) = 0 THEN Title = "Select Path"

  tB.lpszTitle = STRPTR(Title)
  tB.hWndOwner = 0
  tB.ulFlags   = %BIF_ReturnOnlyFSdirs + %BIF_DontGoBelowDomain
  lpIDList     = SHBrowseForFolder(tB)

  IF lpIDList <> 0 THEN
    IF SHGetPathFromIDList(BYVAL lpIDList, Buffer) <> 0 THEN
      IF RIGHT$(Buffer,1) <> "\" THEN Buffer = Buffer & "\"
    END IF
    CoTaskMemFree lpIDList
    FUNCTION = Buffer
  END IF

END FUNCTION

--
C'ya,

  Don Schullian
www.DASoftVSS.com
www.basicguru.com



Mon, 17 Nov 2003 23:30:31 GMT  
 Directory Browse


Quote:
>did you #INCLUDE "win32api.inc" ?

>And if so, is it the correct version?

>--
>Michael Mattias
>Tal Systems
>Racine WI USA



>> [...]

It's the one that came with PB/DLL6.00 dated Jul, 02, 1999.  The include
is in there as it came from the original.

--
ATB

Charles Kincaid



Wed, 19 Nov 2003 01:00:20 GMT  
 Directory Browse
Original = Not current. Get current from PB web site, "files" section.

--
Michael Mattias
Tal Systems
Racine WI USA


Quote:


> >did you #INCLUDE "win32api.inc" ?

> >And if so, is it the correct version?

> >--
> >Michael Mattias
> >Tal Systems
> >Racine WI USA



> >> [...]

> It's the one that came with PB/DLL6.00 dated Jul, 02, 1999.  The include
> is in there as it came from the original.

> --
> ATB

> Charles Kincaid



Wed, 19 Nov 2003 08:36:29 GMT  
 
 [ 11 post ] 

 Relevant Pages 

1. tcl/tk directory browse

2. LISTING DIRECTORIES IN BROWSE

3. Browse for directory widget

4. Browsing directories and files - a tcl script ?

5. Directory of File/Directories on CD

6. copy file from one directory to another directory

7. Creating Directories & Sub-Directories from Clarion

8. dosnames - directory DOSify a directory

9. Copying multiple directories to one directory

10. pathname-directory when pathname is a directory

11. Getting at directories with DIRECTORY

12. Newbie: import works ok if in base directory but fails in other directories

 

 
Powered by phpBB® Forum Software