Pre-setting a file name

Discussions related to database technologies, file handling, directories and storage
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

Pre-setting a file name

Post by KenDown »

Using the routine from the Wiki under "Saving previous load and save paths" I am able to set the filer window to open up to the directory I want to either load from or save to. However try as I might, I simply cannot find a way of setting the filename in advance - it constantly comes up with the last used file name.

So the user loads in "NewFile.txt", but when he comes to save I want to suggest the name "NewEnglish.txt" (which he can alter as he pleases, of course) simply to prevent the other file being over-written by mistake.

I suspect that $$fp{} is somehow involved, but changing that assignment doesn't work. Any ideas, anyone, please?

Thanks.
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

Re: Pre-setting a file name

Post by KenDown »

Hmmm.

I'm still struggling with this one. It would even be useful to know if what I want is impossible!

To repeat: I can set the load or save filer window to open to the desired directory, but I cannot get it to display a file name. It would be useful if the filer window, as well as opening to the correct directory and looking for the desired file type, also had a default file name displayed in the "File name:" line.

Thanks.
Hated Moron

Re: Pre-setting a file name

Post by Hated Moron »

KenDown wrote: Tue 12 Dec 2023, 22:56 It would be useful if the filer window, as well as opening to the correct directory and looking for the desired file type, also had a default file name displayed in the "File name:" line.
Lots of context missing here. Are we talking about BBC BASIC for Windows or BBC BASIC for SDL 2.0? What kind of 'filer window', one created using an Operating System API or one coded in BASIC?

As far as the File Selector created by the filedlg.bbc library is concerned I'm afraid there is no way of pre-setting the filename. That is probably an omission on my part, because it didn't occur to me when I wrote it that it would be useful. I don't expect it would be difficult to add, but the current library doesn't support it.

If it's an OS-supplied file selector (such as the Windows GetOpenFileName API) you will need to consult the associated documentation. There it says this: "lpstrFile: The file name used to initialize the File Name edit control", which suggests it is simply a case of passing the required (NUL-terminated) string in this parameter.

As always, if you can't make it work post a Minimal Reproducible Example (a self-contained piece of code which demonstrates the issue but is as small as possible).
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

Re: Pre-setting a file name

Post by KenDown »

Grrrr! So simple - yet could I get it to work last night? Thank you so much for pointing the way. (BB4W, I'm afraid, not SDL.)

For the benefit of anyone else who may want to do this, here is the functioning program snippet.

Code: Select all

      PROCinit
      PROCsetupfiler(@dir$+CHR$0,"NewFile.txt"+CHR$0,"Text files"+CHR$0+"*.txt"+CHR$0+CHR$0)
      SYS"GetSaveFileName",fs{}TOR%
      IFR%THEN
        REM The actual save routine
      ENDIF
      END
      :
      DEFPROCsetupfiler(dir$,filename$,type$)
      InitialDir$=dir$+CHR$0
      FileFilter$=type$+CHR$0+CHR$0
      fs.lStructSize%=DIM(fs{})
      fs.lpstrFilter%=PTR(FileFilter$)
      fs.lpstrInitialDir%=PTR(InitialDir$)
      fs.lpstrFile%=PTR(filename$)
      ENDPROC
      :
      DEFPROCinit
      REM ----- Structure for the load and save dialog boxes -----
      DIMfs{lStructSize%,hwndOwner%,hInstance%,lpstrFilter%,lpstrCustomFilter%,nMaxCustFilter%,nFilterIndex%, \
      \      lpstrFile%,nMaxFile%,lpstrFileTitle%,nMaxFileTitle%,lpstrInitialDir%,lpstrTitle%,flags%, \
      \      nFileOffset{l&,h&},nFileExtension{l&,h&},lpstrDefExt%,lCustData%,lpfnHook%,lpTemplateName%}
      DIMfp{t&(260)}
      InitialDir$=@dir$+CHR$0
      FileFilter$="Text files"+CHR$0+"*.txt"+CHR$0+CHR$0
      rp$=CHR$195+CHR$170+"!Lfoebmm!L/!Epxo!3121!"
      fs.lStructSize%=DIM(fs{})
      fs.hwndOwner%=@hwnd%
      fs.lpstrFilter%=PTR(FileFilter$)
      fs.lpstrFile%=fp{}
      fs.nMaxFile%=DIM(fp{})-1
      fs.lpstrInitialDir%=PTR(InitialDir$)
      fs.flags%=6
      ENDPROC
Hated Moron

Re: Pre-setting a file name

Post by Hated Moron »

KenDown wrote: Wed 13 Dec 2023, 11:45

Code: Select all

      PROCsetupfiler(@dir$+CHR$0,"NewFile.txt"+CHR$0,"Text files"+CHR$0+"*.txt"+CHR$0+CHR$0)
      SYS"GetSaveFileName",fs{}TOR%
      ...
      DEFPROCsetupfiler(dir$,filename$,type$)
      ...
      fs.lpstrFile%=PTR(filename$)
      ENDPROC
A real nasty I've just spotted: you are setting fs.lpstrFile% to point to the local variable filename$ and then exiting from the procedure using ENDPROC, whereupon the local variable ceases to exist! So by the time you call SYS "GetSaveFileName" fs.lpstrFile% could be pointing at anything (or nothing). The code is (or appears to be) working purely by luck!

It's vitally important that any strings that you pass (in memory) to the API function still exist when that function is called, and aren't local or temporary variables that have since been discarded. A simple fix would be to move the API call into the subroutine:

Code: Select all

      R% = FNselectfile(@dir$+CHR$0,"NewFile.txt"+CHR$0,"Text files"+CHR$0+"*.txt"+CHR$0+CHR$0)
      ...
      DEF FNselectfile(dir$,filename$,type$)
      LOCAL R%
      ...
      fs.lpstrFile%=PTR(filename$)
      SYS "GetSaveFileName", fs{} TO R%
      = R%
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

Re: Pre-setting a file name

Post by KenDown »

Thank you so much. That is a bit of information of which I was completely ignorant. I will, of course, adopt your solution.

Many many thanks.
KenDown
Posts: 327
Joined: Wed 04 Apr 2018, 06:36

Re: Pre-setting a file name

Post by KenDown »

It didn't work: $$fp{} returned a null string.

Code: Select all

      DEFPROCsetupfiler(dir$,filename$,type$)
      InitialDir$=dir$+CHR$0
      FileFilter$=type$+CHR$0+CHR$0
      fs.lStructSize%=DIM(fs{})
      fs.lpstrFilter%=PTR(FileFilter$)
      fs.lpstrFile%=fp{}
      fs.lpstrInitialDir%=PTR(InitialDir$)
      fs.lpstrFile%=PTR(filename$)
      ENDPROC
After much brain-wracking, I finally realised my mistake: fs.lpstrFile% is set to two different values, only one of which can be correct! So this is the corrected version, which does actually work:

Code: Select all

      DEFFNsetupfiler(dir$,filename$,type$):LOCALR%
      InitialDir$=dir$+CHR$0
      FileFilter$=type$+CHR$0+CHR$0
      fs.lStructSize%=DIM(fs{})
      fs.lpstrFilter%=PTR(FileFilter$)
      fs.lpstrFile%=fp{}
      fs.nMaxFile%=DIM(fp{})-1
      fs.lpstrInitialDir%=PTR(InitialDir$)
      $fp{}=filename$+CHR$0
      SYS"GetOpenFileName",fs{}TOR%
      =R%
Now on exit $$fp{} will contain the filename.

The only annoying thing left is that without adding an extra parameter as a flag, the filer open window will always contain the word "OPEN" even when you are saving!