BBC BASIC for Windows
Programming >> Database and Files >> GetOpenFileName selecting *multiple* files?
http://bb4w.conforums.com/index.cgi?board=database&action=display&num=1266668266

GetOpenFileName selecting *multiple* files?
Post by 81RED on Feb 20th, 2010, 11:17am

Has anyone ever used the Windows GetOpenFileName API call to select and process multiple files? (As in selecting more than one file when presented with the file browser dialogue)

According to the OPENFILENAME structure documented here:
http://msdn.microsoft.com/en-us/library/ms646839%28VS.85%29.aspx

It certainly looks like it should be possible, but given my track record of almost* consistently failing to translate anything on MSDN into functioning BB4W code, I'd really appreciate some help.. embarassed

*Actually managed to create a multiline tooltip last night from the documentation found on MSDN. But to be honest, that was rather trivial compared to the above link which causes me to involuntarily reach for my medication.


Re: GetOpenFileName selecting *multiple* files?
Post by Malcolm on Feb 20th, 2010, 3:03pm

It's only a matter of setting the flag

OFN_ALLOWMULTISELECT

There's an example in my Audio Player.
http://tech.groups.yahoo.com/group/bb4w/files/Sound-Music/
Re: GetOpenFileName selecting *multiple* files?
Post by 81RED on Feb 20th, 2010, 6:04pm

Absolutely fantastic, thank you very much Malcolm! cheesy

How on earth one is supposed to deduce that Ofn.flags% = &80206 by reading that MSDN article, I will ponder some other day....
Re: GetOpenFileName selecting *multiple* files?
Post by Richard Russell on Feb 20th, 2010, 11:16pm

on Feb 20th, 2010, 3:03pm, Guest-Malcolm wrote:
It's only a matter of setting the flag OFN_ALLOWMULTISELECT

Actually there's quite a lot more to it than that, because of the rather complicated way the list of files is returned. You need to take account of two cases: when only one file was selected and when two or more files are selected; the data formats are different!

Normally I'd list the code here, but as I'm still hors de combat (after more than two weeks) I can't easily access my main PC on which the code resides. Sorry.

If you still want it after I'm fully recovered (could be a few more weeks at least) remind me then.

Richard.
Re: GetOpenFileName selecting *multiple* files?
Post by Richard Russell on Feb 20th, 2010, 11:25pm

on Feb 20th, 2010, 6:04pm, Simon Mathiassen wrote:
How on earth one is supposed to deduce that Ofn.flags% = &80206 by reading that MSDN article

One isn't. Now we have Michael Hutton's excellent 'Windows Constants' utility we write this and then get the utility to do the hard work:

Code:
Ofn.flags% = OFN_EXPLORER + OFN_ALLOWMULTISELECT + OFN_HIDEREADONLY 


(OFN_OVERWRITEPROMPT, which is also set in the hex constant you quoted, is meaningless when selecting a file to be read).

Richard.
Re: GetOpenFileName selecting *multiple* files?
Post by Malcolm on Feb 21st, 2010, 12:24am

Quote:
Actually there's quite a lot more to it than that, because of the rather complicated way the list of files is returned. You need to take account of two cases: when only one file was selected and when two or more files are selected; the data formats are different!


True. The sorting of different formats is also in The Audio Player. I had forgotten that was necessary.

The other thing you need to realize is that the last selected file comes first or top of you returned list.

So if you are in the habit of selecting down from the top. the order will be, the bottom file, then the top reading down the selection to the bottom -1.
If you select from the bottom up then the order is top to bottom. There may be a flag that stop this but I never found it.


Re: GetOpenFileName selecting *multiple* files?
Post by admin on Feb 21st, 2010, 09:28am

on Feb 21st, 2010, 12:24am, Guest-Malcolm wrote:
The other thing you need to realize is that the last selected file comes first or top of you returned list.
So if you are in the habit of selecting down from the top. the order will be, the bottom file, then the top reading down the selection to the bottom -1.
If you select from the bottom up then the order is top to bottom. There may be a flag that stop this but I never found it.

In fact I don't think the order of the returned files is guaranteed to have any specific relationship with the order in which they are selected (especially if you use Shift+LeftClick to do the multi-selection, because then they weren't selected in any order!).

If the order matters, I put the returned filenames into an array (the code I wanted to post does that anyway) then I sort the array into alphabetical sequence.

Richard.
Re: GetOpenFileName selecting *multiple* files?
Post by admin on Feb 21st, 2010, 09:58am

