Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Select multiple files in VFP

Status
Not open for further replies.

Gerrit Broekhuis

Programmer
Aug 16, 2004
316
NL
Hi,

I’m looking for a (dll based) form or control for selecting multiple files, for example to zip them one by one into a zipfile.

I’ve been using Common Dialog (COMDLG32) so far, but this is giving an error when I select more than approx. 50 files. I don’t know how to make this reliable when selecting more files.

So I’m wondering what others use to select multiple (or a lot of) files for further action. I need a control that allows changing directories, drives, etc..

Regards,

Gerrit

PS: I need something that doesn’t change the selected filenames to lowercase.

 
You can do this with the native VFP listbox control. You would use ADIR() to get the filenames into an array (set the nFlag parameter to 1 to retain the original case setting), and then use the array to populate the listbox. Set the listbox's MultiSelect to .T. to enable multiple selections.

That said, I don't know how well it would support selecting a large number of files (more than 50?),and it wouldn't allow you to navigate between directories. To do that, you could use a list box with the RowSourceType set to 7, which would approximately mimic a standard File Open dialogue, but that's really a hangover from Foxpro 2.x and looks terrible under VFP.

In any case, expecting the user to select 50 files by holding down Ctr or Shift while clicking with the mouse doesn't sound like a good interface. Have you considered using a grid with checkboxes, so that the user ticks the files they want?

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Even not using VFP I usually only zip folders, the simplest way to pick one thing that contains all I want to zip. Zipping a bunch of files always poses the risk for someone to unzip a bulkload of files somewhere instead of unzipping them in a folder. That said it's annoying to me, on the other side, that Windows default unzip option is to create a folder of the zip name and unzip into that.

Anyway, that's just an aside, I'm not saying this is the only way to do it.

If you select too many files the OLE error you get is telling to increase MaxFileSize. Tha maximum for it is 0x7fff and that will be sufficient for a lot more than 50 files. A real world example I have is about 400 files using about 8k bytes, so 32k can go up to something in the magnitude of 1000-1500 files.

Code:
* Taken from [URL unfurl="true"]https://microsoft.public.fox.programmer.exchange.narkive.com/CZNSkocv/sample-code-using-common-dialog-to-select-multiple-files[/URL]
* and adjusted

#Define OFN_ALLOWMULTISELECT 0x200
* Allows multiple file selections; use only with Open.
* OFN_EXPLORER must also be set.
#Define OFN_EXPLORER 0x80000
* Uses Explorer-style dialog boxes. Is automatically set, but must
* specifically be set if OFN_ALLOWMULTISELECT is used.
#Define OFN_LONGNAMES 0x200000
* Explorer-style dialog boxes ignore this flag and always display long
* file names.

lnFlags = OFN_EXPLORER+OFN_ALLOWMULTISELECT+OFN_LONGNAMES
Local Array laFiles[1]
CommonDialogFileOpen(lnFlags,@laFiles)

Clear
For Each lcFile In laFiles
   ? lcFile
Next

Procedure CommonDialogFileOpen(lnFlags As Integer, taFiles)
   Local loForm As oForm, lcStrFiles As String
   loForm = Createobject("MultiSelectForm")
   loForm.commonDialog.Flags = lnFlags
   loForm.commonDialog.MaxFileSize = 0x7fff
   loForm.commonDialog.ShowOpen
   lcStrFiles = loForm.commonDialog.FileName
   Alines(taFiles,Chrtran(lcStrFiles,Chr(0),','),1,',')
Endproc

Define Class multiselectForm As Form
   Add Object commonDialog As OleControl With OleClass="MSComDlg.CommonDialog"
Enddefine

The first array element of laFiles will always be the directory from which the files were selected, followed by filenames in further array elements.

If that's still not enough for you I can only recommend limiting this feature to only accept a directory to archive and then use ADIR (that can get file names with capitalization as it is on disk).

Chriss
 
Hi Chriss,

Your code runs fine as prg. So far so good (what a relief...).

However I have to call the common dialog control from a form's "File Select" button. If I put the code there, it's not working.

I copied the procedure to my start.prg file, where I store more procedures.
I added the line to the form's init:
Code:
Add Object commonDialog As OleControl With OleClass="MSComDlg.CommonDialog"
However I cannot get this working.

Where should I put certain elements of your sample code to get it running from my main form's button?

Regard, Gerrit
 
Well, the way this uses the OleClass="MSComDlg.CommonDialog" is with a form, an empty form.

So you don't add that object to your form, you keep both the PROCEDURE CommonDialogFileOpen and the DEFINE CLASS as is in your start.prg and just call CommonDialogFileOpen as the code does, in your form's button.
You start a dialog, that's its own new form, not your form.

You said you used the common dialog yourself, well, you could of course continue to do it your way, all you need to take over from my code sample is the setting of MaxFileSize and the usage of the flags. And since you say you already can select multiple files, all that hinders you to select more is not setting MaxFileSize to a higher value, that's the main point in all of this.

