Announcement

Collapse
No announcement yet.

SHBROWSEFORFOLDER CODEPTR question

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Mike Trader
    replied
    Wow Semen & Lance,
    I have so much to learn!
    Thx for those pointers. I have streamlined my code as much as possible
    This is about as simple As I can get it I think.
    I use the function return to detect a CANCEL by the user
    and I pass the selected folder back using the Initial path variable.

    I like this cos I can write on line of code to call the function
    and check the result for a cancel:
    IF FolderDialog(0,"Select a folder", Path) THEN

    So here is what I got:

    Code:
    #COMPILE EXE "FindFldr.exe"
    #INCLUDE     "WIN32API.INC" ' Win API definitions
    
    '************************************************************************
    ' Find Folder Declarations
    '************************************************************************
    TYPE browseinfo
         hwndowner AS LONG
         pidlroot AS LONG
         pszdisplayname AS ASCIIZ PTR
         lpsztitle AS ASCIIZ PTR
         ulflags AS LONG
         lpfncallback AS LONG
         lparam AS LONG
         iimage AS LONG
    END TYPE
    
    %BFFM_SETSELECTION = %wm_user+102 ' must be this value (102)
    
    DECLARE SUB CoTaskMemFree LIB "ole32.dll" ALIAS "CoTaskMemFree" (BYVAL hMem AS LONG)
    
    '************************************************************************
    ' Find Folder
    '************************************************************************
    CALLBACK FUNCTION fbrowseproc
        DIM zdir AS ASCIIZ*%max_path
        IF CBMSG = 1 THEN DIALOG SEND CBHNDL, %BFFM_SETSELECTION, %TRUE, CBLPARAM ' %BFFM_INITIALIZED     
        IF CBMSG = 2 THEN CALL SHGETPATHFROMIDLIST(BYVAL CBWPARAM, zDir) ' %BFFM_SELCHANGED
    END FUNCTION    
    
    FUNCTION FolderDialog(hwnd AS LONG, title AS STRING, Dir AS ASCIIZ*%max_path ) AS LONG
        LOCAL zbuffer AS ASCIIZ*%max_path 
        LOCAL lpidlist AS LONG
        LOCAL zstartdir AS ASCIIZ*%max_path 
        LOCAL tbi AS browseinfo
        tbi.hwndowner    = hwnd
        tbi.lpsztitle    = STRPTR(title)
        zstartdir        = Dir
        tbi.ulflags      = &h0001 OR &h0002 OR &h0004
        tbi.pidlroot     = 0
        tbi.lpfncallback = CODEPTR(fbrowseproc) ' Select Starting folder
        tbi.lparam       = VARPTR(zstartdir)
        lpidlist         = SHBROWSEFORFOLDER(tbi)
        IF lpidlist THEN
            CALL SHGETPATHFROMIDLIST (lpidlist&, Dir) ' Return the path
            CALL CoTaskMemFree(lpidlist&)
            FUNCTION = 1 ' User choose a Folder (0 if he hits Cancel)
        END IF
    END FUNCTION
    
    '************************************************************************
    FUNCTION PBMAIN()AS LONG
    LOCAL Path AS ASCIIZ*%max_path 
    
        Path   = "C:\PBDLL60\BIN" ' Starting Directory
        IF FolderDialog(0,"Select a folder", Path) THEN 
            MSGBOX Path
        END IF
    
    END FUNCTION
    '************************************************************************

    ------------------
    Kind Regards
    Mike

    [This message has been edited by Mike Trader (edited July 06, 2001).]

    Leave a comment:


  • Semen Matusovski
    replied
    Mike I combined some fragments.
    Code:
       #Compile Exe
       #Register None
       #Dim All
       #Include "WIN32API.INC"
    
       %ID_FRAME1    = 101
       %ID_DIRECTORY = 102
       %ID_SELECTDIR = 103
    
       Declare Sub CoTaskMemFree Lib "ole32.dll" Alias "CoTaskMemFree" (pv As Long)
       
       %BIF_RETURNONLYFSDIRS   = 1
       %BIF_STATUSTEXT         = 4
       %BFFM_INITIALIZED       = 1
       %BFFM_SELCHANGED        = 2
       %BFFM_SETSTATUSTEXT     = %WM_USER + 100
       %BFFM_ENABLEOK          = %WM_USER + 101
       %BFFM_SETSELECTION      = %WM_USER + 102
                                        
       CallBack Function BrowseForFolderProc
          Dim TmpAsciiz As Asciiz * %MAX_PATH, StatusText As String, CurDrv As Asciiz * 3
          %maxNetResources = 1000
          Dim i As Long, hEnum As Long, d As Long, j As Long, k As Long
          Dim NetResources(%maxNetResources -1) As NETRESOURCE
    
          Select Case CbMsg
             Case %BFFM_INITIALIZED
                TmpAsciiz = CurDir$
                SendMessage CbHndl, %BFFM_SETSELECTION, 1, VarPtr(TmpAsciiz)
             Case %BFFM_SELCHANGED
                SHGetPathFromIDList ByVal CbWparam, TmpAsciiz
                StatusText = TmpAsciiz
                
                If Asc(TmpAsciiz, 2) <> 58 Then i = 0 Else i = Asc(TmpAsciiz, 1)
                If i < 65 Or i > 80 Then i = 0 Else If i >= 97 Or i > 112 Then i = i - 32
                
                If i Then
                   CurDrv = Chr$(i) + ":"
                   Select Case GetDriveType(CurDrv)
                      Case %DRIVE_FIXED
                      Case %DRIVE_REMOTE
                         If IsFalse(WNetOpenEnum(%RESOURCE_CONNECTED, %RESOURCETYPE_ANY, 0&, ByVal 0&, hEnum)) Then
                            If hEnum Then
                               d = %maxNetResources: j = Len(NETRESOURCE) * d
                               If IsFalse(WNetEnumResource(hEnum, d, NetResources(0), j)) Then
                                  For k = 0 To d - 1
                                     If UCase$(Left$(NetResources(k)[email protected], 2)) = CurDrv Then _
                                        StatusText = CurDrv + " = " + NetResources(k)[email protected] + " (not allowed)": i = 0
                                  Next
                               End If
                               WNetCloseEnum hEnum
                            End If
                         End If
                      Case Else
                         i = 0: StatusText = "Illegal drive"
                    End Select
                End If
                If i Then If (GetAttr(TmpAsciiz) And %SUBDIR) <> %SUBDIR Then i = 0
                Dialog Send CbHndl, %BFFM_ENABLEOK, 0, Abs(IsTrue(i))
                SendMessage CbHndl, %BFFM_SETSTATUSTEXT, 0, StrPtr(StatusText)
          End Select
       End Function
    
       CallBack Function DlgProc
          Select Case CbMsg
             Case %WM_INITDIALOG
                Control Add Frame,   CbHndl, %ID_FRAME1, " Folder ", 5, 5, 260, 27
                Control Add TextBox, CbHndl, %ID_DIRECTORY, "", 10, 15, 200, 12
                Control Add Button,  CbHndl, %ID_SELECTDIR, "Browse", 215, 15, 45, 12
             Case %WM_COMMAND
                If CbCtl = %ID_SELECTDIR Then
                   Local pidl As Long, sBrowseInfo As BROWSEINFO, TmpAsciiz As Asciiz * %MAX_PATH, DisplayText As Asciiz * 100
                   DisplayText = "Select a folder on local hard disk"
                   SHGetSpecialFolderLocation CbHndl, 17, ByVal VarPtr(sBrowseInfo.pIDLRoot)
                   sBrowseInfo.hWndOwner = CbHndl
                   sBrowseInfo.lpfnCallback  = CodePtr(BrowseForFolderProc)
                   sBrowseInfo.pszDisplayName = VarPtr(TmpAsciiz)
                   sBrowseInfo.lpszTitle = VarPtr(DisplayText)
                   sBrowseInfo.ulFlags = %BIF_RETURNONLYFSDIRS Or %BIF_STATUSTEXT
                   pidl = SHBrowseForFolder(sBrowseInfo)
                   If pidl Then
                      If SHGetPathFromIDList(ByVal pidl, TmpAsciiz) Then Control Set Text CbHndl, %ID_DIRECTORY, TmpAsciiz
                      CoTaskMemFree ByVal pidl
                   End If
                   CoTaskMemFree ByVal sBrowseInfo.pIDLRoot
                             
                End If
          End Select
       End Function
    
       Function PbMain
          Dim hDlg As Long
          Dialog New 0, "Test", , , 270, 70, %WS_CAPTION Or %WS_SYSMENU Or %WS_MINIMIZEBOX To hDlg
          Dialog Show Modal hDlg Call DlgProc
       End Function
    BTW, one question, not SHBrowseForFolder relative.
    How to detect ia printer port connected to another PC ?
    Should be somewhere around WNet .., but lazy to search.
    Does somebody know ?


    ------------------
    E-MAIL: [email protected]

    Leave a comment:


  • Lance Edmonds
    replied
    The callback in your code is a simple callback rather than a DlgProc/WndProc callback, per se.

    That is, it is not the callback that processes every single SHBrowseForFolder dialog event. Rather, it is a user-defined callback that can receive/process a limited number of notifications from the SHBrowseForFolder dialog - events that your app may need to operate upon for some reason.

    For example, in one of my apps, I use the callback to verify whether the selected folder name is valid in the scope of my application, and if not, I send a %BFFM_ENABLEOK message to disable the OK button. See my very recent post for a snapshot of my callback which (tries to) prevent non-local folder names from being selected.

    A couple of tips for you:

    1. All references to 256 bytes should be replaced with the equate %MAX_PATH (which is 260).

    2. In the calling code, you need to free the memory used by the ID List after retrieving the folder name:
    Code:
    DECLARE SUB CoTaskMemFree LIB "ole32.dll" ALIAS "CoTaskMemFree" (BYVAL hMem AS LONG)
    ...
    IF lpidlist& THEN        
      ' zBuffer = SPACE$(%MAX_PATH) ' ASCIIZ strings do not need to be pre-initialized!
      CALL SHGETPATHFROMIDLIST (lpidlist&, zBuffer)
      CoTaskMemFree lpidlist&
      FUNCTION = lpidlist
    END IF
    (Note: in your calling code, your call to SHGetPathFromIDList passes a variable called "Dir", but this should be "zBuffer")

    3. In your callback, you are passing an ASCIIZ string to ShGetPathFromIDList, so you can pass the second parameter directly, rather than the BYVAL VARPTR(zDir) method you are using:
    Code:
    IF SHGETPATHFROMIDLIST(a&, zdir) THEN
    4. Since this callback uses the standard format of a WndProc/DlgProc (hWnd,wMsg,wParam,lParam), you can substitute a DDT CALLBACK FUNCTION and use the internal CBxxx system variables. This is purely optional, but makes the code slightly easier to write:
    Code:
    CALLBACK FUNCTION fbrowseproc
        DIM zdir AS ASCIIZ * %max_path
        IF CBMSG = %BFFM_INITIALIZED THEN
            DIALOG SEND CBHNDL, %BFFM_SETSELECTION, %TRUE, CBLPARAM
        ELSEIF CBMSG = %BFFM_SELCHANGED THEN
            CALL SHGetPathFromIDList(BYVAL CBWPARAM, zDir)
        END IF
    END FUNCTION
    I hope this helps!


    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>

    Leave a comment:


  • Mike Trader
    replied
    Thx Lance,

    I found Win32.hlp at: http://www.cs.virginia.edu/~lcc-win32/

    I read it, but i just dont get why its necessary to send a message to the main hDlg window?

    The Win32.hlp says:
    The browse dialog box calls this function to notify it about events.

    notify IT - I assume the IT is the SHBROWSEFORFOLDER Dialog box.

    So why are we sending a message to the HDlg window? There is nothing in that Callback function to process anything?
    What is accomplished by doing that?


    ------------------
    Kind Regards
    Mike

    Leave a comment:


  • Lance Edmonds
    replied
    The callback is needed to verify that the dialog should highlight the specified initial folder... exactly as you noted. Without the start folder confirmation (Sending a %bffm_setselection message), the dialog will start with the default set to "My Computer" (or whatever it haappens to be called on the particular installation).

    This is "briefly" documented in WIN32.HLP.

    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>

    Leave a comment:


  • Mike Trader
    started a topic SHBROWSEFORFOLDER CODEPTR question

    SHBROWSEFORFOLDER CODEPTR question

    I have this code from the forum. It works, but I would very much like to remove
    the %wm_user declarations:

    %bffm_setstatustext=%wm_user+100
    %bffm_setselection=%wm_user+102

    I just cant figure out whats going on with the line
    tbi.lpfncallback = CODEPTR(fbrowseproc) ' wassis all about?

    I want to loose the Callback function? fbrowseproc alltogether
    but when I do it no longer goes to my startdir.

    How do I do this pls?

    Code:
    TYPE browseinfo
         hwndowner AS LONG
         pidlroot AS LONG
         pszdisplayname AS ASCIIZ PTR
         lpsztitle AS ASCIIZ PTR
         ulflags AS LONG
         lpfncallback AS LONG
         lparam AS LONG
         iimage AS LONG
    END TYPE
    
    
    'Why dont I need these when i #INCLUDE     "WIN32API.INC"???
    'DECLARE FUNCTION SHBROWSEFORFOLDER   LIB "SHELL32.DLL" ALIAS "SHBrowseForFolder"   (lpbi AS BrowseInfo) AS LONG
    'DECLARE FUNCTION SHGETPATHFROMIDLIST LIB "SHELL32.DLL" ALIAS "SHGetPathFromIDList" (BYVAL pidList AS LONG, BYVAL lpBuffer AS LONG) AS LONG
    
    %bffm_setstatustext=%wm_user+100
    %bffm_setselection=%wm_user+102 
    
    '-----------------------------------------------------------------------------------------------------
    FUNCTION FolderDialog(hwnd AS LONG, title AS STRING, Dir AS ASCIIZ*%max_path ) AS LONG
        LOCAL zbuffer AS ASCIIZ*%max_path 
        LOCAL lpidlist AS LONG
        LOCAL zstartdir AS ASCIIZ*%max_path 
        LOCAL tbi AS browseinfo
        tbi.hwndowner    = hwnd
        tbi.lpsztitle    = STRPTR(title)
        zstartdir        = Dir
        tbi.ulflags      = &h0001 OR &h0002 OR &h0004
        tbi.pidlroot     = 0
        tbi.lpfncallback = CODEPTR(fbrowseproc) ' wassis all about?
        tbi.lparam       = VARPTR(zstartdir)
        lpidlist         = SHBROWSEFORFOLDER(tbi)
        IF lpidlist THEN
            zBuffer = SPACE$(256)
            CALL SHGETPATHFROMIDLIST (lpidlist&, Dir) ' Return the path
           'Dir = LEFT$(Buffer, INSTR(Buffer, CHR$(0)) - 1)
            FUNCTION = lpidlist
        END IF
    MSGBOX zstartdir
    END FUNCTION
    
    '-----------------------------------------------------------------------------------------------------
    FUNCTION fbrowseproc(BYVAL hwnd&, BYVAL msg&, BYVAL a&, BYVAL startdir&) AS LONG ' i wanna loose this alltogether
         STATIC zdir AS ASCIIZ*%max_path
          SELECT CASE msg&
           CASE 1
             SENDMESSAGE hwnd&, %bffm_setselection, %true, startdir&
           CASE 2
            IF SHGETPATHFROMIDLIST(a&,BYVAL VARPTR(zdir)) THEN
               SENDMESSAGE hwnd&, %bffm_setstatustext, 0, BYVAL VARPTR(zdir)
            END IF
          END SELECT
          FUNCTION=0
    END FUNCTION    
    
    '************************************************************************
    ------------------
    Kind Regards
    Mike



    [This message has been edited by Mike Trader (edited July 05, 2001).]
Working...
X