GetOpen/Save filename

Share your advanced PureBasic knowledge/code with the community.
Justin
Addict
Addict
Posts: 948
Joined: Sat Apr 26, 2003 2:49 pm

GetOpen/Save filename

Post by Justin »

Code updated For 5.20+

I needed some more functionality than Openfilerequester so i did this, maybe someone finds it useful. only for windows

extra features are:

you can set parent window
you can set a default extension
it can return the index of the selected file type filter
it can return the file title (filename+ext without path)
you can set any api flag for extra features
you can use multiselection in Save style

i have set the max buffer size to 2048 if is too small returns an empty string

multiselection is done in a similar way of Openfilereq.. but using a handle,
see example

the are 3 main functions
GetOpenFileName()
GetSaveFileName()
NextFileName()

the rest are helpers

Code: Select all

;GetOpenFilename()
;Justin 01/05

#OFN_ENABLESIZING = $800000

Structure _COMMDLG_MULTI_DATA_
  BufOffset.l
  FileBuf.l
  Dir.s
EndStructure

Procedure.s AddBackSlash(dir$)
  If dir$
    If Right(dir$, 1)<>"\" : dir$ + "\" : EndIf
  EndIf
  ProcedureReturn dir$
EndProcedure

Procedure cdgMakeFilter(*filter.BYTE)   
  While *filter\b<>0
    If *filter\b = '|' : *filter\b= 0 : EndIf
    *filter + 1
  Wend
EndProcedure

Procedure.s cdgAskFileName(hwndOwner, Title$, InitialDir$, filter$, FilterIndex, defFile$, defExt$, *hMulti.LONG, *iFilter.LONG, *FileTitle, flags.l, mode)
  of.OPENFILENAME
  
  bufSize = 2048
  of\lpstrFile = AllocateMemory(bufSize)
  
  ret$ = ""
  
  of\lStructSize = SizeOf(OPENFILENAME)
  of\hwndOwner = hwndOwner
  
  If filter$
    tmpFilter$ = filter$ + "|"
    cdgMakeFilter(@tmpFilter$)
    of\lpstrFilter = @tmpFilter$
  EndIf
  
  of\nFilterIndex = FilterIndex
  
  If defFile$ : lstrcpy_(of\lpstrFile, defFile$) : EndIf
  
  of\nMaxFile = bufSize
  If InitialDir$ : of\lpstrInitialDir = @InitialDir$ : EndIf
  
  If *FileTitle
    of\lpstrFileTitle = *FileTitle
    of\nMaxFileTitle = lstrlen_(*FileTitle)
  EndIf
  
  If Title$ : of\lpstrTitle = @Title$ : EndIf
  
  of\Flags = #OFN_EXPLORER | #OFN_ENABLESIZING
  If flags : of\Flags | flags : EndIf
  
  If *hMulti : of\Flags | #OFN_ALLOWMULTISELECT : EndIf
  
  If defExt$ : of\lpstrDefExt = @defExt$ : EndIf
  
  If mode=1
    r = GetOpenFileName_(@of)
  ElseIf mode=2
    r = GetSaveFileName_(@of)
  EndIf
  
  If r ;Ok
    ret$ = PeekS(of\lpstrFile)
    If *iFilter : *iFilter\l = of\nFilterIndex : EndIf
    
    If *hMulti
      *multiDat._COMMDLG_MULTI_DATA_ = AllocateMemory(SizeOf(_COMMDLG_MULTI_DATA_))
      *multiDat\BufOffset = 0
      *multiDat\FileBuf = of\lpstrFile
      
      *hMulti\l = *multiDat
      
      *multiDat\BufOffset + lstrlen_(ret$) + 1 ;null terminated
      *pChar.BYTE = of\lpstrFile + *multiDat\BufOffset
      
      If *pChar\b<>0 ;more than one selected
        *multiDat\Dir = AddBackSlash(ret$)
        
        fileTitle$ = PeekS(*multiDat\FileBuf + *multiDat\BufOffset)
        *multiDat\BufOffset + lstrlen_(fileTitle$) + 1
        ret$ = *multiDat\Dir + filetitle$
      EndIf
    EndIf
  Else ;Cancel or error
    ret$ = ""
  EndIf
  
  ;Single selection
  If *hMulti=0 : FreeMemory(of\lpstrFile) : EndIf
  
  ProcedureReturn ret$
EndProcedure

;*hMulti : handle obtained by GetOpenFileName() or GetSaveFileName()
;Returns   : next Filename or "". Used in multiple selection.
Procedure.s NextFilename(*hMulti._COMMDLG_MULTI_DATA_)   
  ret$ = PeekS(*hMulti\FileBuf + *hMulti\BufOffset)
  
  If ret$
    *hMulti\BufOffset + lstrlen_(ret$) + 1
    
    ProcedureReturn *hMulti\Dir + ret$
  Else ;End
    FreeMemory(*hMulti\FileBuf)
    FreeMemory(*hMulti)
    ProcedureReturn ""
  EndIf
EndProcedure

;hwndOwner      : window handle of parent window or 0
;title$            : title to be displayed in the caption dialog
;InitialDir$   : initial directory
;filter$         : same as Pattern$ Openfilerequester() parameter
;FilterIndex   : 1 based index of the filter to display
;defFile$         : file name used to initialize the File Name edit control, or ""
;defExt$         : extension that will be appended to the file name if the user fails to type an extension, or ""
;*hMulti         : controls multi selection, address of a long value. it will be filled on function return with a handle used by NextFileName(), #NULL for single selection
;*iFilter         : address of a long value, on function return will be filled by the filter index the user selected, or #NULL.
;*FileTitle      : address of a string created with Space(), on function return contains the file title (file name and extension without path information), or #NULL. It only applies to single selection.
;flags            : api flags for extra features, some common values: #OFN_FILEMUSTEXIST, #OFN_OVERWRITEPROMPT, or 0
;Returns         : first filename selected
Procedure.s GetOpenFileName(hwndOwner, Title$, InitialDir$, filter$, FilterIndex, defFile$, defExt$, *hMulti.LONG, *iFilter.LONG, *FileTitle, flags)
  ProcedureReturn cdgAskFileName(hwndOwner, Title$, InitialDir$, filter$, FilterIndex, defFile$, defExt$, *hMulti, *iFilter, *FileTitle, flags, 1)
EndProcedure

Procedure.s GetSaveFileName(hwndOwner, Title$, InitialDir$, filter$, FilterIndex, defFile$, defExt$, *hMulti.LONG, *iFilter.LONG, *FileTitle, flags.l)
  ProcedureReturn cdgAskFileName(hwndOwner, Title$, InitialDir$, filter$, FilterIndex, defFile$, defExt$, *hMulti, *iFilter, *FileTitle, flags, 2)
EndProcedure

;- #TEST
;Single
fileTitle$ = Space(#MAX_PATH)
file$ = GetOpenFileName(0, "", "", "All files (*.*)|*.*|MP3 (*.mp3)|*.mp3", 1, "", "", #Null, @iFilter, @fileTitle$, #OFN_FILEMUSTEXIST)
Debug file$
Debug fileTitle$
Debug iFilter

;Multi
file$ = GetOpenFileName(0, "", "", "All files (*.*)|*.*|MP3 (*.mp3)|*.mp3", 1, "", "", @hMulti, #Null, #Null, #OFN_FILEMUSTEXIST)

While file$
  Debug file$
  
  file$ = NextFilename(hMulti)
Wend