QB64.org Forum

Active Forums => QB64 Discussion => Topic started by: Jon Richfield on June 08, 2020, 02:56:06 am

Title: Opening files
Post by: Jon Richfield on June 08, 2020, 02:56:06 am
Suppose I wish to process a file in a QB64 program. Of course I can read in the file name and path from the keyboard; however, often one wants to click on a file in a directory display and open the file with the program in question.
Can anyone please direct me to instructions for how to do that sort of thing.

Thanks for any suggestions.
Title: Re: Opening files
Post by: codeguy on June 08, 2020, 05:16:59 am
You've got to use COMMAND$

https://www.qb64.org/wiki/COMMAND$ (https://www.qb64.org/wiki/COMMAND$)
Title: Re: Opening files
Post by: Petr on June 08, 2020, 10:21:39 am
Or do you mean a way to display a list of files and directories in QB64, select a file in that list and run some action, all in QB64? This can also be done with QB64.

You can either call a window from Windows via a library declaration to select a file, or you can write the whole thing and use DIRENTRY.H from Steve to list files and directories.

https://www.qb64.org/forum/index.php?topic=321.msg2126#msg2126
Title: Re: Opening files
Post by: Jon Richfield on June 10, 2020, 12:16:12 pm
Thanks Petr and Codeguy. I'll have to go into this to see what best applies to my requirements.
Title: Re: Opening files
Post by: bplus on June 10, 2020, 01:30:29 pm
If you have Windows and don't want to worry about Linux or Mac users (ie doing a cross platform app) there are easier ways.

Code: QB64: [Select]
  1. _TITLE "Tiny Navigator: press f to window and select a file" 'B+ started 2019-08-22
  2. SCREEN _NEWIMAGE(1000, 600, 32)
  3. _SCREENMOVE 100, 50
  4. ' 2019-08-22 orig post at https://www.qb64.org/forum/index.php?topic=1646.msg108682#msg108682
  5. ' 2019-08-23_13-25 try fix (to nav all directories) with one place for tmpFile, theory can't write files in some dir's
  6. ' For some reason Windows won't write to a fully pathed file in my user folder???from a SHELL command
  7. ' Try testing if dir exists "C:\temp" exists and making one if not, yes! and I can write my temp files there
  8. ' and now I can chDir anywhere!!!!
  9. ' 2019-08-23_14-25 Take Steve's Advice to use users tmp directory for temp files
  10. ' 2019-08-23_23+ Have files window working for file selection
  11.  
  12. DIM SHARED selectedFile AS STRING
  13. DIM SHARED tmpDir AS STRING '  establish a permanent spot for temp files
  14. IF ENVIRON$("TEMP") <> "" THEN 'Thanks to Steve McNeill use user temp files directory
  15.     tmpDir = ENVIRON$("TEMP")
  16. ELSEIF ENVIRON$("TMP") <> "" THEN
  17.     tmpDir = ENVIRON$("TMP")
  18. ELSE 'Thanks to Steve McNeill this should be very unlikely
  19.     IF _DIREXISTS("C:\temp") THEN ELSE MKDIR "C:\temp"
  20.     tmpDir = "C:\temp"
  21.  
  22. DIM mySelection&, done$, i, t$
  23.     COLOR _RGB32(180, 180, 255)
  24.     CLS
  25.     t$ = "Current Directory: " + _CWD$
  26.     LOCATE 2, (_WIDTH / 8 - LEN(t$)) / 2: PRINT t$
  27.     REDIM DIRs(0) AS STRING
  28.     loadDIR DIRs()
  29.     REDIM FILs(0) AS STRING
  30.     loadFiles FILs()
  31.     FOR i = 0 TO UBOUND(FILs)
  32.         IF i < 30 THEN LOCATE i + 4, 60: PRINT FILs(i) ELSE EXIT FOR
  33.     NEXT
  34.     mySelection& = getArrayItemNumber&(5, 5, 50, 30, DIRs())
  35.     CLS
  36.     IF selectedFile <> "" THEN
  37.         PRINT "You selected a file: "; selectedFile
  38.         INPUT "Press enter to continue navigator, any + enter to quit... "; done$
  39.         selectedFile = ""
  40.     ELSEIF mySelection& <> -1719 THEN
  41.         CHDIR DIRs(mySelection&)
  42.     ELSE
  43.         PRINT "Nothing selected."
  44.         INPUT "Press enter to continue navigator, any + enter to quit... "; done$
  45.     END IF
  46.     _LIMIT 60
  47. LOOP UNTIL done$ <> ""
  48.  
  49. SUB loadDIR (fa() AS STRING)
  50.     DIM tmpFile AS STRING, Index%, fline$, d$
  51.     tmpFile = tmpDir + "\DIR$INF0.INF" 'aha!, not a fully pathed file to user directory but here is good!
  52.     SHELL _HIDE "DIR /a:d >" + tmpFile 'get directories  but have to do a little pruning
  53.     OPEN tmpFile FOR INPUT AS #1
  54.     Index% = -1
  55.     DO WHILE NOT EOF(1)
  56.         LINE INPUT #1, fline$
  57.         IF INSTR(fline$, "<DIR>") THEN
  58.             d$ = _TRIM$(rightOf$(fline$, "<DIR>"))
  59.             Index% = Index% + 1
  60.             REDIM _PRESERVE fa(Index%)
  61.             fa(Index%) = d$
  62.         END IF
  63.     LOOP
  64.     CLOSE #1
  65.     KILL tmpFile
  66.  
  67. SUB loadFiles (fa() AS STRING)
  68.     DIM tmpFile AS STRING, Index%
  69.     tmpFile = tmpDir + "\FILE$INF0.INF" 'aha!, not a fully pathed file to user directory but here is good!
  70.     SHELL _HIDE "DIR *.* /a:-d /b /o:-gen > " + tmpFile
  71.     OPEN tmpFile$ FOR INPUT AS #1
  72.     Index% = -1
  73.     DO WHILE NOT EOF(1)
  74.         Index% = Index% + 1
  75.         REDIM _PRESERVE fa(Index%) AS STRING
  76.         LINE INPUT #1, fa(Index%)
  77.     LOOP
  78.     CLOSE #1
  79.     KILL tmpFile$
  80.  
  81. FUNCTION rightOf$ (source$, of$)
  82.     IF INSTR(source$, of$) > 0 THEN rightOf$ = MID$(source$, INSTR(source$, of$) + LEN(of$))
  83.  
  84. ' "Escape returns -1719 to allow a Cancel function and signal no slection."
  85. FUNCTION getArrayItemNumber& (locateRow, locateColumn, boxWidth, boxHeight, arr() AS STRING)
  86.     'Notes: locateRow, locateColumn for top right corner of selection box on screen in characters for LOCATE.
  87.     'boxWidth and boxHeight are in character units, again for locate and print at correct places.
  88.     'All displaying is restricted to inside the box, which has PgUP and PgDn as top and bottom lines in the display.
  89.  
  90.     DIM curRow AS INTEGER, curCol AS INTEGER, fg AS _UNSIGNED LONG, bg AS _UNSIGNED LONG
  91.     DIM maxWidth AS INTEGER, maxHeight AS INTEGER, page AS INTEGER, hlite AS INTEGER, mx AS INTEGER, my AS INTEGER
  92.     DIM lastMX AS INTEGER, lastMY AS INTEGER, row AS INTEGER, mb AS INTEGER
  93.     DIM lba AS LONG, uba AS LONG, choice AS LONG, kh AS LONG, index AS LONG
  94.     DIM clrStr AS STRING, b AS STRING, selNum&
  95.  
  96.     'save old settings to restore at end ofsub
  97.     curRow = CSRLIN
  98.     curCol = POS(0)
  99.     fg = _DEFAULTCOLOR
  100.     bg = _BACKGROUNDCOLOR
  101.     _KEYCLEAR
  102.  
  103.     maxWidth = boxWidth '       number of characters in box
  104.     maxHeight = boxHeight - 2 ' number of lines displayed of array at one time = 1 page
  105.     lba = LBOUND(arr)
  106.     uba = UBOUND(arr)
  107.     page = 0
  108.     hlite = 0 '                 line in display ready for selection by spacebar or if no number is started, enter
  109.     clrStr$ = SPACE$(maxWidth) 'clearing a display line
  110.  
  111.     GOSUB update '              show the beginning of the array items for selection
  112.  
  113.     'signal cancel selection process, exit sub with this unlikely index to signal canel
  114.     choice = -1719 'primes 7 and 8, not likely to be a select index of an array
  115.  
  116.     DO 'until get a selection or demand exit
  117.  
  118.         'handle the key stuff
  119.         kh& = _KEYHIT
  120.         IF kh& THEN
  121.             IF kh& > 0 AND kh& < 255 THEN
  122.                 IF INSTR("0123456789", CHR$(kh&)) > 0 THEN b$ = b$ + CHR$(kh&): GOSUB update
  123.                 IF CHR$(kh&) = "f" THEN
  124.                     REDIM FILs(0) AS STRING
  125.                     loadFiles FILs()
  126.                     selNum& = getArrayItemNumber&(5, 60, 60, 30, FILs())
  127.                     COLOR _RGB32(180, 180, 255)
  128.                     CLS 'need to signal out of file selection
  129.                     IF selNum& >= LBOUND(FILs) AND selNum& <= UBOUND(FILs) THEN selectedFile = FILs(selNum&)
  130.                     EXIT DO
  131.                     'back to directory select
  132.                 END IF
  133.  
  134.                 IF CHR$(kh&) = "c" THEN b$ = "": GOSUB update
  135.                 IF kh& = 13 THEN 'enter pressed check if number is being entered?
  136.                     IF LEN(b$) THEN
  137.                         IF VAL(b$) >= lba AND VAL(b$) <= uba THEN 'we have number started
  138.                             choice = VAL(b$): EXIT DO
  139.                         ELSE 'clear b$ to show some response to enter
  140.                             b$ = "": GOSUB update 'clear the value that doesn't work
  141.                         END IF
  142.                     ELSE
  143.                         choice = hlite + page * maxHeight + lba 'must mean to select the highlighted item
  144.                     END IF
  145.                 END IF
  146.                 IF kh& = 27 THEN EXIT DO 'escape clause offered to Cancel selection process
  147.                 IF kh& = 32 THEN choice = hlite + page * maxHeight + lba 'best way to choose highlighted selection
  148.                 IF kh& = 8 THEN 'backspace to edit number
  149.                     IF LEN(b$) THEN b$ = LEFT$(b$, LEN(b$) - 1): GOSUB update
  150.                 END IF
  151.             ELSE
  152.                 SELECT CASE kh& 'choosing sections of array to display and highlighted item
  153.                     CASE 20736 'pg dn
  154.                         IF (page + 1) * maxHeight + lba <= uba THEN page = page + 1: GOSUB update
  155.                     CASE 18688 'pg up
  156.                         IF (page - 1) * maxHeight + lba >= lba THEN page = page - 1: GOSUB update
  157.                     CASE 18432 'up
  158.                         IF hlite - 1 < 0 THEN
  159.                             IF page > 0 THEN
  160.                                 page = page - 1: hlite = maxHeight - 1: GOSUB update
  161.                             END IF
  162.                         ELSE
  163.                             hlite = hlite - 1: GOSUB update
  164.                         END IF
  165.                     CASE 20480 'down
  166.                         IF (hlite + 1) + page * maxHeight + lba <= uba THEN 'ok to move up
  167.                             IF hlite + 1 > maxHeight - 1 THEN
  168.                                 page = page + 1: hlite = 0: GOSUB update
  169.                             ELSE
  170.                                 hlite = hlite + 1: GOSUB update
  171.                             END IF
  172.                         END IF
  173.                     CASE 18176 'home
  174.                         page = 0: hlite = 0: GOSUB update
  175.                     CASE 20224 ' end
  176.                         page = INT((uba - lba) / maxHeight): hlite = maxHeight - 1: GOSUB update
  177.                 END SELECT
  178.             END IF
  179.         END IF
  180.  
  181.         'handle the mouse stuff
  182.         WHILE _MOUSEINPUT
  183.             IF _MOUSEWHEEL = -1 THEN 'up?
  184.                 IF hlite - 1 < 0 THEN
  185.                     IF page > 0 THEN
  186.                         page = page - 1: hlite = maxHeight - 1: GOSUB update
  187.                     END IF
  188.                 ELSE
  189.                     hlite = hlite - 1: GOSUB update
  190.                 END IF
  191.             ELSEIF _MOUSEWHEEL = 1 THEN 'down?
  192.                 IF (hlite + 1) + page * maxHeight + lba <= uba THEN 'ok to move up
  193.                     IF hlite + 1 > maxHeight - 1 THEN
  194.                         page = page + 1: hlite = 0: GOSUB update
  195.                     ELSE
  196.                         hlite = hlite + 1: GOSUB update
  197.                     END IF
  198.                 END IF
  199.             END IF
  200.         WEND
  201.         mx = INT((_MOUSEX - locateColumn * 8) / 8) + 2: my = INT((_MOUSEY - locateRow * 16) / 16) + 2
  202.         IF _MOUSEBUTTON(1) THEN 'click contols or select array item
  203.             'clear mouse clicks
  204.             mb = _MOUSEBUTTON(1)
  205.             IF mb THEN 'clear it
  206.                 WHILE mb 'OK!
  207.                     IF _MOUSEINPUT THEN mb = _MOUSEBUTTON(1)
  208.                     _LIMIT 100
  209.                 WEND
  210.             END IF
  211.  
  212.             IF mx >= 1 AND mx <= maxWidth AND my >= 1 AND my <= maxHeight THEN
  213.                 choice = my + page * maxHeight + lba - 1 'select item clicked
  214.             ELSEIF mx >= 1 AND mx <= maxWidth AND my = 0 THEN 'page up or exit
  215.                 IF my = 0 AND (mx <= maxWidth AND mx >= maxWidth - 2) THEN 'exit sign
  216.                     EXIT DO 'escape plan for mouse click top right corner of display box
  217.                 ELSE 'PgUp bar clicked
  218.                     IF (page - 1) * maxHeight + lba >= lba THEN page = page - 1: GOSUB update
  219.                 END IF
  220.             ELSEIF mx >= 1 AND mx <= maxWidth AND my = maxHeight + 1 THEN 'page down bar clicked
  221.                 IF (page + 1) * maxHeight + lba <= uba THEN page = page + 1: GOSUB update
  222.             END IF
  223.         ELSE '   mouse over highlighting, only if mouse has moved!
  224.             IF mx >= 1 AND mx <= maxWidth AND my >= 1 AND my <= maxHeight THEN
  225.                 IF mx <> lastMX OR my <> lastMY THEN
  226.                     IF my - 1 <> hlite AND (my - 1 + page * maxHeight + lba <= uba) THEN
  227.                         hlite = my - 1
  228.                         lastMX = mx: lastMY = my
  229.                         GOSUB update
  230.                     END IF
  231.                 END IF
  232.             END IF
  233.         END IF
  234.         _LIMIT 200
  235.     LOOP UNTIL choice >= lba AND choice <= uba
  236.     getArrayItemNumber& = choice
  237.     COLOR fg, bg
  238.     'clear key presses
  239.     _KEYCLEAR
  240.     LOCATE curRow, curCol
  241.     'clear mouse clicks
  242.     mb = _MOUSEBUTTON(1)
  243.     IF mb THEN 'clear it
  244.         WHILE mb 'OK!
  245.             IF _MOUSEINPUT THEN mb = _MOUSEBUTTON(1)
  246.             _LIMIT 100
  247.         WEND
  248.     END IF
  249.     EXIT SUB
  250.  
  251.  
  252.     update: '--------------- display of array sections and controls on screen
  253.  
  254.     'fix hlite if it has dropped below last array item
  255.     WHILE hlite + page * maxHeight + lba > uba
  256.         hlite = hlite - 1
  257.     WEND
  258.  
  259.     'main display of array items at page * maxHeight (lines high)
  260.     FOR row = 0 TO maxHeight - 1
  261.         IF hlite = row THEN COLOR _RGB(200, 200, 255), _RGB32(0, 0, 88) ELSE COLOR _RGB32(0, 0, 88), _RGB(200, 200, 255)
  262.         LOCATE locateRow + row, locateColumn: PRINT clrStr$
  263.         index = row + page * maxHeight + lba
  264.         IF index >= lba AND index <= uba THEN
  265.             LOCATE locateRow + row, locateColumn
  266.             PRINT LEFT$(LTRIM$(STR$(index)) + ") " + arr(index), maxWidth)
  267.         END IF
  268.     NEXT
  269.  
  270.     'make page up and down bars to click, print PgUp / PgDn if available
  271.     COLOR _RGB32(200, 200, 255), _RGB32(0, 100, 50)
  272.     LOCATE locateRow - 1, locateColumn: PRINT SPACE$(maxWidth)
  273.     IF page <> 0 THEN LOCATE locateRow - 1, locateColumn: PRINT LEFT$(" Pg Up" + SPACE$(maxWidth), maxWidth)
  274.     LOCATE locateRow + maxHeight, locateColumn: PRINT SPACE$(maxWidth)
  275.     IF page <> INT(uba / maxHeight) THEN
  276.         LOCATE locateRow + maxHeight, locateColumn: PRINT LEFT$(" Pg Dn" + SPACE$(maxWidth), maxWidth)
  277.     END IF
  278.     'make exit sign for mouse click
  279.     COLOR _RGB32(255, 255, 255), _RGB32(200, 100, 0)
  280.     LOCATE locateRow - 1, locateColumn + maxWidth - 3
  281.     PRINT " X "
  282.  
  283.     'if a number selection has been started show it's build = b$
  284.     IF LEN(b$) THEN
  285.         COLOR _RGB(255, 255, 0), _RGB32(0, 0, 0)
  286.         LOCATE locateRow + maxHeight, locateColumn + maxWidth - LEN(b$) - 1
  287.         PRINT b$;
  288.     END IF
  289.     _DISPLAY
  290.     _LIMIT 100
  291.     RETURN
  292.  
  293.  

