File Requester (Windows 8)

Windows specific forum
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

File Requester (Windows 8)

Post by Michael Vogel »

Using the following code below, the file name will not be shown completely before moving the cursor to the left. I don't think, that PB is responsible for this, I would assume it is a windows bug - not sure about the behaviour in other windows versions.

Code: Select all

s.s
s="Oops WWWWWWW.lst"
s=OpenFileRequester(s,s,"Image List files (*.lst)|*.lst|Text Files (*.txt)|*.txt|All Files (*.*)|*.*",0)
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: File Requester (Windows 8)

Post by davido »

@Michael Vogel
Windows 7 64bit with PB5.20LTS 64bit.

I think it shows the same as yours does: 'WWWWWW.lst

Actually just a little bit of the 1st W (depicted by the ' above.) shows, too.
DE AA EB
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: File Requester (Windows 8)

Post by c4s »

Well, I do think that it somehow has to do with PureBasic. When I resave a file called "Oops WWWWWWW" in the Windows Editor the full file name is displayed. Also I've never seen this behavior in any other application that uses a file requester - except my own (written in PureBasic ;-)).
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
TassyJim
Enthusiast
Enthusiast
Posts: 151
Joined: Sun Jun 16, 2013 6:27 am
Location: Tasmania (Australia)

Re: File Requester (Windows 8)

Post by TassyJim »

I just did a test with Liberty Basic and it has the same problem. (Win7 64Bit)
I have been programming with LB for many years and never noticed!

Jim
Fred
Administrator
Administrator
Posts: 16623
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: File Requester (Windows 8)

Post by Fred »

I have tried with full API and it's the same, so it's probably a windows issue.

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


;-{ 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_ENABLESIZING  ;| #OFN_NOCHANGEDIR
  myOFN\lpfnHook          = @gui_OFN_HookProc()
  If *pReq\multiSelect
    myOFN\flags | #OFN_ALLOWMULTISELECT
  EndIf
  GetOpenFileName_(@myOFN)
  
  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$ = "Oops WWWWWWW.lst"
        OFNreq\MultiSelect  = 1
        OFNreq\PatternPos   = 1
        OFNreq\Pattern$     = "Image List files (*.lst)|*.lst|Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
        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
      EndSelect
    EndSelect
  ForEver
EndIf
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: File Requester (Windows 8)

Post by PB »

Seems to be due to the number of chars in the filename.
Or perhaps the pixel width of the filename. Whatever. See:

Code: Select all

Procedure Test(n$)
  OpenFileRequester("Test",n$,"Image List files (*.lst)|*.lst|Text Files (*.txt)|*.txt|All Files (*.*)|*.*",0)
EndProcedure

Test("1234567890.lst") ; Shows all.
Test("123456789012.lst") ; Cropped.
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4637
Joined: Sun Apr 12, 2009 6:27 am

Re: File Requester (Windows 8)

Post by RASHAD »

As Fred said I think it is a windows issue
Because it works fine with the old style of the dialog

Work around
Tested with win 7 x64

Code: Select all

Procedure LongName(Parameter)
  Delay(300)
  keybd_event_(#VK_CONTROL,0,0,0)
  keybd_event_(#VK_C,0,0,0) 
  keybd_event_(#VK_C,0,#KEYEVENTF_KEYUP,0)
  keybd_event_(#VK_V,0,0,0) 
  keybd_event_(#VK_V,0,#KEYEVENTF_KEYUP,0)  
  keybd_event_(#VK_CONTROL,0,#KEYEVENTF_KEYUP,0)
EndProcedure

Thread = CreateThread(@LongName(), 0)

File$ = OpenFileRequester("Please choose file to load", "Oops WWWWWWW.lst", "", 0)
If File$ <> ""
   Debug File$
EndIf
If IsThread(Thread)
   KillThread(Thread)
EndIf
Egypt my love
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: File Requester (Windows 8)

Post by PB »

Your workaround doesn't work here at all. I either get the normal
cropped start of filename, or the text "cv" in the filename field.
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4637
Joined: Sun Apr 12, 2009 6:27 am

Re: File Requester (Windows 8)

Post by RASHAD »

What do you mean by here?
You may need to increase the delay
Another approach

Code: Select all

Global Hook,Run

Procedure HookCB( uMsg , wParam , lParam)   
   Select uMsg
     Case #HC_ACTION
          Run + 1
          hwnd = FindWindow_(0,"Please choose file to load")
          If hWnd And Run = 1
              keybd_event_(#VK_HOME,0,0,0)
              keybd_event_(#VK_HOME,0,#KEYEVENTF_KEYUP,0)
              keybd_event_(#VK_CONTROL,0,0,0)
              keybd_event_(#VK_A,0,0,0)
              keybd_event_(#VK_A,0,#KEYEVENTF_KEYUP,0)
              keybd_event_(#VK_CONTROL,0,#KEYEVENTF_KEYUP,0)
          EndIf
        
   EndSelect   
   ProcedureReturn Result
EndProcedure

Hook = SetWindowsHookEx_(#WH_FOREGROUNDIDLE, @HookCB() , 0, GetCurrentThreadId_())

Pattern$ = "Text (*.txt)|*.txt;*.bat|PureBasic (*.pb)|*.pb|All files (*.*)|*.*"
Pattern = 0 
File$ = OpenFileRequester("Please choose file to load","Oops WWWWWWW.lst", Pattern$, Pattern)
Debug File$
UnhookWindowsHookEx_(Hook)

Egypt my love
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: File Requester (Windows 8)

Post by davido »

@RASHAD
Thank you for taking the time to code these 'workarounds'.

Your 1st program works correctly with my system.
The second program, however, produces the original error.

My system: Windows 7 64bit with PB5.20LTS 64bit.
DE AA EB
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: File Requester (Windows 8)

Post by Little John »

keybd_event_ is only recommended for Windows versions prior to Windows 2000! Most people here probably have more recent Windows versions, this might (partially) explain the problems that they encounter with the code. For Windows 2000 and newer, SendInput_ should be used instead.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4637
Joined: Sun Apr 12, 2009 6:27 am

Re: File Requester (Windows 8)

Post by RASHAD »

Hi davido

Change to and report

Code: Select all

If hWnd And Run = 4
Hi LJ
Yes I know but I am too lazy these days :)

New snippet

Code: Select all

Global Result.s  
  
#OSVEX_LENGTH           = 88 
#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 

#CDN_FIRST = (-601) 
#CDN_SELCHANGE = (#CDN_FIRST - 1) 

Structure OPENFILENAMEXP Extends OPENFILENAME
  pvReserved.l
  dwReserved.l
  FlagsEx.i
EndStructure   
  
Procedure.s My_OpenFileRequester(Title$,Pattern$,Defdir$,Deffile$)
    Pattern$ = Pattern$ + "|"
    Dim x(10):n=1
     For i = 1 To Len(Pattern$)
      If PeekB(@Pattern$+i) = 124
         x(n) = i
         n+1
      EndIf
     Next
     
     For k=1 To n-1
        PokeB(@Pattern$+x(k),0)
     Next
          
    of.OPENFILENAMEXP
    of\lStructSize = SizeOf(of) 
    of\lpstrTitle = @Title$
    of\lpstrInitialDir = @Defdir$
    of\lpstrFilter = @Pattern$
    of\nMaxFile = #MAX_PATH 
    of\lpstrFile = @Deffile$
    ;of\lpfnHook = @OFHookProc()
    of\lCustData = OpenYesNo
    of\Flags     = #OFS_FILE_OPEN_FLAGS | #OFN_ENABLEHOOK| #OFN_ENABLESIZING  ;#OFS_FILE_OPEN_FLAGS | #OFN_ENABLESIZING Flags for new style
    of\FlagsEx   = 0
    If GetOpenFileName_(of) 
      Result = PeekS(of\lpstrFile)
    EndIf
    ProcedureReturn Result 
EndProcedure   
  

Title$   = "Please choose file to load"
Pattern$ = "Text (*.txt)|*.txt;*.bat|PureBasic (*.pb)|*.pb|All files (*.*)|*.*"
Defdir$  = "E:\"
Deffile$ = "Oops WWWWWWW.lst"

My_OpenFileRequester(Title$,Pattern$,Defdir$,Deffile$)
Debug Result
Edit :Just tested the last snippet with Windows 8 and it works fine
I think the problem with windows 7
Use for new look with win 8:

Code: Select all

of\Flags     = #OFS_FILE_OPEN_FLAGS |  #OFN_ENABLESIZING 
Egypt my love
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: File Requester (Windows 8)

Post by davido »

Hi RASHAD,

Run = 4 ; Yes, it works perfectly. Thanks. :D

Just for fun I tried a few variations:

2 - 7 work as for 4
8 initially shows the bug, but after a very short delay (less than a second) displays it correctly. No mouse movement!
The delay increases for larger numbers. At 48 the delay was about 2 seconds. Got bored. Gave up!

*** Your latest snippet works fine. ***
DE AA EB
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: File Requester (Windows 8)

Post by Little John »

RASHAD wrote:Hi LJ
Yes I know but I am too lazy these days :)
:)

Hi RASHAD,

here is my variant of your first code in this thread, which solves the issue for me with PB 5.20 LTS x64 on Windows 7 x64:

Code: Select all

Procedure.i SendKey (key.a, up.i)
   Protected send.Input
   
   send\type = #INPUT_KEYBOARD
   send\ki\wVk = key
   If up = #False
      send\ki\dwFlags = 0
   Else
      send\ki\dwFlags = #KEYEVENTF_KEYUP
   EndIf
   
   ProcedureReturn SendInput_(1, @send, SizeOf(Input))
EndProcedure

Macro SendKeyDown (_key_)
   SendKey(_key_, #False)
EndMacro

Macro SendKeyUp (_key_)
   SendKey(_key_, #True)
EndMacro

;-------------------------------------------------------------

Procedure KeyInput (Parameter)
   Delay(400)
   SendKeyDown(#VK_HOME)
   SendKeyUp  (#VK_HOME)
EndProcedure


Thread = CreateThread(@KeyInput(), 0)

File$ = OpenFileRequester("Please choose file to load", "Oops WWWWWWW.lst", "", 0)
If File$ <> ""
   Debug File$
EndIf
If IsThread(Thread)
   KillThread(Thread)
EndIf
Last edited by Little John on Tue Oct 01, 2013 3:24 pm, edited 1 time in total.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: File Requester (Windows 8)

Post by PB »

> What do you mean by here?

Here on my PC. :)
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
Post Reply