Chriss
 
Hi Chris,

I've got it working now with my form.

I guess you have more knowledge than me regarding this CommonDialog form, and I still have a few issues.

a. How do I open the form for a specific (default) directory? I tried this according to my original code, but this gives error 1426: "OLE error code 0x80020006: Unknown name."

Code:
loForm.commonDialog.cInitialDirectory = cDir      && [C:\...\My Documents]

b. Can I specify specific file types (for example only pdf or jpg). In my version of CommonDialog I have a selection option for various extensions or for all. This does not work with your sample code.

Code:
loForm.commonDialog.AddFilter([PDF-files (*.pdf)],[*.pdf])

c. If I click CANCEL in the CommonDialog form I get error 1426: "OLE error code 0x80020006: Unknown name." This is caused by the following line:

Code:
lcStrFiles = loForm.commonDialog.FileName

I solved this by adding

Code:
IF LEN(ALLTRIM(loForm.commonDialog.FileName)) > 0

I wonder where I can find information about all valid CommonDialog options. I checked the reference in the sample code, but I couldn’t find the “part2” that is mentioned there.

Regards, Gerrit
 
Hi all,

I found a way to offer filter options to the commonDialog:

Code:
loForm.commonDialog.Filter = "All files (*.*)|*.*|PDF documents (*.pdf)|*.pdf|JPG images (*.jpg)|*.jpg|PNG images (*.png)|*.png|E-mails (*.msg)|*.msg"

I cannot get this filter working with multiple extensions, like "Images (*.jpg, *.png)|*.jpg,*.png". If I set a filter this way, no files are shown.

At least I'm coming closer to what I need.

Regards, Gerrit
 
Hi all,

I tried this CommonDialog on a Windows 7 PC, but I get error 1426 on this line:

Code:
loForm = Createobject("MultiSelectForm")

This is the error: "OLE error code 0x80040112: Class is not licensed" (translated from Dutch).

I do have an alternative (older) CommonDialog that is working form Windows 7 (and not for Windows 10) so I can check the OS version and use the appropriate code.
A better solution would be to use the same CommonDialog for all Windows versions.

I have no idea if this is possible. Any comments?

Regards, Gerrit
 
What did you install on that Windows 7? Only you exe, did you install the runtimes.

You do get the license to redistribute several ole controls, Common Dialogs are among them, but this license doesn't go to clients automatically, if you just distribute the EXE.
The way the code I posted acts is using the MSComDlg.CommonDialog on a form, that's a condition you also find for the winsock socket control, it only work when put on a form, not when used standalone. Therefore the define of a form with an added olecontrol object.

If you still use your own usage of common controls you might need to change that for exactly these license issues.

Chriss
 
Oh, my mistke, the error you get points out you DO use the MultiSelectForm that uses the common dialog on a VFP form.

But looking at HOME()+"\redist.txt" I see merge modules listed that will install the license to use the control.
MSCOMCT2.MSM
MSCOMCTL.MSM
MSCOMM32.MSM

It is in one or all of these merge modules. If you don't use an installer or use one that can't install merge modules I don't know how to get the license you need to clients, but InstallShield Express comes with VFP and does install merge modules.


Chriss
 
Hi Chris,

The Windows 7 issue is not bothering me, as I have a perfectly working code for that.

That I cannot set the initial directory is a bigger problem. I tried CHDIR and SET DEFAULT TO to set an initial directory before running the CommonDialog form.
Nothing seems to work. I also tried adding the OFN_NOCHANGEDIR flag to lnFlags, but this doesn't work either.

The CommonDialog form seems to "rembember" where it was left the previous time it was called.

How can I set the initial directory?

Regards, Gerrit

EDIT: I just found the solution (Google is my friend):

Code:
loForm.commonDialog.InitDir = (cDir) && cDir is a variable with the default directory to use in the common dialog form
 
Gerrit Broeckhuis said:
I just found the solution (Google is my friend):
Also a breakpoint an intellisense in the command window or the locals window of the debugger are your friends:

intellisense_clb5ad.jpg

Sorry, tek-tips doesn't seem to like screen sized images, it looks a bit blurry.

Chriss
 
Hi Chriss,

Thanks again for all your help. I think it’s working OK now (time and more testing will tell).

Regards, Gerrit
 
Hi Chriss and everyone else,

As I wrote before the common dialog (using the code you presented the 28th of October) works fine with all 64-bit Windows 10 systems I tested with.

However there are still people using Windows 10 32-bit (because they still have to use DOS software).
On these pc's I get OLE error code 0x80040112: Class is not licensed

I have the code calling the common dialog in a prg file, so I use DO CommonDialog.prg from my main form to call this.
This is the exact code I use:

Code:
#Define OFN_ALLOWMULTISELECT 0x200					&& Allows multiple file selections; use only with Open. OFN_EXPLORER must also be set.
#Define OFN_EXPLORER 0x80000						&& Uses Explorer-style dialog boxes. Is automatically set, but must specifically be set if OFN_ALLOWMULTISELECT is used.
#Define OFN_LONGNAMES 0x200000						&& Explorer-style dialog boxes ignore this flag and always display long file names.
#DEFINE OFN_NOCHANGEDIR 0x8						&& Restores the current directory to its original value if the user changed the directory while searching for files.
#DEFINE OFN_HIDEREADONLY 0x4						&& Hides the read-only box. Should be set for Save As

lnFlags = OFN_EXPLORER+OFN_ALLOWMULTISELECT+OFN_LONGNAMES+OFN_NOCHANGEDIR+OFN_HIDEREADONLY  
PUBLIC Array laFiles[1]						        && original was LOCAL
CommonDialogFileOpen(lnFlags,@laFiles)                                  && [b][COLOR=#EF2929]<== OLE error code 0x80040112 on 32-bit Windows[/color][/b] 

PROCEDURE CommonDialogFileOpen(lnFlags As Integer, taFiles)
   Local loForm As oForm, lcStrFiles As String
   loForm = Createobject("MultiSelectForm")
   loForm.commonDialog.Flags = lnFlags
   loForm.commonDialog.MaxFileSize = 0x7fff
   loForm.commonDialog.FileName = ""
   loForm.commonDialog.InitDir = (cDir)					&& Default folder
   loForm.commonDialog.FilterIndex = 0                                  && no idea what this is doing 
   loForm.commonDialog.DialogTitle = "WinVIS.DigiDossier - Select one or more files..."
   loForm.commonDialog.Filter = "All files (*.*)|*.*|PDF documents (*.pdf)|*.pdf|JPG images (*.jpg)|*.jpg|PNG images (*.png)|*.png|E-mail (*.msg)|*.msg"
   loForm.commonDialog.ShowOpen
   IF LEN(ALLTRIM(loForm.commonDialog.FileName)) > 0
	   lcStrFiles = loForm.commonDialog.FileName
	   Alines(taFiles,Chrtran(lcStrFiles,Chr(0),','),1,',')
   ELSE
   	   WAIT WINDOW "No files selected..." timeout(1)
   ENDIF
ENDPROC


DEFINE CLASS multiselectForm As Form
   ADD OBJECT commonDialog As OleControl With OleClass="MSComDlg.CommonDialog"		&& adding .1 makes no difference
ENDDEFINE

The problematic Windows 10 32-bit pc has version 22H2, Build 19045.2251.

It's hard to believe that there is an actual licensing problem on 32-bit Windows and not on 64-bit Windows.
What can cause this OLE error? What can I try?

Regards, Gerrit
 
myself said:
looking at HOME()+"\redist.txt" I see merge modules listed that will install the license to use the control.
MSCOMCT2.MSM
MSCOMCTL.MSM
MSCOMM32.MSM

you have to make an installer for the right one or simply all of these merge modules.
The more known license issue you can have is with winsock, for which you also have redistribution rights with VFP9, but, well, you have to distribute it and copying files is not sufficient, these licenses are installed on clients by installing merge modules.

Chriss
 
Hi Chriss,

I see these files in "C:\Program Files (x86)\Common Files\Merge Modules" on my development pc.
I use InnoSetup to install my application.

It's not clear to me what to do exactly. Do I have to distribute these files using the installer? I have never had to do this before for these files, but of course I can do that.
If I have to "merge modules" I don't have a clue how to install "merge modules" with InnoSetup (and given the complexity of my InnoSetup configuration I don't switch to another installer program).

What should I do?

Regards, Gerrit
 
As far as I remember inno setup doesn't have the facility to install merge modules. But inno setup experts might help.
VFP9 comees with installshield express, that can install those merge modules.

Before you do a setup with installshield make sure you update the merge modules, too. The latest version change came with the SP2 of VFP9, not sure if the hotfixes later also included yet newer merge modules, but we're talking about the merge modules for the common controls/dialogs and not C/C++ or VFP, so that might be unimportant.

You should be able to make a silent MSI setup that installs the merge module(s) and call that from your inno setup, so it remains all in one.

Chriss
 
Hi Chriss,

I understand very well what you say and I'm sure this could work.

However I've never used InstallShield Express and I have no idea how to make a MSI setup.
Of course I will google for suggestions, but this is becoming way too complicated having to use an installer inside an installer...

Regards, Gerrit
 
There's an easy to follow walkthrough about installshield, and you only need some steps about the merge modules.
The section "Selecting Objects and Merge Modules" is for you.

And inno has I think a presetup and postsetup where you can specify a command which enables to start another setup.exe or [tt]msiexec.exe /i "C:\Example.msi"[/tt]

Chriss
 
Besides the possibility to activate the license. I'm not sure it's necessary for common dialogs themselves, just for the OLE helper class "MSComDlg.CommonDialog".

Have you seen the more recent thread about common dialogs? thread184-1819419

Chriss
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top