My dialog allows muti-select of files and previews the files selected.
It works - up to a point.
My problem is that the selected file name only seems to be available in the
member 'FileName'. The member 'Files' (which is a TStrings - i.e. a list of
strings) is not set up on DoSelectionChange. The multiple file names do
seem to be packed into 'FileName' in a format that is not too difficult to
decode - i.e. path, file name, file name, file name ...... which I used
initially. However I realised that if you selected too many files (i.e.
more than about 10) then 'FileName' becomes empty - presumably the string
gets too long. At that point I can't preview anything.
Does anyone have any idea how I can access the full list of selected files?
Thanks
David.
I haven't checked the VCL code yet, but it seems likely that the
inherited DoSelectionChange does the job you need to find finished.
You haven't posted any code, but have you tried calling *that* first
in your override, instead of at the end?
By the way, you might want to look at
http://www.mitov.com/Dwnd/dwnd.html for one person's approach to the
single filename case.
--
Timothy H. Buchman
========================================
City Center Theater, New York NY
mail address tbuchmanPLEASE(at sign)REMOVEcitycenter.org
Search .borland message archive on http://www.mers.com/searchsite.html
It doesn't seem to matter if you call the inherited function first, either.
That was my initial hope too.
David
Timothy H. Buchman <tbuchmanPLEASE(at sign)REMOVEcitycenter.org> wrote in
message news:3c57f8d7$1_1@dnews...
TOpenPictureDialog is just an extension of TOpenDialog.. TOpenDialog has a
max buffer size of High(Word) - 16 (aka 65,519, I believe) characters if
ofAllowMultiSelect is specified, otherwise the max size is MAX_PATH (aka
260) characters instead.
Gambit
"dvd8n" <dv...@BigFoot.com> wrote in message news:3c587b41_1@dnews...
David
Remy Lebeau <gamb...@gte.net> wrote in message news:3c587eac_1@dnews...
Upon looking at the VCL source, I see that my advice was useless,
because DoSelectionChange only checks for the end-user's event
handler. The action I was looking for is in ExplorerHook and WndProc.
But it appears (this would be a bug) that FFiles (the TStrings you're
looking at) is only set *after* the user presses "OK", and not in time
for OnSelectionChange.
ShowMessage(String(OpenDialog1->Files->Count)); confirms this. I must
add that I was unable to find where FFileName *is* set for
CDN_SELCHANGE, which it indeed *is.
David, I suppose you've made other arrangements by now, but I've spent
some spare time working on the problem. It's more the fault of the
API than TOpenDialog. It turns out that the FileName property is
rarely retrieved from a member variable; Rather the CDM_GETFILEPATH
message is sent to the Open Dialog, and the returned string is
presented as the value of the property. In fact, the
OPENFILENAME->lpstrFile buffer is not set upon selection change, but
only upon clicking the "Open" button. Furthermore, the
CDM_GETFILEPATH message, as you reported, does not work properly at
selection change time when the file list is long. I think this is
internal to the API, because it does not depend on the buffer size
offered to the message.
I've addressed both problems in the derived component below. A huge
buffer is substituted for the VCL's lpstrFile buffer, and the
CDM_GETFILESPEC (!) is sent upon every selection change. It's
essential that the result not be parsed unless the user wants it,
because it could take a lot of time. This code includes material
learned from BCB's dialogs.pas. I chose to create a new property,
FileList, which has the data you want. Tested in BCB3, Win95.
In the header, Bigopdlg.h:
#define BIGBUF_SIZE (25*1024)
class TBigOpenDialog : public TOpenDialog
{
private:
// OPENFILENAME.lpstrFile instead of VCL's own
char * lpstrbuf;
// Keep filespec for each CDN_SELCHANGE
char * bigbuf;
// List of selected files-new property var
Classes::TStrings * FFileList;
protected:
BOOL __fastcall TBigOpenDialog::TaskModalDialog(
void * DialogFunc, void
*DialogData); // override Dialogs::TOpenDialog method
// Derived Dialog's code, followed by call to user's Event, if any
void __fastcall DoSelectionChange();
// Getter function for new property (read-only)
TStrings * __fastcall GetFileList();
__published:
// New property for huge lists of files
__property Classes::TStrings * FileList = {read=GetFileList};
public:
__fastcall virtual TBigOpenDialog(TComponent * Owner);//
Constructor
__fastcall virtual ~TBigOpenDialog();// Destructor
};
char * ztok(char * string);
In Bigopdlg.cpp:
#include <vcl.h>
#pragma hdrstop
#include "Bigopdlg.h"
#include "dlgs.h"
#include "commctrl.h"
__fastcall TBigOpenDialog::TBigOpenDialog(TComponent * Owner) :
TOpenDialog(Owner)
{
Title="Big Open";
FFileList=new TStringList;
lpstrbuf=new char[BIGBUF_SIZE];
bigbuf=new char[BIGBUF_SIZE];
}
__fastcall TBigOpenDialog::~TBigOpenDialog(void)// Destructor
{
delete FFileList;
delete [] lpstrbuf;
delete [] bigbuf;
}
TStrings * __fastcall TBigOpenDialog::GetFileList(void)
{
char * fn=NULL;
AnsiString fname;
AnsiString path;
int directoryextracted=false;
// Get fresh data, if available. Otherwise, use data
// collected upon the last SelectionChange.
if(Handle)
CommDlg_OpenSave_GetFilePath(
GetParent(Handle), bigbuf, BIGBUF_SIZE);
else
memcpy(bigbuf,lpstrbuf,BIGBUF_SIZE);
// Parsing bigbuf: During SelectionChange events, multiple
// filenames (and the directory) are quoted and separated by
// blanks. After the user closes the dialog, these are
// separated by nulls, with two nulls after the last name
FFileList->Clear();
// Could there be multiple filenames?
if(!Options.Contains(ofAllowMultiSelect))
// No, can only be one path/fname
{
FFileList->Add(String(bigbuf));
return FFileList;
}
// Yes, could be directory plus one or more names
for(fn=ztok(bigbuf);
fn;
fn=ztok(NULL))
{
if(*fn==' ') // Skip blank between quoted filenames
continue;
fname=String(fn);
if(fname.Pos(":")) // Path is first entry
{
if(!directoryextracted)
{
path=fname;
directoryextracted=true;
if(*(fname.AnsiLastChar())!='\\')
path=path+'\\';
}
else
{
fname=ExtractFileName(fname);
fname=path+fname;
}
}
else
fname=path+fname;
FFileList->Add(fname);
}
if(FFileList->Count>1) // If multiple files,
FFileList->Delete(0); // First line is path only
return FFileList;
}
// We need to collect the OpenDialog's filename string
// with each selection change, so that it will be on hand
// if the dialog is closed or destroyed.
void __fastcall TBigOpenDialog::DoSelectionChange(void)
{
// Next line abandoned for GetSpec instead
// CommDlg_OpenSave_GetFilePath(
// GetParent(Handle), bigbuf, BIGBUF_SIZE);
CommDlg_OpenSave_GetSpec(
GetParent(Handle), bigbuf, BIGBUF_SIZE);
Dialogs::TOpenDialog::DoSelectionChange();
}
BOOL __fastcall TBigOpenDialog::TaskModalDialog(
void * DialogFunc, void
*DialogData) // override Dialogs::TOpenDialog method
{
char * oldfilespec;
oldfilespec=((LPOPENFILENAMEA)DialogData)->lpstrFile;
((LPOPENFILENAMEA)DialogData)->lpstrFile = lpstrbuf;
strcpy(lpstrbuf,oldfilespec); // user's FileName
((LPOPENFILENAMEA)DialogData)->nMaxFile = BIGBUF_SIZE;
((LPOPENFILENAMEA)DialogData)->hInstance =
(void*)FindClassHInstance(this->ClassType());
return TCommonDialog::TaskModalDialog(DialogFunc, DialogData);
}
// Sequentially select null-terminated strings
// from a buffer terminated by one additional
// null. Used to get filenames from GetOpenFilename
// API message buffer. No error checking. Will
// always return non-NULL at least once.
// Intended to function similarly to strtok.
char * ztok(
char * string)
{
static char * p;
if(string) // Always on first call
{
p=string;
return string;
}
// Repeated call with NULL argument
// Increment return to next string
p+=(strlen(p)+1);
if(!(*p)) // Second null after str?
return NULL; // Yes, end of scan
return p; // No, another string.
}
// -------------------------------------------------------------------
-------
#pragma package(smart_init)
So I'll have a go with this code some time - probably this week.
And once again - thanks a lot.
David.
Timothy H. Buchman <tbuchmanPLEASE(at sign)REMOVEcitycenter.org> wrote in
message
> David, I suppose you've made other arrangements by now, but I've spent
> some spare time working on the problem. It's more the fault of the...