The majority of this code is spent with selecting an item from an array, in this case an array of directories or of files when you press f. You could use simpler techniques. LoadDirs and LoadFiles are main routines for getting folders and files from current directory if I recall correctly.
Title: Re: Opening files
Post by: Petr on June 10, 2020, 03:58:00 pm
Nicely done, BPlus.

Be careful with using DIR statement to file. Ashish and me have already found that it returns differently formatted output to a text file, depending on the system locale used. Therefore, it is better to use the  Steve's library DIRENTRY.H
Title: Re: Opening files
Post by: bplus on June 10, 2020, 04:28:30 pm
Nicely done, BPlus.

Be careful with using DIR statement to file. Ashish and me have already found that it returns differently formatted output to a text file, depending on the system locale used. Therefore, it is better to use the  Steve's library DIRENTRY.H

Hi @Petr,

Thanks.

Quote
... have already found that it returns differently formatted output to a text file, depending on the system locale used.

Are you guys getting file creation dates or dates of any type?

I am not getting those details with my SHELL command.
Title: Re: Opening files
Post by: Petr on June 10, 2020, 05:14:29 pm
This was the case for obtaining file names in 8.3 and long format, and the same for directories. It was used by my player, the 8.3 format was used to access paths with unicode characters in the name.
Title: Re: Opening files
Post by: bplus on June 10, 2020, 06:26:28 pm
This was the case for obtaining file names in 8.3 and long format, and the same for directories. It was used by my player, the 8.3 format was used to access paths with unicode characters in the name.

8.3? Do you mean the old DOS 8 letters base name and 3 letters extension?

I am using *.* format ;-))

for folders
Code: QB64: [Select]
  1. SHELL _HIDE "DIR /a:d >" + tmpFile

for files
Code: QB64: [Select]
  1. SHELL _HIDE "DIR *.* /a:-d /b /o:-gen > " + tmpFile

Title: Re: Opening files
Post by: Petr on June 11, 2020, 11:29:07 am
Hi again. Yes, 8.3 format. Why?

In unicode can be file name using DIR returned as:    kulaÅ“ouŸk  jeskynØ pln  kr pn¡k….gif
This is not valid file name. So therefore is need old format for access to file.
Title: Re: Opening files
Post by: bplus on June 11, 2020, 11:41:25 am
Hi again. Yes, 8.3 format. Why?

In unicode can be file name using DIR returned as:    kulaÅ“ouŸk  jeskynØ pln  kr pn¡k….gif
This is not valid file name. So therefore is need old format for access to file.

@Petr  When you say those names aren't valid, even when DIR gives you those names, that they won't work if you say in code to change directory to one of those "invalid" file names, yes?

(assuming your answer would be yes)
Man this makes me glad to be using English, English was not my favorite class is school but live long enough and everything changes, I love reading even some of the classics. Did not like Animal Farm though (just read) but I digress...

If your answer is not yes, what is the problem then? what makes you say they are invalid?
Title: Re: Opening files
Post by: Petr on June 11, 2020, 01:47:07 pm
The problem is this (I guess I could also write it at once ...)

To get names in 8.3 format as well as names in long format I use DIR without formatting parameters. This will give me a full statement. I can display the long name correctly using MAPUNICODE, but I cannot use it for access. That's what the short name is for me.

And the thing I'm talking about all the time is that this statement has otherwise shifted columns in the statement to a file, so it can't be used internationally. Well, not directly. You must first determine the locale in which the computer is running and adjust the reading of data from the file accordingly.

I used this approach in my QB64Player program, which didn't work for Ashish, but for me, and also for people from Germany, Italy, and I think also from the United States. After analyzing why, I found that the Indian version of windows produces a DIR statement shifted by one or two characters, so a program that did not count on it then returned bad names from the file. However, if I reckoned that all file and directory names would be in English only, then I could use listings of only files and only directories and only long names, and I would not know about this problem.
Title: Re: Opening files
Post by: Jon Richfield on June 12, 2020, 02:42:24 am
Thanks bplus,

That will take a bit of reading, but looks as though it is in the right direction.
Title: Re: Opening files
Post by: Jon Richfield on June 12, 2020, 02:45:43 am
If you have Windows and don't want to worry about Linux or Mac users (ie doing a cross platform app) there are easier ways.

.....

The majority of this code is spent with selecting an item from an array, in this case an array of directories or of files when you press f. You could use simpler techniques. LoadDirs and LoadFiles are main routines for getting folders and files from current directory if I recall correctly.

Forgive my blundering; I still haven't mastered the facilities in this forum. 😳 Everything in time 😉
Title: Re: Opening files
Post by: jack on June 12, 2020, 04:44:14 am
@bplus
maybe you could write a file requester using GetOpenFileName (Windows)
here are some examples in C(++) https://docs.microsoft.com/en-us/windows/win32/dlgbox/using-common-dialog-boxes
I translated the open file example on that site to FB, don't how to do it in QB64, would interesting to see
Title: Re: Opening files
Post by: bplus on June 12, 2020, 10:30:35 am
@bplus
maybe you could write a file requester using GetOpenFileName (Windows)
here are some examples in C(++) https://docs.microsoft.com/en-us/windows/win32/dlgbox/using-common-dialog-boxes
I translated the open file example on that site to FB, don't how to do it in QB64, would interesting to see

@jack

Well so far, I only care about the names of files and directories and if they are hidden with a DIR query that's been OK with me so far. With Steve's icing on the cake tip about establishing a SHARED tempFile by finding the Temp Directory, I have been very satisfied with my own Windows access, mainly for navigation in hard drive.

For someone interested in complete set of details about files and directories, your app worked out in FB might be invaluable source to translate to QB64. Maybe offer it up in Discussion Board or Off-Topic for non QB64 language to QB64 translation challenge. (FB so close to QB64 should be OK in Discussion Board since we are going for QB64 code).

You might not know, I avoid getting help from Windows apps (except SHELL of course), I even avoided Windows Message Box access as shown in QB64 Wiki for my own (and far lesser but simpler to use, IMO anyway) MessageBox.

If you did that translation challenge, I wonder if we would hear from Eric again? ;-))
Title: Re: Opening files
Post by: FilipeEstima on June 13, 2020, 11:27:04 pm
You can either call a window from Windows via a library declaration to select a file, or you can write the whole thing and use DIRENTRY.H from Steve to list files and directories.

How do I do that? I don't know how to call the Windows function to let me pick a file with mouse and pass the file path and name to the QB64 program.
Title: Re: Opening files
Post by: bplus on June 13, 2020, 11:57:29 pm
How do I do that? I don't know how to call the Windows function to let me pick a file with mouse and pass the file path and name to the QB64 program.

I think Petr is talking about this, see instructions for DirEntry.h at bottom if don't have in folder with QB64.exe:

Code: QB64: [Select]
  1. DECLARE CUSTOMTYPE LIBRARY "IDE Files\direntry"
  2.     FUNCTION FILE_load_dir& ALIAS load_dir (s AS STRING)
  3.     FUNCTION FILE_has_next_entry& ALIAS has_next_entry ()
  4.     SUB FILE_close_dir ALIAS close_dir ()
  5.     SUB FILE_get_next_entry ALIAS get_next_entry (s AS STRING, flags AS LONG, file_size AS LONG)
  6.     SUB FILE_get_current_dir ALIAS get_current_dir (s AS STRING)
  7.     FUNCTION FILE_current_dir_length& ALIAS current_dir_length ()
  8.  
  9. SCREEN _NEWIMAGE(1024, 720, 32)
  10.  
  11. a$ = SelectFile$("*.*", 100, 100)
  12. PRINT "You selected:"; a$
  13.  
  14.  
  15. FUNCTION SelectFile$ (search$, x AS INTEGER, y AS INTEGER)
  16.     'save some old values
  17.     LoadFile_DC = _DEFAULTCOLOR: LoadFile_BG = _BACKGROUNDCOLOR
  18.     LoadFile_s = _SOURCE: LoadFile_d = _DEST
  19.     f = _FONT: _FONT 16
  20.     'some variables
  21.  
  22.     LoadFile_BoxColor = &HFFAAAAFF
  23.     LoadFile_FolderColor = &HFFFFFF00
  24.     LoadFile_FileColor = &HFFFFFFFF
  25.     IF INSTR(_OS$, "[WINDOWS]") THEN LoadFile_Slash$ = "\" ELSE LoadFile_Slash$ = "/"
  26.     LoadFile_Dir$ = SPACE$(FILE_current_dir_length)
  27.     FILE_get_current_dir LoadFile_Dir$
  28.     LoadFile_Dir$ = LoadFile_Dir$ + LoadFile_Slash$
  29.     'LoadFile_Dir$ = "." + LoadFile_Slash$
  30.     LoadFile_w = 639: LoadFile_h = 479
  31.     REDIM LoadFile_Label(0) AS STRING: LoadFile_Label(0) = "DIR"
  32.     REDIM LoadFile_DirList(-1 TO 9, -1 TO 9999) AS STRING
  33.     LoadFile_last = 1
  34.     FolderDeep = 1
  35.  
  36.     'some error checking
  37.     IF search$ = "" THEN EXIT SUB 'We can't search for nothing!
  38.  
  39.     'Copy background
  40.     PCOPY 0, 1
  41.     'set workscreen
  42.     LoadFile_ws = _NEWIMAGE(640, 480, 32)
  43.  
  44.     'Count our filetypes to display
  45.     LoadFile_TypeCount = 0
  46.     DO
  47.         LoadFile_TypeCount = LoadFile_TypeCount + 1
  48.         LoadFile_l = INSTR(LoadFile_l + 1, search$, ";") ' look for ; to denote more files
  49.         REDIM _PRESERVE LoadFile_Label(LoadFile_TypeCount) AS STRING
  50.         IF LoadFile_l > 0 THEN LoadFile_Label(LoadFile_TypeCount) = MID$(search$, LoadFile_last + 1, LoadFile_l - LoadFile_last - 1) ELSE LoadFile_Label(LoadFile_TypeCount) = MID$(search$, LoadFile_last + 1, LEN(search$) - LoadFile_last)
  51.         LoadFile_last = LoadFile_l + 1
  52.     LOOP UNTIL LoadFile_l = 0
  53.     LoadFile_l = 640 / (LoadFile_TypeCount + 1)
  54.     REDIM LoadFile_start(LoadFile_TypeCount), LoadFile_previous(LoadFile_TypeCount), LoadFile_more(LoadFile_TypeCount), LoadFile_Count(LoadFile_TypeCount)
  55.     FOR i = 0 TO LoadFile_TypeCount: LoadFile_start(i) = 1: NEXT
  56.  
  57.     _SOURCE LoadFile_ws: _DEST LoadFile_ws
  58.     DO
  59.         _LIMIT 30
  60.         FOR i = 0 TO LoadFile_TypeCount
  61.             LoadFile_Count(i) = 0
  62.             FOR j = 0 TO 9999
  63.                 LoadFile_DirList(i, j) = ""
  64.             NEXT
  65.         NEXT
  66.         'Generate our updated directory listings.
  67.  
  68.         IF FILE_load_dir&(LoadFile_Dir$ + CHR$(0)) THEN
  69.             DO
  70.                 LoadFile_length = FILE_has_next_entry 'Get length of next entry
  71.                 IF LoadFile_length > -1 THEN 'If we have a next entry
  72.                     LoadFile_nam$ = SPACE$(LoadFile_length) 'Set the size of our string
  73.                     FILE_get_next_entry LoadFile_nam$, LoadFile_flags, LoadFile_file_size 'Get the file's name, size, and 'flags'
  74.                     'Check if it's a file or a directory
  75.  
  76.                     IF _DIREXISTS(LoadFile_Dir$ + LoadFile_nam$) THEN
  77.                         IF LoadFile_nam$ <> "." THEN
  78.                             LoadFile_Count(0) = LoadFile_Count(0) + 1
  79.                             LoadFile_DirList(0, LoadFile_Count(0)) = LoadFile_nam$
  80.                         END IF
  81.                     ELSE 'We have a file
  82.                         FOR i = 1 TO LoadFile_TypeCount
  83.                             LoadFile_ext$ = RIGHT$(LoadFile_nam$, LEN(LoadFile_Label(i)))
  84.                             IF UCASE$(LoadFile_ext$) = UCASE$(LoadFile_Label(i)) THEN
  85.                                 LoadFile_Count(i) = LoadFile_Count(i) + 1
  86.                                 LoadFile_DirList(i, LoadFile_Count(i)) = LEFT$(LoadFile_nam$, LEN(LoadFile_nam$) - LEN(LoadFile_Label(i)))
  87.                                 EXIT FOR
  88.                             ELSEIF LoadFile_Label(i) = ".*" THEN
  89.                                 LoadFile_Count(i) = LoadFile_Count(i) + 1
  90.                                 LoadFile_DirList(i, LoadFile_Count(i)) = LoadFile_nam$
  91.                             END IF
  92.                         NEXT
  93.                     END IF
  94.                 END IF
  95.             LOOP UNTIL LoadFile_length = -1
  96.             FILE_close_dir
  97.         END IF
  98.  
  99.         updatelist:
  100.  
  101.  
  102.         CLS , &HFF005050 'Draw a nice display box
  103.         COLOR , 0
  104.         LINE (0, 0)-(LoadFile_w, LoadFile_h + 5 - 2 * 16), LoadFile_BoxColor, B
  105.         LINE (1, 1)-(LoadFile_w - 1, LoadFile_h + 6 - 2 * 16), LoadFile_BoxColor, B
  106.         LINE (0, 0)-(LoadFile_w, LoadFile_h), LoadFile_BoxColor, B
  107.         LINE (1, 1)-(LoadFile_w - 1, LoadFile_h - 1), LoadFile_BoxColor, B
  108.  
  109.         LINE (0, 16 + 3)-(LoadFile_w, 16 + 3), LoadFile_BoxColor
  110.         LINE (0, 16 + 4)-(LoadFile_w, 16 + 4), LoadFile_BoxColor
  111.         FOR i = 0 TO LoadFile_TypeCount
  112.             _PRINTSTRING (i * LoadFile_l + (LoadFile_l - 8 * LEN(LoadFile_Label(i))) / 2, 2), LoadFile_Label(i)
  113.             LINE (i * LoadFile_l, 0)-(i * LoadFile_l, LoadFile_h + 5 - 2 * 16), LoadFile_BoxColor
  114.         NEXT
  115.  
  116.         LINE (627, 2)-(637, 18), &HFFFF0000, BF
  117.         LINE (626, 2)-(637, 18), &HFF000000, B
  118.  
  119.         _PRINTSTRING (628, 2), "X"
  120.         IF selection > 0 THEN
  121.             IF LoadFile_Label(row) <> ".*" AND LoadFile_Label(row) <> "DIR" THEN temp$ = LoadFile_DirList(row, selection) + LoadFile_Label(row) ELSE temp$ = LoadFile_DirList(row, selection)
  122.             IF LoadFile_DirList(row, selection) = "" THEN temp$ = ""
  123.             selection = 0
  124.         END IF
  125.         _PRINTSTRING (10, 28 * 16 + 7), LoadFile_Dir$
  126.         _PRINTSTRING (630 - LEN(temp$) * 8, 28 * 16 + 7), temp$
  127.         IF temp$ = "" THEN oldselection = 0
  128.         IF oldselection > 0 THEN LINE (row * LoadFile_l, (oldselection + 1) * 16 + 5)-((row + 1) * LoadFile_l, (oldselection + 2) * 16 + 5), &HAAAAA000, BF
  129.  
  130.         FOR i = 0 TO UBOUND(LoadFile_label)
  131.             IF i = 0 THEN COLOR LoadFile_FolderColor ELSE COLOR LoadFile_FileColor
  132.             counter = 0
  133.             FOR j = LoadFile_start(i) TO LoadFile_start(i) + 24
  134.                 counter = counter + 1
  135.                 IF LoadFile_DirList(i, j) = "" THEN EXIT FOR
  136.                 _PRINTSTRING (i * LoadFile_l + 5, (counter + 1) * 16 + 7), LEFT$(LoadFile_DirList(i, j), LoadFile_l / 8 - 2)
  137.             NEXT
  138.             IF j = LoadFile_start(i) + 25 THEN LoadFile_more(i) = -1 ELSE LoadFile_more(i) = 0
  139.             IF LoadFile_start(i) > 1 THEN LoadFile_previous(i) = -1 ELSE LoadFile_previous(i) = 0
  140.             IF LoadFile_more(i) THEN
  141.                 LINE (i * LoadFile_l + 2, 27 * 16 + 5)-((i + 1) * LoadFile_l - 3, 28 * 16 + 3), &HFFFF0000, BF
  142.                 LINE (i * LoadFile_l + 2, 27 * 16 + 5)-((i + 1) * LoadFile_l - 3, 28 * 16 + 3), BoxColor, B
  143.                 COLOR &HFFFFFF00: _PRINTSTRING (i * LoadFile_l + (LoadFile_l - 8 * 11) / 2, 27 * 16 + 5), "SCROLL DOWN"
  144.                 COLOR LoadFile_FileColor
  145.             END IF
  146.             IF LoadFile_previous(i) THEN
  147.                 LINE (i * LoadFile_l + 2, 16 + 5)-((i + 1) * LoadFile_l - 3, 2 * 16 + 3), &HFFFF0000, BF
  148.                 LINE (i * LoadFile_l + 2, 16 + 5)-((i + 1) * LoadFile_l - 3, 2 * 16 + 3), BoxColor, B
  149.                 COLOR &HFFFFFF00: _PRINTSTRING (i * LoadFile_l + (LoadFile_l - 8 * 9) / 2, 16 + 5), "SCROLL UP"
  150.                 COLOR LoadFile_FileColor
  151.             END IF
  152.         NEXT
  153.  
  154.         _PUTIMAGE (0 + x, 0 + y)-(640 + x, 480 + y), LoadFile_ws, 0
  155.         _DISPLAY
  156.  
  157.         change = 0
  158.         DO
  159.             _LIMIT 30
  160.             LoadFile_LMB = 0 'This sets the left mouse button as unacceptable.
  161.             a = _KEYHIT
  162.             SELECT CASE a
  163.                 CASE 8 'backspace
  164.                     temp$ = LEFT$(temp$, LEN(temp$) - 1)
  165.                     change = -1
  166.                 CASE 13 'enter
  167.                     DO: LOOP UNTIL INKEY$ = "" 'Clear the keyboard buffer so it doesn't affect the main program.
  168.                     temp$ = LoadFile_Dir$ + temp$
  169.                     COLOR LoadFile_DC, LoadFile_BG: _SOURCE LoadFile_s: _DEST LoadFile_d: PCOPY 1, 0: _DISPLAY: SelectFile$ = temp$ 'Restore our old settings
  170.                     _FONT f
  171.                     EXIT SUB 'And leave
  172.                 CASE 27 'If ESC is pressed then...
  173.                     DO: LOOP UNTIL INKEY$ = "" 'Clear the keyboard buffer so it doesn't affect the main program.
  174.                     COLOR LoadFile_DC, LoadFile_BG: _SOURCE LoadFile_s: _DEST LoadFile_d: PCOPY 1, 0: _DISPLAY: SelectFile$ = "" 'Restore our old settings
  175.                     _FONT f
  176.                     EXIT SUB 'And leave
  177.                 CASE 32 TO 126
  178.                     temp$ = temp$ + CHR$(a)
  179.                     change = -1
  180.             END SELECT
  181.             DO
  182.                 IF _MOUSEBUTTON(1) = 0 THEN LoadFile_LMB = -1 'Only by lifting the mouse, will we count it as down
  183.                 'Note: we ignore LoadFile_LMB for the scroll bars, so we can just hold it down and scroll happily forever and ever...
  184.                 'or until we get to the limit of our file list.
  185.                 'We only check LoadFile_LMB when actually trying to select an item from our list.   No more "OOP!  I held it too long and did something I didn't want to do!"
  186.                 'Now we click once to select, click again to accept that selection.
  187.             LOOP WHILE _MOUSEINPUT
  188.             MX = _MOUSEX: MY = _MOUSEY
  189.             IF _MOUSEBUTTON(2) OR (LoadFile_LMB AND MX > 626 + x AND MX < 638 + x AND MY > 1 + y AND MY < 19 + y AND _MOUSEBUTTON(1)) THEN
  190.                 'restore those old values, and just exit.  Right mouse is an escape
  191.                 COLOR LoadFile_DC, LoadFile_BG: _SOURCE LoadFile_s: _DEST LoadFile_d: PCOPY 1, 0: _DISPLAY: SelectFile$ = ""
  192.                 _FONT f
  193.                 EXIT SUB
  194.             END IF
  195.             IF _MOUSEBUTTON(1) THEN 'Without the mouse being down, we don't need to check squat!
  196.                 'Check the 2 roLoadFile_ws for a click in the proper Y position
  197.                 IF MY >= 16 + 5 + y AND MY <= 2 * 16 + 3 + y THEN 'We're on the top row
  198.                     FOR j = 0 TO UBOUND(LoadFile_label)
  199.                         IF LoadFile_previous(j) AND MX >= j * LoadFile_l + 2 + x AND MX <= (j + 1) * LoadFile_l - 3 + x THEN
  200.                             LoadFile_start(j) = LoadFile_start(j) - 1
  201.                             change = -1: selection = 0: click = 0: temp$ = ""
  202.                             EXIT FOR
  203.                         END IF
  204.                     NEXT
  205.                 ELSEIF MY >= 27 * 16 + 5 + y AND MY <= 28 * 16 + 3 + y THEN 'We're on the bottom row
  206.                     FOR j = 0 TO UBOUND(LoadFile_label)
  207.                         IF LoadFile_more(j) AND MX >= j * LoadFile_l + 2 + x AND MX <= (j + 1) * LoadFile_l - 3 + x THEN
  208.                             LoadFile_start(j) = LoadFile_start(j) + 1
  209.                             change = -1: selection = 0: click = 0: temp$ = ""
  210.                             EXIT FOR
  211.                         END IF
  212.                     NEXT
  213.                 ELSEIF MY >= 37 + y AND MY <= 437 + y AND LoadFile_LMB THEN 'It's in a column somewhere.  Did someone click an item?!
  214.                     FOR j = 0 TO UBOUND(LoadFile_label)
  215.                         IF MX >= j * LoadFile_l + 2 + x AND MX <= (j + 1) * LoadFile_l - 3 + x THEN
  216.                             row = j
  217.                             oldselection = INT((MY - y - 37) / 16) + 1
  218.                             selection = LoadFile_start(j) + oldselection - 1
  219.                             change = -1
  220.                             click = -1
  221.                             EXIT FOR
  222.                         END IF
  223.                     NEXT
  224.                 END IF
  225.             END IF
  226.  
  227.             _DISPLAY
  228.         LOOP UNTIL change
  229.         IF click THEN 'we clicked something besides a scroll bar
  230.             IF LoadFile_Label(row) <> ".*" AND LoadFile_Label(row) <> "DIR" THEN temp1$ = LoadFile_DirList(row, selection) + LoadFile_Label(row) ELSE temp1$ = LoadFile_DirList(row, selection)
  231.             IF temp$ = temp1$ THEN
  232.                 'We picked one!
  233.                 SELECT CASE LoadFile_Label(row)
  234.                     CASE "DIR"
  235.                         IF LoadFile_DirList(row, selection) <> ".." THEN
  236.                             LoadFile_Dir$ = LoadFile_Dir$ + LoadFile_DirList(row, selection) + LoadFile_Slash$
  237.                         ELSE
  238.                             DO
  239.                                 LoadFile_Dir$ = LEFT$(LoadFile_Dir$, LEN(LoadFile_Dir$) - 1)
  240.                             LOOP UNTIL RIGHT$(LoadFile_Dir$, 1) = LoadFile_Slash$ OR LEN(LoadFile_Dir$) = 0
  241.                         END IF
  242.                         FOR i = 1 TO UBOUND(Loadfile_start)
  243.                             LoadFile_start(i) = 1
  244.                         NEXT
  245.                         selection = 0: temp$ = "": oldselection = 0
  246.                     CASE ".*": SelectFile$ = LoadFile_Dir$ + temp$: EXIT DO
  247.                     CASE ELSE: SelectFile$ = LoadFile_Dir$ + temp$: EXIT DO
  248.                 END SELECT
  249.             END IF
  250.             IF row > 0 THEN _DELAY .2: GOTO updatelist
  251.         ELSE
  252.             _DELAY .05
  253.             GOTO updatelist
  254.         END IF
  255.     LOOP
  256.     'restore those old values
  257.     COLOR LoadFile_DC, LoadFile_BG: _SOURCE LoadFile_s: _DEST LoadFile_d: PCOPY 1, 0: _DISPLAY
  258.     _FONT f
  259.  
  260. 'If you don't have a copy of direntry.h in your QB64 folder, then copy the following code into a new IDE window.
  261. 'Then remove the remarks.
  262. 'And save it as direntry.h
  263. 'direntry.h is required for this to work properly with the library files.
  264. 'I thought adding the code here would be a way to make certain that it'd be easy to recover the file
  265. 'in case something ever happened and it was accidently deleted off the drive for some reason.
  266.  
  267. '#include <dirent.h>
  268. '#include <sys/stat.h>
  269. '#include <unistd.h>
  270.  
  271. 'const int IS_DIR_FLAG = 1, IS_FILE_FLAG = 2;
  272.  
  273. 'DIR *pdir;
  274. 'struct dirent *next_entry;
  275. 'struct stat statbuf1;
  276.  
  277. 'char current_dir[FILENAME_MAX];
  278. '#ifdef QB64_WINDOWS
  279. '  #define GetCurrentDir _getcwd
  280. '#else
  281. '  #define GetCurrentDir getcwd
  282. '#endif
  283.  
  284. 'int load_dir (char * path) {
  285. '  struct dirent *pent;
  286. '  struct stat statbuf1;
  287. '//Open current directory
  288. 'pdir = opendir(path);
  289. 'if (!pdir) {
  290. 'return 0; //Didn't open
  291. '}
  292. 'return -1;
  293. '}
  294.  
  295. 'int has_next_entry () {
  296. '  next_entry = readdir(pdir);
  297. '  if (next_entry == NULL) return -1;
  298.  
  299. '  stat(next_entry->d_name, &statbuf1);
  300. '  return strlen(next_entry->d_name);
  301. '}
  302.  
  303. 'void get_next_entry (char * nam, int * flags, int * file_size) {
  304. '  strcpy(nam, next_entry->d_name);
  305. '  if (S_ISDIR(statbuf1.st_mode)) {
  306. '    *flags = IS_DIR_FLAG;
  307. '  } else {
  308. '    *flags = IS_FILE_FLAG;
  309. '  }
  310. '  *file_size = statbuf1.st_size;
  311. '  return ;
  312. '}
  313.  
  314. 'void close_dir () {
  315. '  closedir(pdir);
  316. '  pdir = NULL;
  317. '  return ;
  318. '}
  319.  
  320. 'int current_dir_length () {
  321. '  GetCurrentDir(current_dir, sizeof(current_dir));
  322. '  return strlen(current_dir);
  323. '}
  324.  
  325. 'void get_current_dir(char *dir) {
  326. '  memcpy(dir, current_dir, strlen(current_dir));
  327. '  return ;
  328. '}
  329.  
  330.  
