I asked in "Coding questions" about new look openfilerequester, and I get answered the following, which is working very well:
Code: Select all
; skywalk
; Since the built-in PureBasic OFN Requester does not allow Details View!
; Fill the OFN structure and use a OFNHook Procedure.
; Portions modified from Sparkie's code:
; http://www.purebasic.fr/english/viewtopic.php?p=133878#p133878
EnableExplicit
#sNull$ = "-999"
Structure ScanPBDataTypes
; These take up no memory and are allowed to grow without redim
; when the structure is pointed at a memory buffer.
; ex. *buf\d[i] ; 'i' being incremented in a loop
; Essentially, this is 1 big StructureUnion.
b.b[0] ; byte
w.w[0] ; word
l.l[0] ; long
i.i[0] ; integer
q.q[0] ; quad
f.f[0] ; float
d.d[0] ; double
a.a[0] ; ascii
c.c[0] ; character
u.u[0] ; unicode
;s.s{Use 1-MAX String Length expected 255} ; string
s.s[0] ; This supports 1 String scan. *p\s = @x$, *p\s[1] does not work.
EndStructure
Macro FL_FileExists(Fname)
; 0 = File or Folder does not exist
; 1 = File Exists
; -1 = Folder Exists
; Since FileSize() returns:
; -1 = File Not found.
; -2 = File is a directory.
; 0 = Empty File, > 1 = File Exists
; FileSize() respects '*' wildcards and reports results accordingly.
FileSize(Fname) + 1
EndMacro
Procedure.i SF_CharReplace(*p.ScanPBDataTypes, StrFrom$="|", StrTo$=#NULL$)
; REV: 111227, skywalk
; SYNTAX: nNulls = SF_CharReplace(@x$,"|",#Null$,0)
; DEFAULT: Edit a string in memory to embed null char's = Chr(0)
; RETURN: # of char replacements made.
; If StrFrom$=#Null$, then buffer end is assumed to be double null position.
; Accepts multiple chars, but only works with the 1st char.
; Works with unicode or ascii.
Protected.i i, msLen, nChars
Protected.i CharFrom = Asc(StrFrom$)
Protected.i CharTo = Asc(StrTo$)
; Determine msLen
If CharFrom = #Null ; Search memory for double nulls = end of string buffer
While msLen < 64000
If *p\c[msLen] = 0 And *p\c[msLen+1] = 0
Break
EndIf
msLen + 1
Wend
msLen - 1 ; Ignore the final #Null later in code
Else
msLen = MemoryStringLength(*p) - 1 ; Get Len in characters, not bytes.
; StringByteLength(PeekS(*p)) ; Returns nBytes and depends on ascii/unicode switch!
EndIf
For i = 0 To msLen ; Since walking through String by Character, no need to count bytes/char.
If *p\c[i] = CharFrom
*p\c[i] = CharTo
nChars + 1
EndIf
Next i
;ShowMemoryViewer(@*p,msLen+32)
ProcedureReturn nChars
EndProcedure
Procedure.i Split(s$, Delm$, Array sA.s(1), trimsp.i=0, UseCase.i=#PB_String_CaseSensitive)
; REV: 100405, skywalk
; modified from Trond PB forum code
; www.purebasic.fr/english/viewtopic.php?f=13&t=26738
; REV: 111227, skywalk
; removed ReSize parameter. sA() adjusts to size required = nStrings-1
; added multi-char delimiter, case sensitivity, and unicode.
; UseCase = 0-#PB_String_CaseSensitive or 1-#PB_String_NoCase
; Return: Count of elements or nStrings found.
; If none, then entire string is assigned to sA(0)
; s$ = normal null terminated string
; VB6 syntax -> sA() = Split(expression[, delimiter[, count[, compare]]])
; SizeOf(Character) is converted to a constant by compiler so no speed hit for multiple use
Protected.i i, nStrings
Protected.i sLen = Len(s$)
Protected.i DelmLen = Len(Delm$)
Protected *s.Character = @s$ ; Character Structure points to s$ contents, not its address
Protected.i lastp = *s
Protected Delmc.c
If DelmLen = 0 ; "" or empty
ReDim sA(0)
sA(0) = s$
nStrings = 1
ElseIf sLen = 0 ; s$ = ""
ReDim sA(0)
sA(0) = #NULL$
nStrings = 0
Else ; OK to Split
Dim sA(sLen/DelmLen+1) ; Start array at worst case estimate
If UseCase = #PB_String_CaseSensitive And (DelmLen = 1 Or Delm$ = #CRLF$) ; use faster single character split routine
If DelmLen = 1
Delmc = Asc(Delm$)
Else ; Delm$ = #CRLF$
Delmc = #LF ; use the 2nd char, then trim trailing #CR$ from elements
EndIf
While *s\c ; > 0 means valid Character, = 0 means String terminated.
If *s\c <> Delmc
*s + SizeOf(Character)
Else
*s\c = 0 ; Terminate string with Chr(0) here
sA(nStrings) = PeekS(lastp)
lastp = *s + SizeOf(Character) ; remember last pointer
nStrings + 1
*s + (DelmLen) * SizeOf(Character)
EndIf
Wend
Else ; use slower multi-char split routine
While *s\c ; > 0 means valid Character, = 0 means String terminated.
If CompareMemoryString(*s, @Delm$, UseCase, DelmLen) ; <> 0 means different memory
*s + SizeOf(Character)
Else ; = 0 means identical memory
*s\c = 0 ; Terminate string with Chr(0) here
sA(nStrings) = PeekS(lastp)
lastp = *s + (DelmLen) * SizeOf(Character) ; remember last pointer
nStrings + 1
*s + (DelmLen) * SizeOf(Character)
EndIf
Wend
EndIf
If *s <> lastp ; reached last valid element
sA(nStrings) = PeekS(lastp)
EndIf
ReDim sA(nStrings)
If trimsp
For i = 0 To nStrings
sa(i) = Trim(sa(i))
Next i
If trimsp = 9
For i = 0 To nStrings
sa(i) = Trim(sa(i), #TAB$)
Next i
EndIf
EndIf
If delm$ = #CRLF$
For i = 0 To nStrings
sa(i) = RTrim(sa(i),#CR$)
Next i
EndIf
nStrings + 1 ; Catch #Null$ due to dangling Delm$, "1,2,"
EndIf
ProcedureReturn nStrings
EndProcedure
;-{ GUI FILE STUFF
#OSVEX_LENGTH = 88 ; If > Win2K = 88 Else = 76
#CDN_INITDONE = #CDN_FIRST - 0
#CDN_SELCHANGE = #CDN_FIRST - 1
#CDN_FOLDERCHANGE = #CDN_FIRST - 2
#OFN_VIEW_REPORT = $702C
#OFN_VIEW_LIST = $702B
#OFN_VIEW_LARGEICON = $7029
#OFN_VIEW_SMALLICON = $702A
#OFN_VIEW_THUMBNAIL = $702D
#OFN_VIEW_THUMBNAIL_2K = $7031
#OFN_VIEW_TILE = $702E
#OFN_ENABLESIZING = $800000
#OFS_FILE_OPEN_FLAGS = #OFN_EXPLORER | #OFN_LONGNAMES | #OFN_CREATEPROMPT
#OFS_FILE_SAVE_FLAGS = #OFN_EXPLORER | #OFN_LONGNAMES | #OFN_OVERWRITEPROMPT | #OFN_HIDEREADONLY
Structure OFNdata
Title$
DefFilePath$
Pattern$
PatternPos.i
MultiSelect.i
Array Files$(0)
nFiles.i
EndStructure
Structure OFNgui Extends OFNdata ; Used by OFN Dialog gui
guiX.i
guiY.i
guiWd.i
guiHt.i
EndStructure
Global OFNreq.OFNgui, OFNres.OFNdata
; Custom message for move/resize OpenFileRequester
Global gui_OFN_MoveDlg = RegisterWindowMessage_(@"gui_OFN_MoveDlg")
Procedure gui_OFN_HookProc(hW, msg, wP, lP)
Protected.i hParent, hLV, ri
Select msg
Case #WM_INITDIALOG
; wd, ht
PostMessage_(hW, gui_OFN_MoveDlg, OFNreq\guiWd, OFNreq\guiHt)
Case gui_OFN_MoveDlg
; Reposition @ resize dialog window
hParent = GetParent_(hW)
MoveWindow_(hParent, OFNreq\guiX, OFNreq\guiY, wP, lP, 1)
Case #WM_NOTIFY
; hW is the handle to the dialog
; hParent is the handle to the common control
; hLV is the handle to the listview itself
hParent = GetParent_(hW)
hLV = FindWindowEx_(hParent, 0, "SHELLDLL_DefView", #NULL$)
If hLV
ri = SendMessage_(hLV, #WM_COMMAND, #OFN_VIEW_REPORT, #Null)
EndIf
EndSelect
ProcedureReturn 0
EndProcedure
Procedure.i gui_PathRequester(*pReq.OFNgui, *pRes.OFNdata)
; REV: 120322, skywalk
; Process user response to OpenPathRequester Directory Selection(s)
; Results go in structure OFNres
; If MultiSelect=1, then OFNres\File$(nFiles-1) contains the list of directories
; =0, then OFNres\File$(0) contains 1 selected directory
; SYNTAX: nPaths = gui_PathRequester(hW, @myOFNreq, @myOFNres)
;p$ = PathRequester("Select path(s) to Pack...", "C:\") ; ONLY SUPPORTS 1 PATH SELECTION
Protected.i i, k, wID, xlID, buID, wW, wH
*pRes\nFiles = 0
wID = OpenWindow(#PB_Any, *pReq\guiX, *pReq\guiY, *pReq\guiWd, *pReq\guiHt, *pReq\Title$, #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_SizeGadget)
If wID
StickyWindow(wID, 1)
xlID = ExplorerListGadget(#PB_Any, 10, 10, *pReq\guiWd-20, *pReq\guiHt-50, *pReq\DefFilePath$, #PB_Explorer_NoFiles|#PB_Explorer_MultiSelect|#PB_Explorer_GridLines|#PB_Explorer_FullRowSelect)
buID = ButtonGadget(#PB_Any, *pReq\guiWd/2-40, *pReq\guiHt-GadgetHeight(xlID)-10, 80, 30, "Done")
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
If EventGadget() = buID
*pRes\nFiles = CountGadgetItems(xlID)
ReDim *pRes\Files$(*pRes\nFiles-1)
For i = 0 To *pRes\nFiles - 1
If GetGadgetItemState(xlID, i) & #PB_Explorer_Selected
*pRes\Files$(k) = GetGadgetText(xlID) + GetGadgetItemText(xlID, i)
k + 1
EndIf
Next
*pRes\nFiles = k
If k
ReDim *pRes\Files$(k-1)
*pRes\DefFilePath$ = GetPathPart(*pRes\Files$(0))
Else
ReDim *pRes\Files$(0)
*pRes\DefFilePath$ = *pReq\DefFilePath$
EndIf
Break
EndIf
Case #PB_Event_SizeWindow
wW = WindowWidth(wID)
wH = WindowHeight(wID)
ResizeGadget(xlID, #PB_Ignore, #PB_Ignore, wW-20, wH-50)
ResizeGadget(buID, wW/2-40, GadgetY(xlID)+GadgetHeight(xlID)+5, #PB_Ignore, #PB_Ignore)
Case #PB_Event_CloseWindow
Break
EndSelect
ForEver
EndIf
StickyWindow(wID, 0)
CloseWindow(wID)
ProcedureReturn *pRes\nFiles
EndProcedure
Procedure.i gui_FileRequester(hW.i, *pReq.OFNgui, *pRes.OFNdata)
; REV: 120106, skywalk
; Process user response to OpenFileRequester File Selection(s)
; Results go in structure OFNres
; If MultiSelect=1, then OFNres\File$(nFiles-1) contains the list of files
; =0, then OFNres\File$(0) contains the 1 selected file
; SYNTAX: nFiles = gui_FileRequester(hW, @myOFNreq, @myOFNres)
Protected.i i, j, *selectedFile, bufferSize
Protected.s folder$, nextFile$
; For Filter to function properly, replace "|" with null Chr(0) directly in memory
; Filter must end with 2 null chars
If Right(*pReq\Pattern$,2) <> "||"
*pReq\Pattern$ + "||"
EndIf
SF_CharReplace(@*pReq\Pattern$)
If *pReq\MultiSelect
bufferSize = 32000
Else
bufferSize = 512
EndIf
; Buffer to hold selected file name(s)
*selectedFile = AllocateMemory(bufferSize)
If Len(GetFilePart(*pReq\DefFilePath$))
PokeS(*selectedFile,*pReq\DefFilePath$)
Else
PokeB(*selectedFile, 0) ; 1st byte must be null if no initial file name is to be displayed
EndIf
;ShowMemoryViewer(*selectedFile,750)
Protected myOFN.OPENFILENAME
myOFN\hwndOwner = hW
myOFN\lStructSize = SizeOf(OPENFILENAME) + 12 ; #OSVEX_LENGTH = 88
myOFN\hInstance = #Null
myOFN\lpstrFilter = @*pReq\Pattern$
myOFN\lpstrCustomFilter = #Null
myOFN\nMaxCustFilter = #Null
myOFN\nFilterIndex = *pReq\patternPos
myOFN\lpstrFile = *selectedFile
myOFN\nMaxFile = bufferSize
myOFN\lpstrFileTitle = #Null
myOFN\nMaxFileTitle = #Null
myOFN\lpstrInitialDir = @*pReq\DefFilePath$
myOFN\lpstrTitle = @*pReq\Title$
myOFN\flags = #OFS_FILE_OPEN_FLAGS | #OFN_ENABLEHOOK | #OFN_ENABLESIZING ;| #OFN_NOCHANGEDIR
myOFN\lpfnHook = @gui_OFN_HookProc()
If *pReq\multiSelect
myOFN\flags | #OFN_ALLOWMULTISELECT
EndIf
GetOpenFileName_(@myOFN)
; Deal with multi selections which are null terminated within *selectedFile
; With multi selections, the buffer null terminates folder and files
; If 1st string ends with the folder, we know we have multiple selections
;ShowMemoryViewer(*selectedFile,750)
folder$ = PeekS(*selectedFile)
If *pReq\MultiSelect And FileSize(GetFilePart(folder$)) = -1
*pRes\nFiles = SF_CharReplace(*selectedFile,#NULL$,",")
nextFile$ = PeekS(*selectedFile)
nextFile$ = Mid(nextFile$,FindString(nextFile$,",")+1)
*pRes\nFiles = Split(nextFile$,",",*pRes\Files$())
*pRes\DefFilePath$ = folder$
If Right(*pRes\DefFilePath$,1) <> "\"
*pRes\DefFilePath$ + "\"
EndIf
If *pRes\nFiles = 0
ReDim *pRes\Files$(0)
*pRes\Files$(0) = #sNull$
EndIf
Else ; 1 file selected
If FL_FileExists(folder$) > 0
*pRes\nFiles = 1
*pRes\Files$(0) = GetFilePart(Folder$)
*pRes\DefFilePath$ = GetPathPart(Folder$)
Else
*pRes\nFiles = 0
*pRes\Files$(0) = #sNull$
EndIf
EndIf
FreeMemory(*selectedFile)
ProcedureReturn *pRes\nFiles
EndProcedure
;-}
Enumeration
#gadResults
#gadBrowseFiles
#gadBrowsePaths
#gadClear
EndEnumeration
Define.i i,evG
Define.s s$
If #PB_Compiler_Unicode
s$ = "Get Files w/Details View in Unicode"
Else
s$ = "Get Files w/Details View in Ascii"
EndIf
If OpenWindow(0,0,0,440,340,s$,#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
EditorGadget(#gadResults,20,40,400,300)
ButtonGadget(#gadBrowseFiles,20,0,100,20,"Browse For File(s)...")
ButtonGadget(#gadBrowsePaths,130,0,100,20,"Browse For Path(s)...")
ButtonGadget(#gadClear,390,0,30,20,"Clear")
Repeat
Select WaitWindowEvent(5)
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
evG = EventGadget()
Select evG
Case #gadClear
ClearGadgetItems(#gadResults)
Case #gadBrowseFiles
OFNreq\guiX = 20
OFNreq\guiY = 20
OFNreq\guiWd = 300
OFNreq\guiHt = 300
OFNreq\Title$ = "Select File(s)"
OFNreq\DefFilePath$ = "d:\"
OFNreq\MultiSelect = 1
OFNreq\PatternPos = 1
OFNreq\Pattern$ = "All Files (*.*)|*.*|CSV Files (*.csv)|*.csv|Text Files (*.txt)|*.txt||"
If gui_FileRequester(WindowID(0), @OFNreq, @OFNres)
AddGadgetItem(#gadResults,-1, Str(OFNres\nFiles) + " File(s) From '" + OFNres\DefFilePath$ + "' =")
For i = 0 To OFNres\nFiles - 1
AddGadgetItem(#gadResults,#PB_Any,OFNres\Files$(i))
Next i
EndIf
Case #gadBrowsePaths
OFNreq\guiX = 20
OFNreq\guiY = 20
OFNreq\guiWd = 300
OFNreq\guiHt = 300
OFNreq\Title$ = "Select Path(s)..."
OFNreq\DefFilePath$ = "c:\"
OFNreq\MultiSelect = 1
OFNreq\PatternPos = 1
OFNreq\Pattern$ = "All Files (*.*)|*.*|CSV Files (*.csv)|*.csv|Text Files (*.txt)|*.txt||"
If gui_PathRequester(@OFNreq,@OFNres)
AddGadgetItem(#gadResults,-1, Str(OFNres\nFiles) + " Path(s) From '" + OFNres\DefFilePath$ + "' =")
For i = 0 To OFNres\nFiles - 1
AddGadgetItem(#gadResults,#PB_Any,OFNres\Files$(i))
Next i
EndIf
EndSelect
EndSelect
ForEver
EndIf
Code: Select all
Global resultsdll.s
; skywalk
; Since the built-in PureBasic OFN Requester does not allow Details View!
; Fill the OFN structure and use a OFNHook Procedure.
; Portions modified from Sparkie's code:
; http://www.purebasic.fr/english/viewtopic.php?p=133878#p133878
EnableExplicit
#sNull$ = "-999"
Structure ScanPBDataTypes
; These take up no memory and are allowed to grow without redim
; when the structure is pointed at a memory buffer.
; ex. *buf\d[i] ; 'i' being incremented in a loop
; Essentially, this is 1 big StructureUnion.
b.b[0] ; byte
w.w[0] ; word
l.l[0] ; long
i.i[0] ; integer
q.q[0] ; quad
f.f[0] ; float
d.d[0] ; double
a.a[0] ; ascii
c.c[0] ; character
u.u[0] ; unicode
;s.s{Use 1-MAX String Length expected 255} ; string
s.s[0] ; This supports 1 String scan. *p\s = @x$, *p\s[1] does not work.
EndStructure
Macro FL_FileExists(Fname)
; 0 = File or Folder does not exist
; 1 = File Exists
; -1 = Folder Exists
; Since FileSize() returns:
; -1 = File Not found.
; -2 = File is a directory.
; 0 = Empty File, > 1 = File Exists
; FileSize() respects '*' wildcards and reports results accordingly.
FileSize(Fname) + 1
EndMacro
Procedure.i SF_CharReplace(*p.ScanPBDataTypes, StrFrom$="|", StrTo$=#NULL$)
; REV: 111227, skywalk
; SYNTAX: nNulls = SF_CharReplace(@x$,"|",#Null$,0)
; DEFAULT: Edit a string in memory to embed null char's = Chr(0)
; RETURN: # of char replacements made.
; If StrFrom$=#Null$, then buffer end is assumed to be double null position.
; Accepts multiple chars, but only works with the 1st char.
; Works with unicode or ascii.
Protected.i i, msLen, nChars
Protected.i CharFrom = Asc(StrFrom$)
Protected.i CharTo = Asc(StrTo$)
; Determine msLen
If CharFrom = #Null ; Search memory for double nulls = end of string buffer
While msLen < 64000
If *p\c[msLen] = 0 And *p\c[msLen+1] = 0
Break
EndIf
msLen + 1
Wend
msLen - 1 ; Ignore the final #Null later in code
Else
msLen = MemoryStringLength(*p) - 1 ; Get Len in characters, not bytes.
; StringByteLength(PeekS(*p)) ; Returns nBytes and depends on ascii/unicode switch!
EndIf
For i = 0 To msLen ; Since walking through String by Character, no need to count bytes/char.
If *p\c[i] = CharFrom
*p\c[i] = CharTo
nChars + 1
EndIf
Next i
;ShowMemoryViewer(@*p,msLen+32)
ProcedureReturn nChars
EndProcedure
Procedure.i Split(s$, Delm$, Array sA.s(1), trimsp.i=0, UseCase.i=#PB_String_CaseSensitive)
; REV: 100405, skywalk
; modified from Trond PB forum code
; www.purebasic.fr/english/viewtopic.php?f=13&t=26738
; REV: 111227, skywalk
; removed ReSize parameter. sA() adjusts to size required = nStrings-1
; added multi-char delimiter, case sensitivity, and unicode.
; UseCase = 0-#PB_String_CaseSensitive or 1-#PB_String_NoCase
; Return: Count of elements or nStrings found.
; If none, then entire string is assigned to sA(0)
; s$ = normal null terminated string
; VB6 syntax -> sA() = Split(expression[, delimiter[, count[, compare]]])
; SizeOf(Character) is converted to a constant by compiler so no speed hit for multiple use
Protected.i i, nStrings
Protected.i sLen = Len(s$)
Protected.i DelmLen = Len(Delm$)
Protected *s.Character = @s$ ; Character Structure points to s$ contents, not its address
Protected.i lastp = *s
Protected Delmc.c
If DelmLen = 0 ; "" or empty
ReDim sA(0)
sA(0) = s$
nStrings = 1
ElseIf sLen = 0 ; s$ = ""
ReDim sA(0)
sA(0) = #NULL$
nStrings = 0
Else ; OK to Split
Dim sA(sLen/DelmLen+1) ; Start array at worst case estimate
If UseCase = #PB_String_CaseSensitive And (DelmLen = 1 Or Delm$ = #CRLF$) ; use faster single character split routine
If DelmLen = 1
Delmc = Asc(Delm$)
Else ; Delm$ = #CRLF$
Delmc = #LF ; use the 2nd char, then trim trailing #CR$ from elements
EndIf
While *s\c ; > 0 means valid Character, = 0 means String terminated.
If *s\c <> Delmc
*s + SizeOf(Character)
Else
*s\c = 0 ; Terminate string with Chr(0) here
sA(nStrings) = PeekS(lastp)
lastp = *s + SizeOf(Character) ; remember last pointer
nStrings + 1
*s + (DelmLen) * SizeOf(Character)
EndIf
Wend
Else ; use slower multi-char split routine
While *s\c ; > 0 means valid Character, = 0 means String terminated.
If CompareMemoryString(*s, @Delm$, UseCase, DelmLen) ; <> 0 means different memory
*s + SizeOf(Character)
Else ; = 0 means identical memory
*s\c = 0 ; Terminate string with Chr(0) here
sA(nStrings) = PeekS(lastp)
lastp = *s + (DelmLen) * SizeOf(Character) ; remember last pointer
nStrings + 1
*s + (DelmLen) * SizeOf(Character)
EndIf
Wend
EndIf
If *s <> lastp ; reached last valid element
sA(nStrings) = PeekS(lastp)
EndIf
ReDim sA(nStrings)
If trimsp
For i = 0 To nStrings
sa(i) = Trim(sa(i))
Next i
If trimsp = 9
For i = 0 To nStrings
sa(i) = Trim(sa(i), #TAB$)
Next i
EndIf
EndIf
If delm$ = #CRLF$
For i = 0 To nStrings
sa(i) = RTrim(sa(i),#CR$)
Next i
EndIf
nStrings + 1 ; Catch #Null$ due to dangling Delm$, "1,2,"
EndIf
ProcedureReturn nStrings
EndProcedure
;-{ GUI FILE STUFF
#OSVEX_LENGTH = 88 ; If > Win2K = 88 Else = 76
#CDN_INITDONE = #CDN_FIRST - 0
#CDN_SELCHANGE = #CDN_FIRST - 1
#CDN_FOLDERCHANGE = #CDN_FIRST - 2
#OFN_VIEW_REPORT = $702C
#OFN_VIEW_LIST = $702B
#OFN_VIEW_LARGEICON = $7029
#OFN_VIEW_SMALLICON = $702A
#OFN_VIEW_THUMBNAIL = $702D
#OFN_VIEW_THUMBNAIL_2K = $7031
#OFN_VIEW_TILE = $702E
#OFN_ENABLESIZING = $800000
#OFS_FILE_OPEN_FLAGS = #OFN_EXPLORER | #OFN_LONGNAMES | #OFN_CREATEPROMPT
#OFS_FILE_SAVE_FLAGS = #OFN_EXPLORER | #OFN_LONGNAMES | #OFN_OVERWRITEPROMPT | #OFN_HIDEREADONLY
Structure OFNdata
Title$
DefFilePath$
Pattern$
PatternPos.i
MultiSelect.i
Array Files$(0)
nFiles.i
EndStructure
Structure OFNgui Extends OFNdata ; Used by OFN Dialog gui
guiX.i
guiY.i
guiWd.i
guiHt.i
EndStructure
Global OFNreq.OFNgui, OFNres.OFNdata
; Custom message for move/resize OpenFileRequester
Global gui_OFN_MoveDlg = RegisterWindowMessage_(@"gui_OFN_MoveDlg")
Procedure gui_OFN_HookProc(hW, msg, wP, lP)
Protected.i hParent, hLV, ri
Select msg
Case #WM_INITDIALOG
; wd, ht
PostMessage_(hW, gui_OFN_MoveDlg, OFNreq\guiWd, OFNreq\guiHt)
Case gui_OFN_MoveDlg
; Reposition @ resize dialog window
hParent = GetParent_(hW)
MoveWindow_(hParent, OFNreq\guiX, OFNreq\guiY, wP, lP, 1)
Case #WM_NOTIFY
; hW is the handle to the dialog
; hParent is the handle to the common control
; hLV is the handle to the listview itself
hParent = GetParent_(hW)
hLV = FindWindowEx_(hParent, 0, "SHELLDLL_DefView", #NULL$)
If hLV
ri = SendMessage_(hLV, #WM_COMMAND, #OFN_VIEW_REPORT, #Null)
EndIf
EndSelect
ProcedureReturn 0
EndProcedure
Procedure.i gui_FileRequester(hW.i, *pReq.OFNgui, *pRes.OFNdata)
; REV: 120106, skywalk
; Process user response to OpenFileRequester File Selection(s)
; Results go in structure OFNres
; If MultiSelect=1, then OFNres\File$(nFiles-1) contains the list of files
; =0, then OFNres\File$(0) contains the 1 selected file
; SYNTAX: nFiles = gui_FileRequester(hW, @myOFNreq, @myOFNres)
Protected.i i, j, *selectedFile, bufferSize
Protected.s folder$, nextFile$
; For Filter to function properly, replace "|" with null Chr(0) directly in memory
; Filter must end with 2 null chars
If Right(*pReq\Pattern$,2) <> "||"
*pReq\Pattern$ + "||"
EndIf
SF_CharReplace(@*pReq\Pattern$)
If *pReq\MultiSelect
bufferSize = 32000
Else
bufferSize = 512
EndIf
; Buffer to hold selected file name(s)
*selectedFile = AllocateMemory(bufferSize)
If Len(GetFilePart(*pReq\DefFilePath$))
PokeS(*selectedFile,*pReq\DefFilePath$)
Else
PokeB(*selectedFile, 0) ; 1st byte must be null if no initial file name is to be displayed
EndIf
;ShowMemoryViewer(*selectedFile,750)
Protected myOFN.OPENFILENAME
myOFN\hwndOwner = hW
myOFN\lStructSize = SizeOf(OPENFILENAME) + 12 ; #OSVEX_LENGTH = 88
myOFN\hInstance = #Null
myOFN\lpstrFilter = @*pReq\Pattern$
myOFN\lpstrCustomFilter = #Null
myOFN\nMaxCustFilter = #Null
myOFN\nFilterIndex = *pReq\patternPos
myOFN\lpstrFile = *selectedFile
myOFN\nMaxFile = bufferSize
myOFN\lpstrFileTitle = #Null
myOFN\nMaxFileTitle = #Null
myOFN\lpstrInitialDir = @*pReq\DefFilePath$
myOFN\lpstrTitle = @*pReq\Title$
myOFN\flags = #OFS_FILE_OPEN_FLAGS | #OFN_ENABLEHOOK | #OFN_ENABLESIZING ;| #OFN_NOCHANGEDIR
myOFN\lpfnHook = @gui_OFN_HookProc()
If *pReq\multiSelect
myOFN\flags | #OFN_ALLOWMULTISELECT
EndIf
GetOpenFileName_(@myOFN)
; Deal with multi selections which are null terminated within *selectedFile
; With multi selections, the buffer null terminates folder and files
; If 1st string ends with the folder, we know we have multiple selections
;ShowMemoryViewer(*selectedFile,750)
folder$ = PeekS(*selectedFile)
If *pReq\MultiSelect And FileSize(GetFilePart(folder$)) = -1
*pRes\nFiles = SF_CharReplace(*selectedFile,#NULL$,",")
nextFile$ = PeekS(*selectedFile)
nextFile$ = Mid(nextFile$,FindString(nextFile$,",")+1)
*pRes\nFiles = Split(nextFile$,",",*pRes\Files$())
*pRes\DefFilePath$ = folder$
If Right(*pRes\DefFilePath$,1) <> "\"
*pRes\DefFilePath$ + "\"
EndIf
If *pRes\nFiles = 0
ReDim *pRes\Files$(0)
*pRes\Files$(0) = #sNull$
EndIf
Else ; 1 file selected
If FL_FileExists(folder$) > 0
*pRes\nFiles = 1
*pRes\Files$(0) = GetFilePart(Folder$)
*pRes\DefFilePath$ = GetPathPart(Folder$)
Else
*pRes\nFiles = 0
*pRes\Files$(0) = #sNull$
EndIf
EndIf
FreeMemory(*selectedFile)
ProcedureReturn *pRes\nFiles
EndProcedure
ProcedureDLL.s OpenFileRequester4(title.s,Path1.s, Filtre.s)
Protected i.a
resultsdll=""
OFNreq\guiX = 20
OFNreq\guiY = 20
OFNreq\guiWd = 300
OFNreq\guiHt = 300
OFNreq\Title$ = title
OFNreq\DefFilePath$ = Path1
OFNreq\MultiSelect = 1
OFNreq\PatternPos = 1
OFNreq\Pattern$ = Filtre
If gui_FileRequester(WindowID(0), @OFNreq, @OFNres)
For i = 0 To OFNres\nFiles - 1
resultsdll+OFNres\Files$(i)
Debug OFNres\Files$(i)
Next i
EndIf
ProcedureReturn resultsdll
EndProcedure
then I tried to test it with the following small program:
Code: Select all
OpenWindow(0,0,0,440,340,"hello",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
Path1.s = "C:\"
Filtre1.s = "Text (*.txt)|*.txt;*.bat|PureBasic (*.pb)|*.pb|All Files (*.*)|*.*"
tmp.s= OpenFileRequester4("title",Path1, Filtre1)
Debug tmp
I had error at the line: tmp.s= OpenFileRequester4("title",Path1, Filtre1)
Invalid memory access.
what's wrong??
any help is appreciated
thank you