on Feb 20th, 2010, 11:16pm, Guest-Richard Russell wrote:
Normally I'd list the code here, but as I'm still hors de combat (after more than two weeks) I can't easily access my main PC

I've managed to extract the code by connecting to my main PC wirelessly (sneaky!). Here it is:

Code:
      fp% = fs.lpstrFile%
      total% = 0
      WHILE ($$fp% <> "")
        o$(total%) = $$fp%
        fp% += LEN$$fp% + 1
        total% += 1
      ENDWHILE
      IF total% > 1 THEN
        total% -= 1
        FOR I% = 1 TO total%
          o$(I%) = o$(0) + "\" + o$(I%)
        NEXT
      ELSE
        o$(1) = o$(0)
      ENDIF 

It is assumed that the o$() array has already been dimensioned to hold as many files as may ever be selected. On exit from this code total% holds the number of files selected and o$(1) to o$(total%) are the full path+filenames of the selected files.

Richard.
Re: GetOpenFileName selecting *multiple* files?
Post by 81RED on Feb 21st, 2010, 1:09pm

@Richard: Thank you for that code! Is somewhat more transparent than what I ended up with after taking snippets from Malcolms Audioplayer source, and is something that's definitely worthy of a wiki entry if you ask me. Am doing my best not to think about how long that would have taken me, had you gentlemen not been there to help....

@Malcolm: Your Audioplayer is wonderful! Ultra-lightweight and loads practically instantly compared to several other "bloatware" offerings currently available. Adding a seeking trackbar and mouse scrollwheel volume controls would put it right in the frontline. smiley
Re: GetOpenFileName selecting *multiple* files?
Post by Malcolm on Feb 21st, 2010, 3:06pm


I agree it is much more compact than my code and deserved of a Wiki in due course.

Quote:
Adding a seeking trackbar and mouse scrollwheel volume controls would put it right in the frontline.


I don't understand the seeking trackbar. Is that how far through a track one is? The standard trackbar is kind of large so it would involve designing my own. But I guess that's possible. Thanks for the comments.


Re: GetOpenFileName selecting *multiple* files?
Post by 81RED on Feb 21st, 2010, 3:23pm

on Feb 21st, 2010, 3:06pm, Guest-Malcolm wrote:
I don't understand the seeking trackbar. Is that how far through a track one is?

Sorry Malcolm, I'm not entirely sure what the correct English term is - but yes, its purpose is to quickly go to/seek to a certain point in the track. If you for example want to resume listening to something at the 30-minute mark out of a 1 hour track, you would drag the "trackbar" to the middle.

Hope that makes some sort of sense...
Re: GetOpenFileName selecting *multiple* files?
Post by Malcolm on Feb 21st, 2010, 3:56pm

OK. Yes your terminology was correct.
I'll see if that is something I can do. Note that the randomizing code has a bug I have just noticed so I will be reissuing the program soon. It may have some new features.

Quote:
I've managed to extract the code by connecting to my main PC wirelessly (sneaky!).

Richard, thanks for the code snippet. I am always amazed at the brevity of your code.
Re: GetOpenFileName selecting *multiple* files?
Post by admin on Feb 21st, 2010, 4:39pm

on Feb 21st, 2010, 3:56pm, Guest-Malcolm wrote:
Richard, thanks for the code snippet. I am always amazed at the brevity of your code.

I expect it stems from the reduced capacity of my brain - quite literally as I have a fluid-filled arachnoid cyst where some of my brain should be!

Richard.
Re: GetOpenFileName selecting *multiple* files?
Post by Malcolm on Feb 22nd, 2010, 12:20am

Here is the essence of the code I used in the Audio Player.
I was also extracting the name less path for the title bar. (not shown here)