Title: Re: Opening files
Post by: Petr on June 14, 2020, 06:52:40 am
As for Windows dialogs, I've talked about this:

(Source code is modified from QB64 wiki, because there is used new function _WIDOWHANDLE, it is nice, BUT this source code works not under 64 bit version QB64, therefore, 32 bit older versions know not this new function name and need extra library for it:

Code: QB64: [Select]
  1. ' Dialog flag constants (use + or OR to use more than 1 flag value)
  2. CONST OFN_ALLOWMULTISELECT = &H200& '  Allows the user to select more than one file, not recommended!
  3. CONST OFN_CREATEPROMPT = &H2000& '     Prompts if a file not found should be created(GetOpenFileName only).
  4. CONST OFN_EXTENSIONDIFFERENT = &H400& 'Allows user to specify file extension other than default extension.
  5. CONST OFN_FILEMUSTEXIST = &H1000& '    Chechs File name exists(GetOpenFileName only).
  6. CONST OFN_HIDEREADONLY = &H4& '        Hides read-only checkbox(GetOpenFileName only)
  7. CONST OFN_NOCHANGEDIR = &H8& '         Restores the current directory to original value if user changed
  8. CONST OFN_NODEREFERENCELINKS = &H100000& 'Returns path and file name of selected shortcut(.LNK) file instead of file referenced.
  9. CONST OFN_NONETWORKBUTTON = &H20000& ' Hides and disables the Network button.
  10. CONST OFN_NOREADONLYRETURN = &H8000& ' Prevents selection of read-only files, or files in read-only subdirectory.
  11. CONST OFN_NOVALIDATE = &H100& '        Allows invalid file name characters.
  12. CONST OFN_OVERWRITEPROMPT = &H2& '     Prompts if file already exists(GetSaveFileName only)
  13. CONST OFN_PATHMUSTEXIST = &H800& '     Checks Path name exists (set with OFN_FILEMUSTEXIST).
  14. CONST OFN_READONLY = &H1& '            Checks read-only checkbox. Returns if checkbox is checked
  15. CONST OFN_SHAREAWARE = &H4000& '       Ignores sharing violations in networking
  16. CONST OFN_SHOWHELP = &H10& '           Shows the help button (useless!)
  17. '--------------------------------------------------------------------------------------------
  18.  
  19. DEFINT A-Z
  20. TYPE FILEDIALOGTYPE
  21.     lStructSize AS LONG '        For the DLL call
  22.     hwndOwner AS LONG '          Dialog will hide behind window when not set correctly
  23.     hInstance AS LONG '          Handle to a module that contains a dialog box template.
  24.     lpstrFilter AS _OFFSET '     Pointer of the string of file filters
  25.     lpstrCustFilter AS _OFFSET
  26.     nMaxCustFilter AS LONG
  27.     nFilterIndex AS LONG '       One based starting filter index to use when dialog is called
  28.     lpstrFile AS _OFFSET '       String full of 0's for the selected file name
  29.     nMaxFile AS LONG '           Maximum length of the string stuffed with 0's minus 1
  30.     lpstrFileTitle AS _OFFSET '  Same as lpstrFile
  31.     nMaxFileTitle AS LONG '      Same as nMaxFile
  32.     lpstrInitialDir AS _OFFSET ' Starting directory
  33.     lpstrTitle AS _OFFSET '      Dialog title
  34.     flags AS LONG '              Dialog flags
  35.     nFileOffset AS INTEGER '     Zero-based offset from path beginning to file name string pointed to by lpstrFile
  36.     nFileExtension AS INTEGER '  Zero-based offset from path beginning to file extension string pointed to by lpstrFile.
  37.     lpstrDefExt AS _OFFSET '     Default/selected file extension
  38.     lCustData AS LONG
  39.     lpfnHook AS LONG
  40.     lpTemplateName AS _OFFSET
  41.  
  42. DECLARE DYNAMIC LIBRARY "comdlg32" ' Library declarations using _OFFSET types
  43.     FUNCTION GetOpenFileNameA& (DIALOGPARAMS AS FILEDIALOGTYPE) ' The Open file dialog
  44.     FUNCTION GetSaveFileNameA& (DIALOGPARAMS AS FILEDIALOGTYPE) ' The Save file dialog
  45.  
  46.     FUNCTION FindWindow& (BYVAL ClassName AS _OFFSET, WindowName$) ' To get hWnd handle
  47.  
  48. _TITLE "FileOpen Common Dialog demo" 'set Title of program
  49. hWnd& = FindWindow(0, "Open and Save Dialog demo" + CHR$(0)) 'get window handle using _TITLE string
  50.  
  51. ' Do the Open File dialog call!
  52. Filter$ = "Batch files (*.bat)|*.BAT|JPEG images (*.jpg)|*.JPG|All files (*.*)|*.*"
  53. Flags& = OFN_FILEMUSTEXIST + OFN_NOCHANGEDIR + OFN_READONLY '    add flag constants here
  54. OFile$ = GetOpenFileName$("YEAH! Common Dialogs in QB64!!!", ".\", Filter$, 1, Flags&, hWnd&)
  55.  
  56. IF OFile$ = "" THEN ' Display Open dialog results
  57.     PRINT "Shame on you! You didn't pick any file..."
  58.     PRINT "You picked this file: "
  59.     PRINT OFile$
  60.     IF (Flags& AND OFN_READONLY) THEN PRINT "Read-only checkbox checked." 'read-only value in return
  61.  
  62. _DELAY 5 ' Do the Save File dialog call!
  63. Filter$ = "Basic files (*.bas)|*.BAS|All files (*.*)|*.*"
  64. Flags& = OFN_OVERWRITEPROMPT + OFN_NOCHANGEDIR '   add flag constants here
  65. SFile$ = GetSaveFileName$("Save will not create a file!!!", ".\", Filter$, 1, Flags&, hWnd&)
  66.  
  67. IF SFile$ = "" THEN ' Display Save dialog results
  68.     PRINT "You didn't save the file..."
  69.     PRINT "You saved this file: "
  70.     PRINT SFile$
  71.  
  72. FUNCTION GetOpenFileName$ (Title$, InitialDir$, Filter$, FilterIndex, Flags&, hWnd&)
  73. '  Title$      - The dialog title.
  74. '  InitialDir$ - If this left blank, it will use the directory where the last opened file is
  75. '  located. Specify ".\" if you want to always use the current directory.
  76. '  Filter$     - File filters separated by pipes (|) in the same format as using VB6 common dialogs.
  77. '  FilterIndex - The initial file filter to use. Will be altered by user during the call.
  78. '  Flags&      - Dialog flags. Will be altered by the user during the call.
  79. '  hWnd&       - Your program's window handle that should be aquired by the FindWindow function.
  80. '
  81. ' Returns: Blank when cancel is clicked otherwise, the file name selected by the user.
  82. ' FilterIndex and Flags& will be changed depending on the user's selections.
  83.  
  84. DIM OpenCall AS FILEDIALOGTYPE ' Needed for dialog call
  85.  
  86. fFilter$ = Filter$
  87. FOR R = 1 TO LEN(fFilter$) ' Replace the pipes with character zero
  88.     IF MID$(fFilter$, R, 1) = "|" THEN MID$(fFilter$, R, 1) = CHR$(0)
  89. fFilter$ = fFilter$ + CHR$(0)
  90.  
  91. lpstrFile$ = STRING$(2048, 0) ' For the returned file name
  92. lpstrDefExt$ = STRING$(10, 0) ' Extension will not be added when this is not specified
  93. OpenCall.lStructSize = LEN(OpenCall)
  94. OpenCall.hwndOwner = hWnd&
  95. OpenCall.lpstrFilter = _OFFSET(fFilter$)
  96. OpenCall.nFilterIndex = FilterIndex
  97. OpenCall.lpstrFile = _OFFSET(lpstrFile$)
  98. OpenCall.nMaxFile = LEN(lpstrFile$) - 1
  99. OpenCall.lpstrFileTitle = OpenCall.lpstrFile
  100. OpenCall.nMaxFileTitle = OpenCall.nMaxFile
  101. OpenCall.lpstrInitialDir = _OFFSET(InitialDir$)
  102. OpenCall.lpstrTitle = _OFFSET(Title$)
  103. OpenCall.lpstrDefExt = _OFFSET(lpstrDefExt$)
  104. OpenCall.flags = Flags&
  105.  
  106. Result = GetOpenFileNameA&(OpenCall) '            Do Open File dialog call!
  107.  
  108. IF Result THEN ' Trim the remaining zeros
  109.     GetOpenFileName$ = LEFT$(lpstrFile$, INSTR(lpstrFile$, CHR$(0)) - 1)
  110.     Flags& = OpenCall.flags
  111.     FilterIndex = OpenCall.nFilterIndex
  112.  
  113.  
  114. FUNCTION GetSaveFileName$ (Title$, InitialDir$, Filter$, FilterIndex, Flags&, hWnd&)
  115. '  Title$      - The dialog title.
  116. '  InitialDir$ - If this left blank, it will use the directory where the last opened file is
  117. '     located. Specify ".\" if you want to always use the current directory.
  118. '  Filter$     - File filters separated by pipes (|) in the same format as VB6 common dialogs.
  119. '  FilterIndex - The initial file filter to use. Will be altered by user during the call.
  120. '  Flags&      - Dialog flags. Will be altered by the user during the call.
  121. '  hWnd&       - Your program's window handle that should be aquired by the FindWindow function.
  122.  
  123. ' Returns: Blank when cancel is clicked otherwise, the file name entered by the user.
  124. ' FilterIndex and Flags& will be changed depending on the user's selections.
  125.  
  126. DIM SaveCall AS FILEDIALOGTYPE ' Needed for dialog call
  127.  
  128. fFilter$ = Filter$
  129. FOR R = 1 TO LEN(fFilter$) ' Replace the pipes with zeros
  130.     IF MID$(fFilter$, R, 1) = "|" THEN MID$(fFilter$, R, 1) = CHR$(0)
  131. fFilter$ = fFilter$ + CHR$(0)
  132.  
  133. lpstrFile$ = STRING$(2048, 0) ' For the returned file name
  134. lpstrDefExt$ = STRING$(10, 0) ' Extension will not be added when this is not specified
  135. SaveCall.lStructSize = LEN(SaveCall)
  136. SaveCall.hwndOwner = hWnd&
  137. SaveCall.lpstrFilter = _OFFSET(fFilter$)
  138. SaveCall.nFilterIndex = FilterIndex
  139. SaveCall.lpstrFile = _OFFSET(lpstrFile$)
  140. SaveCall.nMaxFile = LEN(lpstrFile$) - 1
  141. SaveCall.lpstrFileTitle = SaveCall.lpstrFile
  142. SaveCall.nMaxFileTitle = SaveCall.nMaxFile
  143. SaveCall.lpstrInitialDir = _OFFSET(InitialDir$)
  144. SaveCall.lpstrTitle = _OFFSET(Title$)
  145. SaveCall.lpstrDefExt = _OFFSET(lpstrDefExt$)
  146. SaveCall.flags = Flags&
  147.  
  148. Result& = GetSaveFileNameA&(SaveCall) ' Do dialog call!
  149.  
  150. IF Result& THEN ' Trim the remaining zeros
  151.     GetSaveFileName$ = LEFT$(lpstrFile$, INSTR(lpstrFile$, CHR$(0)) - 1)
  152.     Flags& = SaveCall.flags
  153.     FilterIndex = SaveCall.nFilterIndex
  154.  

You need OLD 32 bit version QB64 IDE for running this. Here is program output:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

OR,

If you need just FOLDER selecting under Windows dialog, use this also modified source code from Wiki. This works under 64 bit QB64, original source code on wiki works under 32 bit QB64
All sources working in 32 bits are here: http://www.qb64.org/wiki/Windows_Libraries

Code: QB64: [Select]
  1.     FUNCTION FindWindow& (BYVAL ClassName AS _OFFSET, WindowName$)
  2.  
  3. _TITLE "Super Window"
  4. hwnd& = _WINDOWHANDLE 'FindWindow(0, "Super Window" + CHR$(0))
  5.  
  6. TYPE BROWSEINFO 'typedef struct _browseinfo 'Microsoft MSDN
  7.     hwndOwner AS _INTEGER64 '              '  HWND
  8.     pidlRoot AS _OFFSET '             '  PCIDLIST_ABSOLUTE
  9.     pszDisplayName AS _OFFSET '      '  LPTSTR
  10.     lpszTitle AS _OFFSET '           '  LPCTSTR
  11.     ulFlags AS _UNSIGNED LONG '  UINT
  12.     lpfn AS _OFFSET '                '  BFFCALLBACK
  13.     lParam AS _OFFSET '              '  LPARAM
  14.     iImage AS LONG '                 '  int
  15. END TYPE 'BROWSEINFO, *PBROWSEINFO, *LPBROWSEINFO;
  16.  
  17.     FUNCTION SHBrowseForFolder%& (x AS BROWSEINFO) 'Microsoft MSDN
  18.     SUB SHGetPathFromIDList (BYVAL lpItem AS _OFFSET, BYVAL szDir AS _OFFSET) 'Microsoft MSDN
  19.  
  20. DIM b AS BROWSEINFO
  21. b.hwndOwner = hwnd
  22. DIM s AS STRING * 1024
  23. b.pszDisplayName = _OFFSET(s$)
  24. a$ = "Choose a folder!!!" + CHR$(0)
  25. b.lpszTitle = _OFFSET(a$)
  26. o = SHBrowseForFolder(b)
  27.     PRINT LEFT$(s$, INSTR(s$, CHR$(0)) - 1)
  28.     DIM s2 AS STRING * 1024
  29.     SHGetPathFromIDList o, _OFFSET(s2$)
  30.     PRINT LEFT$(s2$, INSTR(s2$, CHR$(0)) - 1)
  31.     PRINT "Cancel?"
  32.  

You need choosing drive or  short file name? Use this source:  (2 source codes in one program)

Code: QB64: [Select]
  1. DECLARE LIBRARY 'Directory Information using KERNEL32
  2.     FUNCTION GetShortPathNameA (lpLongPath AS STRING, lpShortPath AS STRING, BYVAL cBufferLen AS LONG)
  3.  
  4. '=== SHOW SHORT PATH NAME
  5. FileOrPath$ = "e:\video to gif converter\videotogifconverter.exe" '<< change to a relevant path or file name on computer
  6. IF _FILEEXISTS(FileOrPath$) THEN PRINT "Path ok"
  7. ShortPathName$ = SPACE$(260)
  8. Result = GetShortPathNameA(FileOrPath$ + CHR$(0), ShortPathName$, LEN(ShortPathName$))
  9. PRINT Result
  10. IF Result THEN PRINT "SHORT PATH NAME: " + ShortPathName$ ELSE PRINT "NOT Found!"
  11.  
  12.  
  13.  
  14. 'disk drivers
  15. CONST REMOVABLE = 2
  16. CONST FIXED = 3
  17. CONST REMOTE = 4
  18. CONST CDROM = 5
  19. CONST RAMDISK = 6
  20.  
  21.     FUNCTION GetDriveTypeA& (nDrive AS STRING)
  22.     FUNCTION GetLogicalDriveStringsA (BYVAL nBuff AS LONG, lpbuff AS STRING)
  23.  
  24. DIM DList AS STRING, DL AS STRING
  25. DIM i AS LONG, typ AS LONG
  26.  
  27. i = GetLogicalDriveStringsA(0, DList) 'zero returns the drive string byte size
  28. DList = SPACE$(i) 'set drive string length. Each drive is followed by CHR$(0)
  29. i = GetLogicalDriveStringsA(i, DList) 'the byte size returns a string that long
  30. PRINT DList
  31.  
  32. FOR n = 65 TO 90
  33.     IF INSTR(DList, CHR$(n)) THEN
  34.         DL = CHR$(n) + ":\" + CHR$(0)
  35.         typ = GetDriveTypeA(DL)
  36.         SELECT CASE typ
  37.             CASE REMOVABLE: PRINT DL + "Removable"
  38.             CASE FIXED: PRINT DL + "Fixed"
  39.             CASE REMOTE: PRINT DL + "Remote"
  40.             CASE CDROM: PRINT DL + "CDROM"
  41.             CASE RAMDISK: PRINT DL + "RAM"
  42.         END SELECT
  43.     END IF
  44.  

(this last source works under both QB64 versions)

Of course, I tried to run the first example under QB64 - 64 bit as well, but I couldn't find where the problem was. I used _INTEGER64 instead of LONG values, without success.

If someone could find and repair problem and run it for QB64 in 64 bit as well, it would be very useful and enjoyable.
Title: Re: Opening files
Post by: Petr on June 14, 2020, 02:20:29 pm
So.

Here is Open/Save Windows dialog, rewrited for 64bit QB64. Jack helped me with this program upgrade:

Code: QB64: [Select]
  1. ' Dialog flag constants (use + or OR to use more than 1 flag value)
  2. CONST OFN_ALLOWMULTISELECT = &H200& '  Allows the user to select more than one file, not recommended!
  3. CONST OFN_CREATEPROMPT = &H2000& '     Prompts if a file not found should be created(GetOpenFileName only).
  4. CONST OFN_EXTENSIONDIFFERENT = &H400& 'Allows user to specify file extension other than default extension.
  5. CONST OFN_FILEMUSTEXIST = &H1000& '    Chechs File name exists(GetOpenFileName only).
  6. CONST OFN_HIDEREADONLY = &H4& '        Hides read-only checkbox(GetOpenFileName only)
  7. CONST OFN_NOCHANGEDIR = &H8& '         Restores the current directory to original value if user changed
  8. CONST OFN_NODEREFERENCELINKS = &H100000& 'Returns path and file name of selected shortcut(.LNK) file instead of file referenced.
  9. CONST OFN_NONETWORKBUTTON = &H20000& ' Hides and disables the Network button.
  10. CONST OFN_NOREADONLYRETURN = &H8000& ' Prevents selection of read-only files, or files in read-only subdirectory.
  11. CONST OFN_NOVALIDATE = &H100& '        Allows invalid file name characters.
  12. CONST OFN_OVERWRITEPROMPT = &H2& '     Prompts if file already exists(GetSaveFileName only)
  13. CONST OFN_PATHMUSTEXIST = &H800& '     Checks Path name exists (set with OFN_FILEMUSTEXIST).
  14. CONST OFN_READONLY = &H1& '            Checks read-only checkbox. Returns if checkbox is checked
  15. CONST OFN_SHAREAWARE = &H4000& '       Ignores sharing violations in networking
  16. CONST OFN_SHOWHELP = &H10& '           Shows the help button (useless!)
  17. '--------------------------------------------------------------------------------------------
  18.  
  19. DEFINT A-Z
  20.  
  21. TYPE FILEDIALOGTYPE
  22.     lStructSize AS LONG '           For the DLL call
  23.     hwndOwner AS _OFFSET '          Dialog will hide behind window when not set correctly
  24.     hInstance AS _OFFSET '          Handle to a module that contains a dialog box template.
  25.     lpstrFilter AS _OFFSET '        Pointer of the string of file filters
  26.     lpstrCustFilter AS LONG
  27.     nMaxCustFilter AS _INTEGER64
  28.     nFilterIndex AS _INTEGER64 '    One based starting filter index to use when dialog is called
  29.     lpstrFile AS _OFFSET '          String full of 0's for the selected file name
  30.     nMaxFile AS _INTEGER64 '        Maximum length of the string stuffed with 0's minus 1
  31.     lpstrFileTitle AS _OFFSET '     Same as lpstrFile
  32.     nMaxFileTitle AS _OFFSET '      Same as nMaxFile
  33.     lpstrInitialDir AS _OFFSET '    Starting directory
  34.     lpstrTitle AS _OFFSET '         Dialog title
  35.     flags AS _INTEGER64 '           Dialog flags
  36.     nFileOffset AS _INTEGER64 '     Zero-based offset from path beginning to file name string pointed to by lpstrFile
  37.     nFileExtension AS _INTEGER64 '  Zero-based offset from path beginning to file extension string pointed to by lpstrFile.
  38.     lpstrDefExt AS _OFFSET '        Default/selected file extension
  39.     lCustData AS _INTEGER64
  40.     lpfnHook AS _INTEGER64
  41.     lpTemplateName AS _INTEGER64
  42.  
  43. DECLARE DYNAMIC LIBRARY "comdlg32" ' Library declarations using _OFFSET types
  44.     FUNCTION GetOpenFileNameA&& (DIALOGPARAMS AS FILEDIALOGTYPE) ' The Open file dialog
  45.     FUNCTION GetSaveFileNameA&& (DIALOGPARAMS AS FILEDIALOGTYPE) ' The Save file dialog
  46.  
  47.     FUNCTION FindWindow~&& (BYVAL ClassName AS _OFFSET, WindowName$) ' To get hWnd handle
  48.  
  49. _TITLE "FOCdemo" 'set Title of program
  50. hWnd = _WINDOWHANDLE 'FindWindow(0, "Open and Save Dialog demo" + CHR$(0)) 'get window handle using _TITLE string
  51.  
  52. 'hWnd~&& = FindWindow(0, "FOCdemo" + CHR$(0)) 'get window handle using _TITLE string
  53.  
  54. PRINT hWnd
  55. ' Do the Open File dialog call!
  56. Filter$ = "Batch files (*.bat)|*.BAT|JPEG images (*.jpg)|*.JPG|All files (*.*)|*.*"
  57. Flags& = OFN_FILEMUSTEXIST + OFN_NOCHANGEDIR + OFN_READONLY '    add flag constants here
  58. OFile$ = GetOpenFileName$("YEAH! Common Dialogs in QB64!!!", ".\", Filter$, 1, Flags&, hWnd&&)
  59.  
  60. IF OFile$ = "" THEN ' Display Open dialog results
  61.     PRINT "Shame on you! You didn't pick any file..."
  62.     PRINT "You picked this file: "
  63.     PRINT OFile$
  64.     IF (Flags& AND OFN_READONLY) THEN PRINT "Read-only checkbox checked." 'read-only value in return
  65.  
  66. _DELAY 5 ' Do the Save File dialog call!
  67. Filter$ = "Basic files (*.bas)|*.BAS|All files (*.*)|*.*"
  68. Flags& = OFN_OVERWRITEPROMPT + OFN_NOCHANGEDIR '   add flag constants here
  69. SFile$ = GetSaveFileName$("Save will not create a file!!!", ".\", Filter$, 1, Flags&, hWnd%&)
  70.  
  71. IF SFile$ = "" THEN ' Display Save dialog results
  72.     PRINT "You didn't save the file..."
  73.     PRINT "You saved this file: "
  74.     PRINT SFile$
  75.  
  76. FUNCTION GetOpenFileName$ (Title$, InitialDir$, Filter$, FilterIndex&, Flags&, hWnd AS _INTEGER64)
  77.     '  Title$      - The dialog title.
  78.     '  InitialDir$ - If this left blank, it will use the directory where the last opened file is
  79.     '  located. Specify ".\" if you want to always use the current directory.
  80.     '  Filter$     - File filters separated by pipes (|) in the same format as using VB6 common dialogs.
  81.     '  FilterIndex - The initial file filter to use. Will be altered by user during the call.
  82.     '  Flags&      - Dialog flags. Will be altered by the user during the call.
  83.     '  hWnd&       - Your program's window handle that should be aquired by the FindWindow function.
  84.     '
  85.     ' Returns: Blank when cancel is clicked otherwise, the file name selected by the user.
  86.     ' FilterIndex and Flags& will be changed depending on the user's selections.
  87.  
  88.     DIM OpenCall AS FILEDIALOGTYPE ' Needed for dialog call
  89.  
  90.     fFilter$ = Filter$
  91.     FOR R = 1 TO LEN(fFilter$) ' Replace the pipes with character zero
  92.         IF MID$(fFilter$, R, 1) = "|" THEN MID$(fFilter$, R, 1) = CHR$(0)
  93.     NEXT R
  94.     fFilter$ = fFilter$ + CHR$(0)
  95.  
  96.     lpstrFile$ = STRING$(2048, 0) ' For the returned file name
  97.     lpstrDefExt$ = STRING$(10, 0) ' Extension will not be added when this is not specified
  98.     OpenCall.lStructSize = LEN(OpenCall)
  99.     OpenCall.hwndOwner = hWnd&&
  100.     OpenCall.lpstrFilter = _OFFSET(fFilter$)
  101.     OpenCall.nFilterIndex = FilterIndex&
  102.     OpenCall.lpstrFile = _OFFSET(lpstrFile$)
  103.     OpenCall.nMaxFile = LEN(lpstrFile$) - 1
  104.     OpenCall.lpstrFileTitle = OpenCall.lpstrFile
  105.     OpenCall.nMaxFileTitle = OpenCall.nMaxFile
  106.     OpenCall.lpstrInitialDir = _OFFSET(InitialDir$)
  107.     OpenCall.lpstrTitle = _OFFSET(Title$)
  108.     OpenCall.lpstrDefExt = _OFFSET(lpstrDefExt$)
  109.     OpenCall.flags = Flags&
  110.  
  111.     Result = GetOpenFileNameA&&(OpenCall) '            Do Open File dialog call!
  112.  
  113.     IF Result THEN ' Trim the remaining zeros
  114.         GetOpenFileName$ = LEFT$(lpstrFile$, INSTR(lpstrFile$, CHR$(0)) - 1)
  115.         Flags& = OpenCall.flags
  116.         FilterIndex = OpenCall.nFilterIndex
  117.     END IF
  118.  
  119.  
  120. FUNCTION GetSaveFileName$ (Title$, InitialDir$, Filter$, FilterIndex, Flags&, hWnd%&)
  121.     '  Title$      - The dialog title.
  122.     '  InitialDir$ - If this left blank, it will use the directory where the last opened file is
  123.     '     located. Specify ".\" if you want to always use the current directory.
  124.     '  Filter$     - File filters separated by pipes (|) in the same format as VB6 common dialogs.
  125.     '  FilterIndex - The initial file filter to use. Will be altered by user during the call.
  126.     '  Flags&      - Dialog flags. Will be altered by the user during the call.
  127.     '  hWnd&       - Your program's window handle that should be aquired by the FindWindow function.
  128.  
  129.     ' Returns: Blank when cancel is clicked otherwise, the file name entered by the user.
  130.     ' FilterIndex and Flags& will be changed depending on the user's selections.
  131.  
  132.     DIM SaveCall AS FILEDIALOGTYPE ' Needed for dialog call
  133.  
  134.     fFilter$ = Filter$
  135.     FOR R = 1 TO LEN(fFilter$) ' Replace the pipes with zeros
  136.         IF MID$(fFilter$, R, 1) = "|" THEN MID$(fFilter$, R, 1) = CHR$(0)
  137.     NEXT R
  138.     fFilter$ = fFilter$ + CHR$(0)
  139.  
  140.     lpstrFile$ = STRING$(2048, 0) ' For the returned file name
  141.     lpstrDefExt$ = STRING$(10, 0) ' Extension will not be added when this is not specified
  142.     SaveCall.lStructSize = LEN(SaveCall)
  143.     SaveCall.hwndOwner = _OFFSET(hWnd%&)
  144.     SaveCall.lpstrFilter = _OFFSET(fFilter$)
  145.     SaveCall.nFilterIndex = FilterIndex
  146.     SaveCall.lpstrFile = _OFFSET(lpstrFile$)
  147.     SaveCall.nMaxFile = LEN(lpstrFile$) - 1
  148.     SaveCall.lpstrFileTitle = SaveCall.lpstrFile
  149.     SaveCall.nMaxFileTitle = SaveCall.nMaxFile
  150.     SaveCall.lpstrInitialDir = _OFFSET(InitialDir$)
  151.     SaveCall.lpstrTitle = _OFFSET(Title$)
  152.     SaveCall.lpstrDefExt = _OFFSET(lpstrDefExt$)
  153.     SaveCall.flags = Flags&
  154.  
  155.     Result& = GetSaveFileNameA&&(SaveCall) ' Do dialog call!
  156.  
  157.     IF Result& THEN ' Trim the remaining zeros
  158.         GetSaveFileName$ = LEFT$(lpstrFile$, INSTR(lpstrFile$, CHR$(0)) - 1)
  159.         Flags& = SaveCall.flags
  160.         FilterIndex = SaveCall.nFilterIndex
  161.     END IF
  162.  
  163.  
Title: Re: Opening files
Post by: SMcNeill on June 14, 2020, 02:33:27 pm
And this version should now work in both 32 and 64-bit Windows:

Code: QB64: [Select]
  1. ' Dialog flag constants (use + or OR to use more than 1 flag value)
  2. CONST OFN_ALLOWMULTISELECT = &H200& '  Allows the user to select more than one file, not recommended!
  3. CONST OFN_CREATEPROMPT = &H2000& '     Prompts if a file not found should be created(GetOpenFileName only).
  4. CONST OFN_EXTENSIONDIFFERENT = &H400& 'Allows user to specify file extension other than default extension.
  5. CONST OFN_FILEMUSTEXIST = &H1000& '    Chechs File name exists(GetOpenFileName only).
  6. CONST OFN_HIDEREADONLY = &H4& '        Hides read-only checkbox(GetOpenFileName only)
  7. CONST OFN_NOCHANGEDIR = &H8& '         Restores the current directory to original value if user changed
  8. CONST OFN_NODEREFERENCELINKS = &H100000& 'Returns path and file name of selected shortcut(.LNK) file instead of file referenced.
  9. CONST OFN_NONETWORKBUTTON = &H20000& ' Hides and disables the Network button.
  10. CONST OFN_NOREADONLYRETURN = &H8000& ' Prevents selection of read-only files, or files in read-only subdirectory.
  11. CONST OFN_NOVALIDATE = &H100& '        Allows invalid file name characters.
  12. CONST OFN_OVERWRITEPROMPT = &H2& '     Prompts if file already exists(GetSaveFileName only)
  13. CONST OFN_PATHMUSTEXIST = &H800& '     Checks Path name exists (set with OFN_FILEMUSTEXIST).
  14. CONST OFN_READONLY = &H1& '            Checks read-only checkbox. Returns if checkbox is checked
  15. CONST OFN_SHAREAWARE = &H4000& '       Ignores sharing violations in networking
  16. CONST OFN_SHOWHELP = &H10& '           Shows the help button (useless!)
  17. '--------------------------------------------------------------------------------------------
  18.  
  19. DEFINT A-Z
  20.  
  21. TYPE FILEDIALOGTYPE
  22.     $IF 32BIT THEN
  23.     TYPE FILEDIALOGTYPE
  24.     lStructSize AS LONG '        For the DLL call
  25.     hwndOwner AS LONG '          Dialog will hide behind window when not set correctly
  26.     hInstance AS LONG '          Handle to a module that contains a dialog box template.
  27.     lpstrFilter AS _OFFSET '     Pointer of the string of file filters
  28.     lpstrCustFilter AS _OFFSET
  29.     nMaxCustFilter AS LONG
  30.     nFilterIndex AS LONG '       One based starting filter index to use when dialog is called
  31.     lpstrFile AS _OFFSET '       String full of 0's for the selected file name
  32.     nMaxFile AS LONG '           Maximum length of the string stuffed with 0's minus 1
  33.     lpstrFileTitle AS _OFFSET '  Same as lpstrFile
  34.     nMaxFileTitle AS LONG '      Same as nMaxFile
  35.     lpstrInitialDir AS _OFFSET ' Starting directory
  36.     lpstrTitle AS _OFFSET '      Dialog title
  37.     flags AS LONG '              Dialog flags
  38.     nFileOffset AS INTEGER '     Zero-based offset from path beginning to file name string pointed to by lpstrFile
  39.     nFileExtension AS INTEGER '  Zero-based offset from path beginning to file extension string pointed to by lpstrFile.
  40.     lpstrDefExt AS _OFFSET '     Default/selected file extension
  41.     lCustData AS LONG
  42.     lpfnHook AS LONG
  43.     lpTemplateName AS _OFFSET
  44.     $ELSE
  45.         lStructSize AS LONG '           For the DLL call
  46.         hwndOwner AS _OFFSET '          Dialog will hide behind window when not set correctly
  47.         hInstance AS _OFFSET '          Handle to a module that contains a dialog box template.
  48.         lpstrFilter AS _OFFSET '        Pointer of the string of file filters
  49.         lpstrCustFilter AS LONG
  50.         nMaxCustFilter AS _INTEGER64
  51.         nFilterIndex AS _INTEGER64 '    One based starting filter index to use when dialog is called
  52.         lpstrFile AS _OFFSET '          String full of 0's for the selected file name
  53.         nMaxFile AS _INTEGER64 '        Maximum length of the string stuffed with 0's minus 1
  54.         lpstrFileTitle AS _OFFSET '     Same as lpstrFile
  55.         nMaxFileTitle AS _OFFSET '      Same as nMaxFile
  56.         lpstrInitialDir AS _OFFSET '    Starting directory
  57.         lpstrTitle AS _OFFSET '         Dialog title
  58.         flags AS _INTEGER64 '           Dialog flags
  59.         nFileOffset AS _INTEGER64 '     Zero-based offset from path beginning to file name string pointed to by lpstrFile
  60.         nFileExtension AS _INTEGER64 '  Zero-based offset from path beginning to file extension string pointed to by lpstrFile.
  61.         lpstrDefExt AS _OFFSET '        Default/selected file extension
  62.         lCustData AS _INTEGER64
  63.         lpfnHook AS _INTEGER64
  64.         lpTemplateName AS _INTEGER64
  65.     $END IF
  66.  
  67. DECLARE DYNAMIC LIBRARY "comdlg32" ' Library declarations using _OFFSET types
  68.     FUNCTION GetOpenFileNameA&& (DIALOGPARAMS AS FILEDIALOGTYPE) ' The Open file dialog
  69.     FUNCTION GetSaveFileNameA&& (DIALOGPARAMS AS FILEDIALOGTYPE) ' The Save file dialog
  70.  
  71.     FUNCTION FindWindow~&& (BYVAL ClassName AS _OFFSET, WindowName$) ' To get hWnd handle
  72.  
  73. _TITLE "FOCdemo" 'set Title of program
  74. hWnd = _WINDOWHANDLE 'FindWindow(0, "Open and Save Dialog demo" + CHR$(0)) 'get window handle using _TITLE string
  75.  
  76. 'hWnd~&& = FindWindow(0, "FOCdemo" + CHR$(0)) 'get window handle using _TITLE string
  77.  
  78. PRINT hWnd
  79. ' Do the Open File dialog call!
  80. Filter$ = "Batch files (*.bat)|*.BAT|JPEG images (*.jpg)|*.JPG|All files (*.*)|*.*"
  81. Flags& = OFN_FILEMUSTEXIST + OFN_NOCHANGEDIR + OFN_READONLY '    add flag constants here
  82. OFile$ = GetOpenFileName$("YEAH! Common Dialogs in QB64!!!", ".\", Filter$, 1, Flags&, hWnd&&)
  83.  
  84. IF OFile$ = "" THEN ' Display Open dialog results
  85.     PRINT "Shame on you! You didn't pick any file..."
  86.     PRINT "You picked this file: "
  87.     PRINT OFile$
  88.     IF (Flags& AND OFN_READONLY) THEN PRINT "Read-only checkbox checked." 'read-only value in return
  89.  
  90. _DELAY 5 ' Do the Save File dialog call!
  91. Filter$ = "Basic files (*.bas)|*.BAS|All files (*.*)|*.*"
  92. Flags& = OFN_OVERWRITEPROMPT + OFN_NOCHANGEDIR '   add flag constants here
  93. SFile$ = GetSaveFileName$("Save will not create a file!!!", ".\", Filter$, 1, Flags&, hWnd%&)
  94.  
  95. IF SFile$ = "" THEN ' Display Save dialog results
  96.     PRINT "You didn't save the file..."
  97.     PRINT "You saved this file: "
  98.     PRINT SFile$
  99.  
  100. FUNCTION GetOpenFileName$ (Title$, InitialDir$, Filter$, FilterIndex&, Flags&, hWnd AS _INTEGER64)
  101.     '  Title$      - The dialog title.
  102.     '  InitialDir$ - If this left blank, it will use the directory where the last opened file is
  103.     '  located. Specify ".\" if you want to always use the current directory.
  104.     '  Filter$     - File filters separated by pipes (|) in the same format as using VB6 common dialogs.
  105.     '  FilterIndex - The initial file filter to use. Will be altered by user during the call.
  106.     '  Flags&      - Dialog flags. Will be altered by the user during the call.
  107.     '  hWnd&       - Your program's window handle that should be aquired by the FindWindow function.
  108.     '
  109.     ' Returns: Blank when cancel is clicked otherwise, the file name selected by the user.
  110.     ' FilterIndex and Flags& will be changed depending on the user's selections.
  111.  
  112.     DIM OpenCall AS FILEDIALOGTYPE ' Needed for dialog call
  113.  
  114.     fFilter$ = Filter$
  115.     FOR R = 1 TO LEN(fFilter$) ' Replace the pipes with character zero
  116.         IF MID$(fFilter$, R, 1) = "|" THEN MID$(fFilter$, R, 1) = CHR$(0)
  117.     NEXT R
  118.     fFilter$ = fFilter$ + CHR$(0)
  119.  
  120.     lpstrFile$ = STRING$(2048, 0) ' For the returned file name
  121.     lpstrDefExt$ = STRING$(10, 0) ' Extension will not be added when this is not specified
  122.     OpenCall.lStructSize = LEN(OpenCall)
  123.     OpenCall.hwndOwner = hWnd&&
  124.     OpenCall.lpstrFilter = _OFFSET(fFilter$)
  125.     OpenCall.nFilterIndex = FilterIndex&
  126.     OpenCall.lpstrFile = _OFFSET(lpstrFile$)
  127.     OpenCall.nMaxFile = LEN(lpstrFile$) - 1
  128.     OpenCall.lpstrFileTitle = OpenCall.lpstrFile
  129.     OpenCall.nMaxFileTitle = OpenCall.nMaxFile
  130.     OpenCall.lpstrInitialDir = _OFFSET(InitialDir$)
  131.     OpenCall.lpstrTitle = _OFFSET(Title$)
  132.     OpenCall.lpstrDefExt = _OFFSET(lpstrDefExt$)
  133.     OpenCall.flags = Flags&
  134.  
  135.     Result = GetOpenFileNameA&&(OpenCall) '            Do Open File dialog call!
  136.  
  137.     IF Result THEN ' Trim the remaining zeros
  138.         GetOpenFileName$ = LEFT$(lpstrFile$, INSTR(lpstrFile$, CHR$(0)) - 1)
  139.         Flags& = OpenCall.flags
  140.         FilterIndex = OpenCall.nFilterIndex
  141.     END IF
  142.  
  143.  
  144. FUNCTION GetSaveFileName$ (Title$, InitialDir$, Filter$, FilterIndex, Flags&, hWnd%&)
  145.     '  Title$      - The dialog title.
  146.     '  InitialDir$ - If this left blank, it will use the directory where the last opened file is
  147.     '     located. Specify ".\" if you want to always use the current directory.
  148.     '  Filter$     - File filters separated by pipes (|) in the same format as VB6 common dialogs.
  149.     '  FilterIndex - The initial file filter to use. Will be altered by user during the call.
  150.     '  Flags&      - Dialog flags. Will be altered by the user during the call.
  151.     '  hWnd&       - Your program's window handle that should be aquired by the FindWindow function.
  152.  
  153.     ' Returns: Blank when cancel is clicked otherwise, the file name entered by the user.
  154.     ' FilterIndex and Flags& will be changed depending on the user's selections.
  155.  
  156.     DIM SaveCall AS FILEDIALOGTYPE ' Needed for dialog call
  157.  
  158.     fFilter$ = Filter$
  159.     FOR R = 1 TO LEN(fFilter$) ' Replace the pipes with zeros
  160.         IF MID$(fFilter$, R, 1) = "|" THEN MID$(fFilter$, R, 1) = CHR$(0)
  161.     NEXT R
  162.     fFilter$ = fFilter$ + CHR$(0)
  163.  
  164.     lpstrFile$ = STRING$(2048, 0) ' For the returned file name
  165.     lpstrDefExt$ = STRING$(10, 0) ' Extension will not be added when this is not specified
  166.     SaveCall.lStructSize = LEN(SaveCall)
  167.     SaveCall.hwndOwner = _OFFSET(hWnd%&)
  168.     SaveCall.lpstrFilter = _OFFSET(fFilter$)
  169.     SaveCall.nFilterIndex = FilterIndex
  170.     SaveCall.lpstrFile = _OFFSET(lpstrFile$)
  171.     SaveCall.nMaxFile = LEN(lpstrFile$) - 1
  172.     SaveCall.lpstrFileTitle = SaveCall.lpstrFile
  173.     SaveCall.nMaxFileTitle = SaveCall.nMaxFile
  174.     SaveCall.lpstrInitialDir = _OFFSET(InitialDir$)
  175.     SaveCall.lpstrTitle = _OFFSET(Title$)
  176.     SaveCall.lpstrDefExt = _OFFSET(lpstrDefExt$)
  177.     SaveCall.flags = Flags&
  178.  
  179.     Result& = GetSaveFileNameA&&(SaveCall) ' Do dialog call!
  180.  
  181.     IF Result& THEN ' Trim the remaining zeros
  182.         GetSaveFileName$ = LEFT$(lpstrFile$, INSTR(lpstrFile$, CHR$(0)) - 1)
  183.         Flags& = SaveCall.flags
  184.         FilterIndex = SaveCall.nFilterIndex
  185.     END IF
  186.  

(Unless I missed something else you changed besides the type...)
Title: Re: Opening files
Post by: Petr on June 14, 2020, 02:47:24 pm
Steve, here is upgraded your version (not work under 32 bit), this works.

See to source code,  some old 32 bit version can't  _WINDOWHANDLE function and  next repair is in row 178 in your source (OFFSET there is bad)

This is tested and working under 1.4 and 1.1

Code: QB64: [Select]
  1. ' Dialog flag constants (use + or OR to use more than 1 flag value)
  2. CONST OFN_ALLOWMULTISELECT = &H200& '  Allows the user to select more than one file, not recommended!
  3. CONST OFN_CREATEPROMPT = &H2000& '     Prompts if a file not found should be created(GetOpenFileName only).
  4. CONST OFN_EXTENSIONDIFFERENT = &H400& 'Allows user to specify file extension other than default extension.
  5. CONST OFN_FILEMUSTEXIST = &H1000& '    Chechs File name exists(GetOpenFileName only).
  6. CONST OFN_HIDEREADONLY = &H4& '        Hides read-only checkbox(GetOpenFileName only)
  7. CONST OFN_NOCHANGEDIR = &H8& '         Restores the current directory to original value if user changed
  8. CONST OFN_NODEREFERENCELINKS = &H100000& 'Returns path and file name of selected shortcut(.LNK) file instead of file referenced.
  9. CONST OFN_NONETWORKBUTTON = &H20000& ' Hides and disables the Network button.
  10. CONST OFN_NOREADONLYRETURN = &H8000& ' Prevents selection of read-only files, or files in read-only subdirectory.
  11. CONST OFN_NOVALIDATE = &H100& '        Allows invalid file name characters.
  12. CONST OFN_OVERWRITEPROMPT = &H2& '     Prompts if file already exists(GetSaveFileName only)
  13. CONST OFN_PATHMUSTEXIST = &H800& '     Checks Path name exists (set with OFN_FILEMUSTEXIST).
  14. CONST OFN_READONLY = &H1& '            Checks read-only checkbox. Returns if checkbox is checked
  15. CONST OFN_SHAREAWARE = &H4000& '       Ignores sharing violations in networking
  16. CONST OFN_SHOWHELP = &H10& '           Shows the help button (useless!)
  17. '--------------------------------------------------------------------------------------------
  18.  
  19. DEFINT A-Z
  20.  
  21. TYPE FILEDIALOGTYPE
  22.     $IF 32BIT THEN
  23.  
  24.     lStructSize AS LONG '        For the DLL call
  25.     hwndOwner AS LONG '          Dialog will hide behind window when not set correctly
  26.     hInstance AS LONG '          Handle to a module that contains a dialog box template.
  27.     lpstrFilter AS _OFFSET '     Pointer of the string of file filters
  28.     lpstrCustFilter AS _OFFSET
  29.     nMaxCustFilter AS LONG
  30.     nFilterIndex AS LONG '       One based starting filter index to use when dialog is called
  31.     lpstrFile AS _OFFSET '       String full of 0's for the selected file name
  32.     nMaxFile AS LONG '           Maximum length of the string stuffed with 0's minus 1
  33.     lpstrFileTitle AS _OFFSET '  Same as lpstrFile
  34.     nMaxFileTitle AS LONG '      Same as nMaxFile
  35.     lpstrInitialDir AS _OFFSET ' Starting directory
  36.     lpstrTitle AS _OFFSET '      Dialog title
  37.     flags AS LONG '              Dialog flags
  38.     nFileOffset AS INTEGER '     Zero-based offset from path beginning to file name string pointed to by lpstrFile
  39.     nFileExtension AS INTEGER '  Zero-based offset from path beginning to file extension string pointed to by lpstrFile.
  40.     lpstrDefExt AS _OFFSET '     Default/selected file extension
  41.     lCustData AS LONG
  42.     lpfnHook AS LONG
  43.     lpTemplateName AS _OFFSET
  44.     $ELSE
  45.         lStructSize AS LONG '           For the DLL call
  46.         hwndOwner AS _OFFSET '          Dialog will hide behind window when not set correctly
  47.         hInstance AS _OFFSET '          Handle to a module that contains a dialog box template.
  48.         lpstrFilter AS _OFFSET '        Pointer of the string of file filters
  49.         lpstrCustFilter AS LONG
  50.         nMaxCustFilter AS _INTEGER64
  51.         nFilterIndex AS _INTEGER64 '    One based starting filter index to use when dialog is called
  52.         lpstrFile AS _OFFSET '          String full of 0's for the selected file name
  53.         nMaxFile AS _INTEGER64 '        Maximum length of the string stuffed with 0's minus 1
  54.         lpstrFileTitle AS _OFFSET '     Same as lpstrFile
  55.         nMaxFileTitle AS _OFFSET '      Same as nMaxFile
  56.         lpstrInitialDir AS _OFFSET '    Starting directory
  57.         lpstrTitle AS _OFFSET '         Dialog title
  58.         flags AS _INTEGER64 '           Dialog flags
  59.         nFileOffset AS _INTEGER64 '     Zero-based offset from path beginning to file name string pointed to by lpstrFile
  60.         nFileExtension AS _INTEGER64 '  Zero-based offset from path beginning to file extension string pointed to by lpstrFile.
  61.         lpstrDefExt AS _OFFSET '        Default/selected file extension
  62.         lCustData AS _INTEGER64
  63.         lpfnHook AS _INTEGER64
  64.         lpTemplateName AS _INTEGER64
  65.     $END IF
  66.  
  67. DECLARE DYNAMIC LIBRARY "comdlg32" ' Library declarations using _OFFSET types
  68.     FUNCTION GetOpenFileNameA&& (DIALOGPARAMS AS FILEDIALOGTYPE) ' The Open file dialog
  69.     FUNCTION GetSaveFileNameA&& (DIALOGPARAMS AS FILEDIALOGTYPE) ' The Save file dialog
  70.  
  71.     FUNCTION FindWindow~&& (BYVAL ClassName AS _OFFSET, WindowName$) ' To get hWnd handle
  72.  
  73. _TITLE "FOCdemo" 'set Title of program
  74. $IF 64BIT THEN
  75.     hWnd = _WINDOWHANDLE 'FindWindow(0, "Open and Save Dialog demo" + CHR$(0)) 'get window handle using _TITLE string
  76.     hWnd&& = FindWindow(0, "FOCdemo" + CHR$(0)) 'get window handle using _TITLE string
  77. PRINT hWnd
  78. ' Do the Open File dialog call!
  79. Filter$ = "Batch files (*.bat)|*.BAT|JPEG images (*.jpg)|*.JPG|All files (*.*)|*.*"
  80. Flags& = OFN_FILEMUSTEXIST + OFN_NOCHANGEDIR + OFN_READONLY '    add flag constants here
  81. OFile$ = GetOpenFileName$("YEAH! Common Dialogs in QB64!!!", ".\", Filter$, 1, Flags&, hWnd&&)
  82.  
  83. IF OFile$ = "" THEN ' Display Open dialog results
  84.     PRINT "Shame on you! You didn't pick any file..."
  85.     PRINT "You picked this file: "
  86.     PRINT OFile$
  87.     IF (Flags& AND OFN_READONLY) THEN PRINT "Read-only checkbox checked." 'read-only value in return
  88.  
  89. _DELAY 5 ' Do the Save File dialog call!
  90. Filter$ = "Basic files (*.bas)|*.BAS|All files (*.*)|*.*"
  91. Flags& = OFN_OVERWRITEPROMPT + OFN_NOCHANGEDIR '   add flag constants here
  92. SFile$ = GetSaveFileName$("Save will not create a file!!!", ".\", Filter$, 1, Flags&, hWnd&&)
  93.  
  94. IF SFile$ = "" THEN ' Display Save dialog results
  95.     PRINT "You didn't save the file..."
  96.     PRINT "You saved this file: "
  97.     PRINT SFile$
  98.  
  99. FUNCTION GetOpenFileName$ (Title$, InitialDir$, Filter$, FilterIndex&, Flags&, hWnd AS _INTEGER64)
  100.     '  Title$      - The dialog title.
  101.     '  InitialDir$ - If this left blank, it will use the directory where the last opened file is
  102.     '  located. Specify ".\" if you want to always use the current directory.
  103.     '  Filter$     - File filters separated by pipes (|) in the same format as using VB6 common dialogs.
  104.     '  FilterIndex - The initial file filter to use. Will be altered by user during the call.
  105.     '  Flags&      - Dialog flags. Will be altered by the user during the call.
  106.     '  hWnd&       - Your program's window handle that should be aquired by the FindWindow function.
  107.     '
  108.     ' Returns: Blank when cancel is clicked otherwise, the file name selected by the user.
  109.     ' FilterIndex and Flags& will be changed depending on the user's selections.
  110.  
  111.     DIM OpenCall AS FILEDIALOGTYPE ' Needed for dialog call
  112.  
  113.     fFilter$ = Filter$
  114.     FOR R = 1 TO LEN(fFilter$) ' Replace the pipes with character zero
  115.         IF MID$(fFilter$, R, 1) = "|" THEN MID$(fFilter$, R, 1) = CHR$(0)
  116.     NEXT R
  117.     fFilter$ = fFilter$ + CHR$(0)
  118.  
  119.     lpstrFile$ = STRING$(2048, 0) ' For the returned file name
  120.     lpstrDefExt$ = STRING$(10, 0) ' Extension will not be added when this is not specified
  121.     OpenCall.lStructSize = LEN(OpenCall)
  122.     OpenCall.hwndOwner = hWnd&&
  123.     OpenCall.lpstrFilter = _OFFSET(fFilter$)
  124.     OpenCall.nFilterIndex = FilterIndex&
  125.     OpenCall.lpstrFile = _OFFSET(lpstrFile$)
  126.     OpenCall.nMaxFile = LEN(lpstrFile$) - 1
  127.     OpenCall.lpstrFileTitle = OpenCall.lpstrFile
  128.     OpenCall.nMaxFileTitle = OpenCall.nMaxFile
  129.     OpenCall.lpstrInitialDir = _OFFSET(InitialDir$)
  130.     OpenCall.lpstrTitle = _OFFSET(Title$)
  131.     OpenCall.lpstrDefExt = _OFFSET(lpstrDefExt$)
  132.     OpenCall.flags = Flags&
  133.  
  134.     Result = GetOpenFileNameA&&(OpenCall) '            Do Open File dialog call!
  135.  
  136.     IF Result THEN ' Trim the remaining zeros
  137.         GetOpenFileName$ = LEFT$(lpstrFile$, INSTR(lpstrFile$, CHR$(0)) - 1)
  138.         Flags& = OpenCall.flags
  139.         FilterIndex = OpenCall.nFilterIndex
  140.     END IF
  141.  
  142.  
  143. FUNCTION GetSaveFileName$ (Title$, InitialDir$, Filter$, FilterIndex, Flags&, hWnd&&)
  144.     '  Title$      - The dialog title.
  145.     '  InitialDir$ - If this left blank, it will use the directory where the last opened file is
  146.     '     located. Specify ".\" if you want to always use the current directory.
  147.     '  Filter$     - File filters separated by pipes (|) in the same format as VB6 common dialogs.
  148.     '  FilterIndex - The initial file filter to use. Will be altered by user during the call.
  149.     '  Flags&      - Dialog flags. Will be altered by the user during the call.
  150.     '  hWnd&       - Your program's window handle that should be aquired by the FindWindow function.
  151.  
  152.     ' Returns: Blank when cancel is clicked otherwise, the file name entered by the user.
  153.     ' FilterIndex and Flags& will be changed depending on the user's selections.
  154.  
  155.     DIM SaveCall AS FILEDIALOGTYPE ' Needed for dialog call
  156.  
  157.     fFilter$ = Filter$
  158.     FOR R = 1 TO LEN(fFilter$) ' Replace the pipes with zeros
  159.         IF MID$(fFilter$, R, 1) = "|" THEN MID$(fFilter$, R, 1) = CHR$(0)
  160.     NEXT R
  161.     fFilter$ = fFilter$ + CHR$(0)
  162.  
  163.     lpstrFile$ = STRING$(2048, 0) ' For the returned file name
  164.     lpstrDefExt$ = STRING$(10, 0) ' Extension will not be added when this is not specified
  165.     SaveCall.lStructSize = LEN(SaveCall)
  166.     SaveCall.hwndOwner = hWnd&&
  167.     SaveCall.lpstrFilter = _OFFSET(fFilter$)
  168.     SaveCall.nFilterIndex = FilterIndex
  169.     SaveCall.lpstrFile = _OFFSET(lpstrFile$)
  170.     SaveCall.nMaxFile = LEN(lpstrFile$) - 1
  171.     SaveCall.lpstrFileTitle = SaveCall.lpstrFile
  172.     SaveCall.nMaxFileTitle = SaveCall.nMaxFile
  173.     SaveCall.lpstrInitialDir = _OFFSET(InitialDir$)
  174.     SaveCall.lpstrTitle = _OFFSET(Title$)
  175.     SaveCall.lpstrDefExt = _OFFSET(lpstrDefExt$)
  176.     SaveCall.flags = Flags&
  177.  
  178.     Result& = GetSaveFileNameA&&(SaveCall) ' Do dialog call!
  179.  
  180.     IF Result& THEN ' Trim the remaining zeros
  181.         GetSaveFileName$ = LEFT$(lpstrFile$, INSTR(lpstrFile$, CHR$(0)) - 1)
  182.         Flags& = SaveCall.flags
  183.         FilterIndex = SaveCall.nFilterIndex
  184.     END IF
  185.  
Title: Re: Opening files
Post by: SMcNeill on June 14, 2020, 03:54:54 pm
Quote
See to source code,  some old 32 bit version can't  _WINDOWHANDLE function and  next repair is in row 178 in your source (OFFSET there is bad)

Try inserting a small _DELAY in there before  the _WINDOWHANDLE.  It might correct the problem on older versions. _WINDOWHANDLE has been a part of the language for several years now.  (From 2017 onwards)
Title: Re: Opening files
Post by: Petr on June 15, 2020, 01:41:25 pm
I found a pretty big bug that I fixed with this version. In the previous case, the circled part in the 64-bit version was missing in the window. It's already there in this program version! (in both, 32 or 64 bit)

Code: QB64: [Select]
  1. ' Dialog flag constants (use + or OR to use more than 1 flag value)
  2. CONST OFN_ALLOWMULTISELECT = &H200& '  Allows the user to select more than one file, not recommended!
  3. CONST OFN_CREATEPROMPT = &H2000& '     Prompts if a file not found should be created(GetOpenFileName only).
  4. CONST OFN_EXTENSIONDIFFERENT = &H400& 'Allows user to specify file extension other than default extension.
  5. CONST OFN_FILEMUSTEXIST = &H1000& '    Chechs File name exists(GetOpenFileName only).
  6. CONST OFN_HIDEREADONLY = &H4& '        Hides read-only checkbox(GetOpenFileName only)
  7. CONST OFN_NOCHANGEDIR = &H8& '         Restores the current directory to original value if user changed
  8. CONST OFN_NODEREFERENCELINKS = &H100000& 'Returns path and file name of selected shortcut(.LNK) file instead of file referenced.
  9. CONST OFN_NONETWORKBUTTON = &H20000& ' Hides and disables the Network button.
  10. CONST OFN_NOREADONLYRETURN = &H8000& ' Prevents selection of read-only files, or files in read-only subdirectory.
  11. CONST OFN_NOVALIDATE = &H100& '        Allows invalid file name characters.
  12. CONST OFN_OVERWRITEPROMPT = &H2& '     Prompts if file already exists(GetSaveFileName only)
  13. CONST OFN_PATHMUSTEXIST = &H800& '     Checks Path name exists (set with OFN_FILEMUSTEXIST).
  14. CONST OFN_READONLY = &H1& '            Checks read-only checkbox. Returns if checkbox is checked
  15. CONST OFN_SHAREAWARE = &H4000& '       Ignores sharing violations in networking
  16. CONST OFN_SHOWHELP = &H10& '           Shows the help button (useless!)
  17. '--------------------------------------------------------------------------------------------
  18.  
  19. DEFINT A-Z
  20.  
  21. TYPE FILEDIALOGTYPE
  22.     $IF 32BIT THEN
  23.  
  24.     lStructSize AS LONG '        For the DLL call
  25.     hwndOwner AS LONG '          Dialog will hide behind window when not set correctly
  26.     hInstance AS LONG '          Handle to a module that contains a dialog box template.
  27.     lpstrFilter AS _OFFSET '     Pointer of the string of file filters
  28.     lpstrCustFilter AS _OFFSET
  29.     nMaxCustFilter AS LONG
  30.     nFilterIndex AS LONG '       One based starting filter index to use when dialog is called
  31.     lpstrFile AS _OFFSET '       String full of 0's for the selected file name
  32.     nMaxFile AS LONG '           Maximum length of the string stuffed with 0's minus 1
  33.     lpstrFileTitle AS _OFFSET '  Same as lpstrFile
  34.     nMaxFileTitle AS LONG '      Same as nMaxFile
  35.     lpstrInitialDir AS _OFFSET ' Starting directory
  36.     lpstrTitle AS _OFFSET '      Dialog title
  37.     flags AS LONG '              Dialog flags
  38.     nFileOffset AS INTEGER '     Zero-based offset from path beginning to file name string pointed to by lpstrFile
  39.     nFileExtension AS INTEGER '  Zero-based offset from path beginning to file extension string pointed to by lpstrFile.
  40.     lpstrDefExt AS _OFFSET '     Default/selected file extension
  41.     lCustData AS LONG
  42.     lpfnHook AS LONG
  43.     lpTemplateName AS _OFFSET
  44.     $ELSE
  45.         lStructSize AS _OFFSET '           For the DLL call
  46.         hwndOwner AS _OFFSET '          Dialog will hide behind window when not set correctly
  47.         hInstance AS _OFFSET '          Handle to a module that contains a dialog box template.
  48.         lpstrFilter AS _OFFSET '        Pointer of the string of file filters
  49.         lpstrCustFilter AS LONG
  50.         nMaxCustFilter AS LONG
  51.         nFilterIndex AS _INTEGER64 '    One based starting filter index to use when dialog is called
  52.         lpstrFile AS _OFFSET '          String full of 0's for the selected file name
  53.         nMaxFile AS _OFFSET '        Maximum length of the string stuffed with 0's minus 1
  54.         lpstrFileTitle AS _OFFSET '     Same as lpstrFile
  55.         nMaxFileTitle AS _OFFSET '      Same as nMaxFile
  56.         lpstrInitialDir AS _OFFSET '    Starting directory
  57.         lpstrTitle AS _OFFSET '         Dialog title
  58.         flags AS _INTEGER64 '           Dialog flags
  59.         nFileOffset AS _INTEGER64 '     Zero-based offset from path beginning to file name string pointed to by lpstrFile
  60.         nFileExtension AS _INTEGER64 '  Zero-based offset from path beginning to file extension string pointed to by lpstrFile.
  61.         lpstrDefExt AS _OFFSET '        Default/selected file extension
  62.         lCustData AS _INTEGER64
  63.         lpfnHook AS _INTEGER64
  64.         lpTemplateName AS _OFFSET
  65.     $END IF
  66.  
  67. DECLARE DYNAMIC LIBRARY "comdlg32" ' Library declarations using _OFFSET types
  68.     FUNCTION GetOpenFileNameA&& (DIALOGPARAMS AS FILEDIALOGTYPE) ' The Open file dialog
  69.     FUNCTION GetSaveFileNameA&& (DIALOGPARAMS AS FILEDIALOGTYPE) ' The Save file dialog
  70.  
  71.     FUNCTION FindWindow~&& (BYVAL ClassName AS _OFFSET, WindowName$) ' To get hWnd handle
  72.  
  73. _TITLE "FOCdemo" 'set Title of program
  74. $IF 64BIT THEN
  75.     hWnd = _WINDOWHANDLE 'FindWindow(0, "Open and Save Dialog demo" + CHR$(0)) 'get window handle using _TITLE string
  76.     hWnd&& = FindWindow(0, "FOCdemo" + CHR$(0)) 'get window handle using _TITLE string
  77. PRINT hWnd
  78. ' Do the Open File dialog call!
  79. Filter$ = "Batch files (*.bat)|*.BAT|JPEG images (*.jpg)|*.JPG|All files (*.*)|*.*"
  80. Flags& = OFN_FILEMUSTEXIST + OFN_NOCHANGEDIR + OFN_READONLY '    add flag constants here
  81. OFile$ = GetOpenFileName$("YEAH! Common Dialogs in QB64!!!", ".\", Filter$, 1, Flags&, hWnd&&)
  82.  
  83. IF OFile$ = "" THEN ' Display Open dialog results
  84.     PRINT "Shame on you! You didn't pick any file..."
  85.     PRINT "You picked this file: "
  86.     PRINT OFile$
  87.     IF (Flags& AND OFN_READONLY) THEN PRINT "Read-only checkbox checked." 'read-only value in return
  88.  
  89. _DELAY 5 ' Do the Save File dialog call!
  90. Filter$ = "Basic files (*.bas)|*.BAS|All files (*.*)|*.*"
  91. Flags& = OFN_OVERWRITEPROMPT + OFN_NOCHANGEDIR '   add flag constants here
  92. SFile$ = GetSaveFileName$("Save will not create a file!!!", ".\", Filter$, 1, Flags&, hWnd&&)
  93.  
  94. IF SFile$ = "" THEN ' Display Save dialog results
  95.     PRINT "You didn't save the file..."
  96.     PRINT "You saved this file: "
  97.     PRINT SFile$
  98.  
  99. FUNCTION GetOpenFileName$ (Title$, InitialDir$, Filter$, FilterIndex&, Flags&, hWnd AS _INTEGER64)
  100.     '  Title$      - The dialog title.
  101.     '  InitialDir$ - If this left blank, it will use the directory where the last opened file is
  102.     '  located. Specify ".\" if you want to always use the current directory.
  103.     '  Filter$     - File filters separated by pipes (|) in the same format as using VB6 common dialogs.
  104.     '  FilterIndex - The initial file filter to use. Will be altered by user during the call.
  105.     '  Flags&      - Dialog flags. Will be altered by the user during the call.
  106.     '  hWnd&       - Your program's window handle that should be aquired by the FindWindow function.
  107.     '
  108.     ' Returns: Blank when cancel is clicked otherwise, the file name selected by the user.
  109.     ' FilterIndex and Flags& will be changed depending on the user's selections.
  110.  
  111.     DIM OpenCall AS FILEDIALOGTYPE ' Needed for dialog call
  112.  
  113.     fFilter$ = Filter$
  114.     FOR R = 1 TO LEN(fFilter$) ' Replace the pipes with character zero
  115.         IF MID$(fFilter$, R, 1) = "|" THEN MID$(fFilter$, R, 1) = CHR$(0)
  116.     NEXT R
  117.     fFilter$ = fFilter$ + CHR$(0)
  118.  
  119.     lpstrFile$ = STRING$(2048, 0) ' For the returned file name
  120.     lpstrDefExt$ = STRING$(10, 0) ' Extension will not be added when this is not specified
  121.     OpenCall.lStructSize = LEN(OpenCall)
  122.     OpenCall.hwndOwner = hWnd&&
  123.     OpenCall.lpstrFilter = _OFFSET(fFilter$)
  124.     OpenCall.nFilterIndex = FilterIndex&
  125.     OpenCall.lpstrFile = _OFFSET(lpstrFile$)
  126.     OpenCall.nMaxFile = LEN(lpstrFile$) - 1
  127.     OpenCall.lpstrFileTitle = OpenCall.lpstrFile
  128.     OpenCall.nMaxFileTitle = OpenCall.nMaxFile
  129.     OpenCall.lpstrInitialDir = _OFFSET(InitialDir$)
  130.     OpenCall.lpstrTitle = _OFFSET(Title$)
  131.     OpenCall.lpstrDefExt = _OFFSET(lpstrDefExt$)
  132.     OpenCall.flags = Flags&
  133.  
  134.     Result = GetOpenFileNameA&&(OpenCall) '            Do Open File dialog call!
  135.  
  136.     IF Result THEN ' Trim the remaining zeros
  137.         GetOpenFileName$ = LEFT$(lpstrFile$, INSTR(lpstrFile$, CHR$(0)) - 1)
  138.         Flags& = OpenCall.flags
  139.         FilterIndex = OpenCall.nFilterIndex
  140.     END IF
  141.  
  142.  
  143. FUNCTION GetSaveFileName$ (Title$, InitialDir$, Filter$, FilterIndex, Flags&, hWnd&&)
  144.     '  Title$      - The dialog title.
  145.     '  InitialDir$ - If this left blank, it will use the directory where the last opened file is
  146.     '     located. Specify ".\" if you want to always use the current directory.
  147.     '  Filter$     - File filters separated by pipes (|) in the same format as VB6 common dialogs.
  148.     '  FilterIndex - The initial file filter to use. Will be altered by user during the call.
  149.     '  Flags&      - Dialog flags. Will be altered by the user during the call.
  150.     '  hWnd&       - Your program's window handle that should be aquired by the FindWindow function.
  151.  
  152.     ' Returns: Blank when cancel is clicked otherwise, the file name entered by the user.
  153.     ' FilterIndex and Flags& will be changed depending on the user's selections.
  154.  
  155.     DIM SaveCall AS FILEDIALOGTYPE ' Needed for dialog call
  156.  
  157.     fFilter$ = Filter$
  158.     FOR R = 1 TO LEN(fFilter$) ' Replace the pipes with zeros
  159.         IF MID$(fFilter$, R, 1) = "|" THEN MID$(fFilter$, R, 1) = CHR$(0)
  160.     NEXT R
  161.     fFilter$ = fFilter$ + CHR$(0)
  162.  
  163.     lpstrFile$ = STRING$(2048, 0) ' For the returned file name
  164.     lpstrDefExt$ = STRING$(10, 0) ' Extension will not be added when this is not specified
  165.     SaveCall.lStructSize = LEN(SaveCall)
  166.     SaveCall.hwndOwner = hWnd&&
  167.     SaveCall.lpstrFilter = _OFFSET(fFilter$)
  168.     SaveCall.nFilterIndex = FilterIndex
  169.     SaveCall.lpstrFile = _OFFSET(lpstrFile$)
  170.     SaveCall.nMaxFile = LEN(lpstrFile$) - 1
  171.     SaveCall.lpstrFileTitle = SaveCall.lpstrFile
  172.     SaveCall.nMaxFileTitle = SaveCall.nMaxFile
  173.     SaveCall.lpstrInitialDir = _OFFSET(InitialDir$)
  174.     SaveCall.lpstrTitle = _OFFSET(Title$)
  175.     SaveCall.lpstrDefExt = _OFFSET(lpstrDefExt$)
  176.     SaveCall.flags = Flags&
  177.  
  178.     Result& = GetSaveFileNameA&&(SaveCall) ' Do dialog call!
  179.  
  180.     IF Result& THEN ' Trim the remaining zeros
  181.         GetSaveFileName$ = LEFT$(lpstrFile$, INSTR(lpstrFile$, CHR$(0)) - 1)
  182.         Flags& = SaveCall.flags
  183.         FilterIndex = SaveCall.nFilterIndex
  184.     END IF
  185.  

  [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: Opening files
Post by: SpriggsySpriggs on June 15, 2020, 03:20:23 pm
Yeah I noticed that the file filter doesn't work in the 64 bit version. What is the fix for that?
Title: Re: Opening files
Post by: Petr on June 15, 2020, 04:04:15 pm
Data type in field FIELDDIALOGTYPE for 64 bit version was wrong. Now it is repaired.
Title: Re: Opening files
Post by: SpriggsySpriggs on June 16, 2020, 07:44:49 am
Data type in field FIELDDIALOGTYPE for 64 bit version was wrong. Now it is repaired.
When I use the above code in an InForm program the file filter only works in 32 bit. I discovered that the issue must have been the DEFINT A-Z that was causing an issue for this. I removed that and it suddenly worked. Thank you all so much.
Title: Re: Opening files
Post by: bplus on June 16, 2020, 11:35:04 am
When I use the above code in an InForm program the file filter only works in 32 bit. I discovered that the issue must have been the DEFINT A-Z that was causing an issue for this. I removed that and it suddenly worked. Thank you all so much.

Ah the power of habit, so powerful when it saves us time from considering every little thing and leaves us blind when it works against our goals.

Good one to put on your debugging list: "Default Types" along with Typos and notes about INKEY$ and IF logic cautions (a whole sublist special cases for keywords) and what _LOADFILE returns when fails.

Have you started your list?  ;)

Oh,  from last night the problem _DISPLAY and  the cure _AUTODISPLAY