PathRequester to find a specific file

Just starting out? Need help? Post your questions and find answers here.
SniffTheGlove
Enthusiast
Enthusiast
Posts: 122
Joined: Sat Nov 19, 2011 6:51 pm

PathRequester to find a specific file

Post by SniffTheGlove »

Hello,
Looking for a Windows Only implementation...

I am looking for a way to replicate how windows shows a path selector (just like PB PathRequester) however the OK button is disabled until a path is chosen that includes a specific file.

In Windows this happens when you are asked to select the location of an ini file during installation of some drivers.

EG I want the user to locate a specific file say myfile.ini

If I use PB OpenFileRequester then I can specify a file however the verification check only happens once a user clicks the OPEN button and as happens the file does not have to be there for the OPEN to process, so you have to add code into the cancellation to recall the OpenFileRequestor and so on.

I much prefer PathRequester but only for the OK to be enabled as soon ans a path is clicked on and that file resides in that path or if there is a way to disable the OPEN button in OpenFileRequester until a path is chosen that includes the specified file.

I hope you understand me.

Thanks
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: PathRequester to find a specific file

Post by IdeasVacuum »

...At the end of the day, it's just a form, you can code it yourself in 5 minutes.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
pwd
User
User
Posts: 60
Joined: Thu Sep 06, 2012 9:39 am

Re: PathRequester to find a specific file

Post by pwd »

Slightly modified version of this snippet.

Code: Select all