Code:
      REM Open or select multiple files
      
      OFN_ALLOWMULTISELECT = &200  :REM Thanks to Michael Hutton for ADD WIN CONSTANTS
      OFN_EXPLORER = &80000
      OFN_HIDEREADONLY = &4
      OFN_OVERWRITEPROMPT = &2
      
      REM Define OpenFile Structure for Open Dialog box
      DIM Ofn{lStructSize%, hwndOwner%, hInstance%, lpstrFilter%, \
      \      lpstrCustomFilter%, nMaxCustFilter%, nFilterIndex%, \
      \      lpstrFile%, nMaxFile%, lpstrFileTitle%, \
      \      nMaxFileTitle%, lpstrInitialDir%, lpstrTitle%, \
      \      flags%, nFileOffset{l&,h&}, nFileExtension{l&,h&}, \
      \      lpstrDefExt%, lCustData%, lpfnHook%, lpTemplateName%}
      DIM FileName% 7999  :REM Room for 256 file titles.
      filter$ = "Media files"+CHR$0+"*.MP3;*.WMA;*.WAV;*.MID"+CHR$0+"All files"+CHR$0+"*.*"+CHR$0+CHR$0
      Ofn.lStructSize% = DIM(Ofn{})
      Ofn.hwndOwner% = @hwnd%
      Ofn.lpstrFilter% = !^filter$
      Ofn.lpstrFile% = FileName%        :REM A pointer to where all the file names are returned.
      Ofn.nMaxFile% = 8000
      Ofn.flags% =   OFN_HIDEREADONLY OR OFN_ALLOWMULTISELECT OR OFN_EXPLORER
      
      DIM Song%(256) :REM Holds offset to start of song(n)'s filename in returned string.
      
      SYS "GetOpenFileName", Ofn{} TO R%  :REM Normal Open Dialog operation
      a$=""
      
      IF $$FileName%="" THEN PRINT "None Selected":END
      
      nFiles%=0
      IF Ofn.nFileExtension.l&  THEN
        nFiles%=1
      ELSE :REM More than one file
        I%=Ofn.nFileOffset.l& : REM First file name starts at FileName%?nFileOffset.l&
        Song%(nFiles%)=I% : REM Format in FileName%  Path null title1 null title2 null title3 null : I% points to first null
        REPEAT
          WHILE FileName%?I% >0  AND  I% < 7999 :REM Look for Zero's that terminate title strings.
            I%+=1
          ENDWHILE
          nFiles%+=1 :I%+=1
          Song%(nFiles%)=I%  :REM Save the position of the title within $$FileName%
          :REM Song (n)'s filename starts at Song%(n) offset from FileName%
        UNTIL FileName%?I%=0 OR nFiles%=256
      ENDIF
      Fn$=$$FileName%
      
      
      REM Test
      PRINT "Number of files :"; nFiles%
      IF nFiles%>1 THEN
        FOR Trk%=0 TO nFiles%-1
          a$=Fn$+"\"+$$(FileName%+Song%(Trk%))
          PRINTa$
        NEXT
      ELSE a$=Fn$
      ENDIF
      
      END
 


The essential difference from Richard's code is that I did not store the strings in an array because they are already stored in the buffer. I had an array to store the start position of the strings of the file titles in the buffer. Then I compiled the complete filename with path as needed.

Obviously if I wanted to use the buffer for some other file operation then this would not be acceptable. I only had a play list to open and each selection overwrote the previous.
But it does consume less memory which might be important. It really wasn't for me as the Audio Player quickly grew too large for the Demo version of BB4W.



Re: GetOpenFileName selecting *multiple* files?
Post by Malcolm on Feb 22nd, 2010, 05:21am

Quote:
Adding a seeking trackbar and mouse scrollwheel volume controls would put it right in the frontline. smiley


Actually that worked out easier than I thought it would.
Take a look in the Temp Folder for a test version and let me know if that's what you had in mind. Suggestions about the implementations welcomed.
Still to test it fully on CD's but it seems to work on MP3 and WMA just fine. Window had to get a little larger.
Re: GetOpenFileName selecting *multiple* files?
Post by admin on Feb 22nd, 2010, 09:31am

on Feb 22nd, 2010, 12:20am, Guest-Malcolm wrote:
The essential difference from Richard's code is that I did not store the strings in an array

I nearly always want to sort the list of filenames, so I need them in an array anyway for the convenience of using SORTLIB.

Quote:
IF Ofn.nFileExtension.l& THEN
nFiles%=1

Are you sure this works reliably? According to my reading of MSDN, if the user selects a single file which doesn't have an extension Ofn.nFileExtension.l% will be zero and your code will assume a multiple-file selection has been made!

http://msdn.microsoft.com/en-us/library/ms646839.aspx

'If lpstrFile points to a string that does not contain any "." character such as "c:\dir1\dir2\readme", this member contains zero'.

Richard.
Re: GetOpenFileName selecting *multiple* files?
Post by Malcolm on Feb 22nd, 2010, 2:11pm

Quote:
Are you sure this works reliably?


Probably not! Of course it would fail to play anything with no extension either.

It is worthy of an additional check for that case though, thanks.

Re: GetOpenFileName selecting *multiple* files?
Post by 81RED on Feb 22nd, 2010, 2:32pm

on Feb 22nd, 2010, 05:21am, Guest-Malcolm wrote:
Take a look in the Temp Folder for a test version and let me know if that's what you had in mind. Suggestions about the implementations welcomed.

Wow, that was quick.
Excellent job. It it was up to me, the trackbar (did we agree on that term?) should be a little bit bigger as it currently requires something equivalent to surgical precision to hit.
Neverthelesss, your audioplayer is now the standard application for playback on my PCs. smiley
Re: GetOpenFileName selecting *multiple* files?
Post by admin on Feb 22nd, 2010, 2:35pm

on Feb 22nd, 2010, 2:11pm, Guest-Malcolm wrote:
Of course it would fail to play anything with no extension either.

That's not obvious to me. I can rename a .MP3 file to have no extension, and it will still play in Windows Media Player (it warns me that it's not a recognised extension, but asks if I want to play it anyway). Often, with media files, the file type is identified by information within the file itself (e.g. a header) rather than the extension.

If it really is the case that your program won't play a file if it doesn't have one of the 'recognised' extensions, why does it let me select an 'All files (*.*)' filter?

Richard.
Re: GetOpenFileName selecting *multiple* files?
Post by Malcolm on Feb 22nd, 2010, 3:51pm

If it finds a codec it will play other types. I just can't predict what file extensions might be used in the furute.

No extension give a "Wrong File Type" error.


Re: GetOpenFileName selecting *multiple* files?
Post by admin on Feb 22nd, 2010, 4:59pm

on Feb 22nd, 2010, 3:51pm, Guest-Malcolm wrote:
No extension give a "Wrong File Type" error.

A possible explanation is that Windows Media Player is probably using Direct Show (or something even more modern!) and your program is using MCI. It may well be that MCI still uses the file extension to identify the type.

later Confirmed it: I can play my renamed MP3 file (with no extension) using the Direct Show code here:

http://bb4w.wikispaces.com/Playing+a+media+file+using+Direct+Show

Fortunately for you, as far as audio is concerned MCI still seems to support all the common formats. For video, it's no longer very satisfactory to use MCI since too many formats only have Direct Show (or later) codecs.

Richard.
Re: GetOpenFileName selecting *multiple* files?
Post by Malcolm on Feb 25th, 2010, 5:45pm

Quote:
In fact I don't think the order of the returned files is guaranteed to have any specific relationship with the order in which they are selected (especially if you use Shift+LeftClick to do the multi-selection, because then they weren't selected in any order!).


Absolutely they are.
That will be the last selected file (or the end of the shift left click selection), then the order in which they appear in the directory listing. If the file directory was sorted on a particular criterion prior to selection that is the order.


Re: GetOpenFileName selecting *multiple* files?
Post by Malcolm on Feb 25th, 2010, 5:54pm

Quote:
Fortunately for you, as far as audio is concerned MCI still seems to support all the common formats.


Unless anyone thinks that MCI is going away anytime soon, the Microsoft developers blog tells how they planned to get rid of MCI in the 64 bit platforms until they realized that CD support could not be done by any of the alternatives they had, so they put MCI back in.
The question then becomes when can you end of life an API.
They seemed to think it can only happen with a change of platform and when there are well accepted alternatives. That typically means 3 to 4 versions of windows after the alternative API is introduced. Or perhaps when CDs are the equivalent of 8-track.

So the next platform change after 64 bit might be some while. I'll certainly be too old to care.

Re: GetOpenFileName selecting *multiple* files?
Post by admin on Feb 25th, 2010, 11:42pm

on Feb 25th, 2010, 5:45pm, Guest-Malcolm wrote:
Absolutely they are.

Link, please! Not that I disbelieve you, but I'd like to see it from the horse's mouth. On a quick search, I didn't manage to find anything in MSDN about the returned file order.

Richard.
Re: GetOpenFileName selecting *multiple* files?
Post by admin on Feb 25th, 2010, 11:50pm

on Feb 25th, 2010, 5:54pm, Guest-Malcolm wrote:
Unless anyone thinks that MCI is going away anytime soon...

MCI can't go away, any more than any other Windows API, but new audio formats can come along which MCI won't necessarily support. Is your audio player happy to play Ogg Vorbis files, for example? These are becoming increasingly popular.

Richard.
Re: GetOpenFileName selecting *multiple* files?
Post by Malcolm on Feb 26th, 2010, 2:36pm

End of Life Issues
http://blogs.msdn.com/larryosterman/archive/2005/05/12/416990.aspx

Google MSDN Blogs MCI gets quite a bit more.

ogg on MCI.
Not from Microsoft but if you load one of several codecs people say it's possible. As with all the formats if there is a codec it will play.
http://gmc.yoyogames.com/lofiversion/index.php/t134021.html