Procedure BrowseCallbackProc(hwnd, msg, lParam, lData)
  szDir$ = Space(#MAX_PATH)
  Select msg
    Case #BFFM_INITIALIZED
      SendMessage_(hwnd, #BFFM_SETSELECTION, #BFFM_INITIALIZED, lData)
      SendMessage_(hwnd, #BFFM_ENABLEOK, 0, 0)

    Case #BFFM_SELCHANGED
      If SHGetPathFromIDList_(lParam, @szDir$)
        SendMessage_(hwnd, #BFFM_SETSTATUSTEXT, 0, @szDir$)
        If szDir$ = "PATH\TO\YOUR\file.ini"
          SendMessage_(hwnd, #BFFM_ENABLEOK, 0, 1)
        Else
          SendMessage_(hwnd, #BFFM_ENABLEOK, 0, 0)
        EndIf        
      EndIf
  EndSelect
EndProcedure

Procedure.s BrowseForFolder(Style, Titel.s, Path.s)
  Folder.s = Space(#MAX_PATH)
  Dir.BROWSEINFO
  Dir\hwndOwner = GetActiveWindow_()
  Dir\pszDisplayName = @Folder
  Dir\lpszTitle = @Titel
  Dir\ulFlags = Style
  Dir\lpfn = @BrowseCallbackProc()
  Dir\lParam = @Path
  result.l = SHBrowseForFolder_(@Dir)
  SHGetPathFromIDList_(result, @Folder)
  If Folder <> ""
    If FileSize(Folder) = - 2
      If Right(Folder, 1) <> "\" : Folder + "\" : EndIf
    EndIf
  EndIf
  CoTaskMemFree_(result)
  ProcedureReturn Folder
EndProcedure

Style = #BIF_STATUSTEXT | #BIF_BROWSEINCLUDEFILES
Debug BrowseForFolder(Style, "Please choose your path", "")
SniffTheGlove
Enthusiast
Enthusiast
Posts: 122
Joined: Sat Nov 19, 2011 6:51 pm

Re: PathRequester to find a specific file

Post by SniffTheGlove »

Thanks PWD, that got me to a good starting point. I made a few changes to the code and it now does what I want.

I only have one issue if anybody knows how to correct it I will be grateful.

From the following code I have had to set a global variable so I can search for that file when a folder is selected. So is there a way to send the variable FileName.s to the BrowseCallbackProc procedure with out using a global variable from the BrowseForFolder procedure.

If you run this code then the file win.ini is located in the Windows folder...

Code: Select all

Global FileName.s = "win.ini"

Procedure BrowseCallbackProc(hwnd, msg, lParam, lData)
  szDir$ = Space(#MAX_PATH)
  Select msg
    Case #BFFM_INITIALIZED
      SendMessage_(hwnd, #BFFM_SETSELECTION, #BFFM_INITIALIZED, lData)
      SendMessage_(hwnd, #BFFM_ENABLEOK, 0, 0)
      
    Case #BFFM_SELCHANGED
      If SHGetPathFromIDList_(lParam, @szDir$)
        If ExamineDirectory(0, szDir$, "*." + GetExtensionPart(FileName.s))
          While NextDirectoryEntry(0)
            If LCase(DirectoryEntryName(0)) = LCase(Filename.s)
              SendMessage_(hwnd, #BFFM_ENABLEOK, 0, 1)
            Else
              SendMessage_(hwnd, #BFFM_ENABLEOK, 0, 0)
            EndIf       
          Wend
          FinishDirectory(0)
        EndIf
      EndIf
  EndSelect
EndProcedure

Procedure.s BrowseForFolder(Style, Titel.s, Path.s, FileName.s)
  Folder.s = Space(#MAX_PATH)
  Dir.BROWSEINFO
  Dir\hwndOwner = GetActiveWindow_()
  Dir\pszDisplayName = @Folder
  Dir\lpszTitle = @Titel
  Dir\ulFlags = Style
  Dir\lParam = @Path
  Dir\lpfn = @BrowseCallbackProc()
  result.l = SHBrowseForFolder_(@Dir)
  SHGetPathFromIDList_(result, @Folder)
  If Folder <> ""
    If FileSize(Folder) = - 2
      If Right(Folder, 1) <> "\" : Folder + "\" : EndIf
    EndIf
  EndIf
  CoTaskMemFree_(result)
  ProcedureReturn Folder
EndProcedure

Style = 0
FullPathAndFileName.s = BrowseForFolder(Style, "Please choose your path", "C:\",FileName.s)
Debug FullPathAndFileName.s + FileName.s
.
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: PathRequester to find a specific file

Post by luis »

Since BROWSEINFO\lParam it's a custom parameter, probably you could just merge all the vars you want in path$ inside BrowseForFolder().
In the callback, split the string back into its components.
Or use a structure defined in BrowseForFolder() and store its address inside Dir\lParam.
Since you don't leave the procedure the struct should be accessible from the callback.


EDIT: Using your code, something like this:

Code: Select all

; Global FileName.s = "win.ini"

Structure T_BROWSE_DATA
 Path$
 FileName$
EndStructure

Procedure BrowseCallbackProc(hwnd, msg, lParam, *lData.T_BROWSE_DATA)
  szDir$ = Space(#MAX_PATH)
  
  FileName$ = *lData\FileName$
  Path$ = *lData\Path$
  
  Select msg
    Case #BFFM_INITIALIZED
      SendMessage_(hwnd, #BFFM_SETSELECTION, #BFFM_INITIALIZED, Path$)
      SendMessage_(hwnd, #BFFM_ENABLEOK, 0, 0)      
     
    Case #BFFM_SELCHANGED
      SendMessage_(hwnd, #BFFM_ENABLEOK, 0, 0) 
      
      If SHGetPathFromIDList_(lParam, @szDir$)
        If ExamineDirectory(0, szDir$, "*." + GetExtensionPart(FileName$))
          While NextDirectoryEntry(0)            
            If LCase(DirectoryEntryName(0)) = LCase(FileName$)
              SendMessage_(hwnd, #BFFM_ENABLEOK, 0, 1) 
            EndIf       
          Wend
          FinishDirectory(0)
        EndIf
      EndIf
  EndSelect
EndProcedure

Procedure.s BrowseForFolder(Style, Titel.s, Path.s, FileName.s)
  Protected MyData.T_BROWSE_DATA  
  
  MyData\Path$ = Path
  MyData\FileName$ = FileName
  
  Folder.s = Space(#MAX_PATH)
  Dir.BROWSEINFO
  Dir\hwndOwner = GetActiveWindow_()
  Dir\pszDisplayName = @Folder
  Dir\lpszTitle = @Titel
  Dir\ulFlags = Style
  Dir\lParam = @MyData ; -> this end up in *lData
  Dir\lpfn = @BrowseCallbackProc()
  result.l = SHBrowseForFolder_(@Dir)
  SHGetPathFromIDList_(result, @Folder)
  If Folder <> ""
    If FileSize(Folder) = - 2
      If Right(Folder, 1) <> "\" : Folder + "\" : EndIf
    EndIf
  EndIf
  CoTaskMemFree_(result)
  ProcedureReturn Folder
EndProcedure

Style = 0
FileName.s = "filename.ini"
FullPathAndFileName.s = BrowseForFolder(Style, "Please choose your path", "C:\", FileName)
Debug FullPathAndFileName + FileName
Last edited by luis on Sun Mar 31, 2013 12:40 pm, edited 1 time in total.
"Have you tried turning it off and on again ?"
A little PureBasic review
SniffTheGlove
Enthusiast
Enthusiast
Posts: 122
Joined: Sat Nov 19, 2011 6:51 pm

Re: PathRequester to find a specific file

Post by SniffTheGlove »

Thanks Luis.

I went with the structure you posted. Works great
Post Reply