by Scott Anderson, Stuart Morris and Jurjen
"SYSTEM-DIALOG GET-FILE" allows to select only one filename. When you want to select multiple filenames you can call API function GetOpenFileNameA, specifying the OFN_ALLOWMULTISELECT flag.
Procedure SelectMultipleFileNames uses GetOpenFileNameA for the purpose of selecting multiple filenames. The first listing shows how to call the procedure, the second listing shows the implementation of the procedure.
The parameters are:
* FilterList
a list of filters separated by 'pipe'-symbols ( "|" ). Each individual filter is a description, followed by a pipe-symbol, followed by a semicolon-separated list of wildcards. The format of the description is not important but by convention it should be a text followed by the list of wildcards between brackets. The first filter is the default.
* InitialDirectory
Name of the directory where you want to the dialog to start. Specify the unknown value (?) to start in the current directory.
* DialogTitle
Specifies the title for the dialog.
* FileNames
returns a comma-separated list of selected filenames unless OK=FALSE.
* OK
returns FALSE if the user selected the Cancel button.
DEFINE VARIABLE lv-Files AS CHARACTER NO-UNDO. DEFINE VARIABLE OK AS LOGICAL NO-UNDO. RUN SelectMultipleFileNames (INPUT "Word Documents (*.doc,*.rtf)|*.doc;*.rtf" + "|" + "Excel Worksheets (*.xls)|*.xls" + "|" + "Access Databases (*.mdb)|*.mdb" + "|" + "All (doc,rtf,xls,mdb,ppt)|*.doc;*.rtf;*.xls;*.mdb;*.ppt", INPUT "C:\My Documents", INPUT "Select one or more Office documents", OUTPUT lv-Files, OUTPUT OK ). IF OK THEN MESSAGE "you selected these files:" SKIP lv-Files VIEW-AS ALERT-BOX. ELSE MESSAGE "you pressed Cancel" VIEW-AS ALERT-BOX.
&GLOBAL-DEFINE OFN_OVERWRITEPROMPT 2 &GLOBAL-DEFINE OFN_HIDEREADONLY 4 &GLOBAL-DEFINE OFN_NOCHANGEDIR 8 &GLOBAL-DEFINE OFN_ALLOWMULTISELECT 512 &GLOBAL-DEFINE OFN_PATHMUSTEXIST 2048 &GLOBAL-DEFINE OFN_FILEMUSTEXIST 4096 &GLOBAL-DEFINE OFN_NOREADONLYRETURN 32768 &GLOBAL-DEFINE OFN_EXPLORER 524288 PROCEDURE GetOpenFileNameA EXTERNAL "comdlg32.dll" : DEFINE INPUT PARAMETER lpOfn AS LONG. DEFINE RETURN PARAMETER pReturn AS LONG. END PROCEDURE. PROCEDURE SelectMultipleFileNames : /*------------------------------------------------------------------------------ Purpose: Replaces the SYSTEM-DIALOG-GET-FILE common dialog, supports multiselect. Parameters: ------------------------------------------------------------------------------*/ DEFINE INPUT PARAMETER FilterList AS CHARACTER NO-UNDO. DEFINE INPUT PARAMETER InitialDirectory AS CHARACTER NO-UNDO. DEFINE INPUT PARAMETER DialogTitle AS CHARACTER NO-UNDO. DEFINE OUTPUT PARAMETER FileNames AS CHARACTER NO-UNDO. DEFINE OUTPUT PARAMETER OK AS INTEGER NO-UNDO. DEFINE VARIABLE Flags AS INTEGER NO-UNDO. DEFINE VARIABLE lpOfn AS MEMPTR NO-UNDO. DEFINE VARIABLE lpstrFilter AS MEMPTR NO-UNDO. DEFINE VARIABLE lpstrTitle AS MEMPTR NO-UNDO. DEFINE VARIABLE lpstrInitialDir AS MEMPTR NO-UNDO. DEFINE VARIABLE lpstrFile AS MEMPTR NO-UNDO. DEFINE VARIABLE offset AS INTEGER NO-UNDO. /* Flags controls the behaviour and appearance of the dialog-box. There is much room for experiments. This combination works nice: */ Flags = {&OFN_ALLOWMULTISELECT} + {&OFN_EXPLORER} + {&OFN_NOCHANGEDIR}. /* convert the "|"-separated list of filters to a CHR(0)-separated list and make sure it's terminated with a double CHR(0): */ FilterList = TRIM(FilterList,"|") + "|". /* this will cause the double CHR(0) */ SET-SIZE(lpstrFilter) = LENGTH(FilterList) + 1. PUT-STRING(lpstrFilter, 1) = FilterList. DO offset=1 TO GET-SIZE(lpstrFilter) : IF GET-BYTE(lpstrFilter,offset)=124 /* =ASC("|") */ THEN PUT-BYTE(lpstrFilter,offset)=0. END. /* get memory-pointers to the string parameters: */ SET-SIZE(lpstrFile) = 1024. /* room for a couple of files... */ PUT-BYTE(lpstrFile,1) = 0. /* don't initialize dialog to a file */ SET-SIZE(lpstrTitle) = LENGTH(DialogTitle) + 1. PUT-STRING(lpstrTitle,1) = DialogTitle. IF InitialDirectory NE ? THEN DO: SET-SIZE(lpstrInitialDir) = LENGTH(InitialDirectory) + 1. PUT-STRING(lpstrInitialDir,1) = InitialDirectory. END. /* create and initialize an OPENFILENAME structure: */ SET-SIZE(lpOfn) = 76. /* = {&OPENFILENAME_SIZE_VERSION_400} to be used in NT4 and Windows 95/98. Windows 2000 supports a couple more fields. */ /* size */ PUT-LONG (lpOfn, 1) = GET-SIZE(lpOfn). /* hwndOwner */ PUT-LONG (lpOfn, 5) = CURRENT-WINDOW:HWND. /* hInstance */ PUT-LONG (lpOfn, 9) = 0. /* lpstrFilter */ PUT-LONG (lpOfn,13) = GET-POINTER-VALUE(lpstrFilter). /* lpstrCustomFilter */ PUT-LONG (lpOfn,17) = 0. /* nMaxCustFilter */ PUT-LONG (lpOfn,21) = 0. /* nFilterIndex */ PUT-LONG (lpOfn,25) = 0. /* lpstrFile */ PUT-LONG (lpOfn,29) = GET-POINTER-VALUE(lpstrFile). /* nMaxFile */ PUT-LONG (lpOfn,33) = GET-SIZE(lpstrFile). /* lpstrFileTitle */ PUT-LONG (lpOfn,37) = 0. /* nMaxFileTitle */ PUT-LONG (lpOfn,41) = 0. /* lpstrInitialDir */ PUT-LONG (lpOfn,45) = GET-POINTER-VALUE(lpstrInitialDir). /* lpstrTitle */ PUT-LONG (lpOfn,49) = GET-POINTER-VALUE(lpstrTitle). /* flags */ PUT-LONG (lpOfn,53) = Flags. /* nFileOffset */ PUT-SHORT(lpOfn,57) = 0. /* nFileExtension */ PUT-SHORT(lpOfn,59) = 0. /* lpstrDefExt */ PUT-LONG (lpOfn,61) = 0. /* lCustData */ PUT-LONG (lpOfn,65) = 0. /* lpfnHook */ PUT-LONG (lpOfn,69) = 0. /* lpTemplateName */ PUT-LONG (lpOfn,73) = 0. /* run the dialog: */ RUN GetOpenFileNameA (GET-POINTER-VALUE(lpOfn), OUTPUT OK). /* release memory: */ SET-SIZE(lpstrFilter) = 0. SET-SIZE(lpOfn) = 0. SET-SIZE(lpstrTitle) = 0. SET-SIZE(lpstrInitialDir) = 0. /* lpstrFilter now contains a path, followed by CHR(0), followed by a CHR(0)-separated list of filenames, terminated by a double CHR(0). Unless the user selected only one file: then lpstrFilter will simply contain the fully-qualified filename. Either way, let's convert the result to a comma-separated list of fully-qualified filenames: */ IF OK NE 0 THEN DO: DEFINE VARIABLE cPath AS CHARACTER NO-UNDO. DEFINE VARIABLE cList AS CHARACTER NO-UNDO. DEFINE VARIABLE cFile AS CHARACTER NO-UNDO. ASSIGN cPath = GET-STRING(lpstrFile,1) offset = LENGTH(cPath) + 2. REPEAT: cFile = GET-STRING(lpstrFile, offset). IF cFile = "" THEN LEAVE. ASSIGN cList = cList + ',' + cPath + '\' + cFile offset = offset + LENGTH(cFile) + 1. END. ASSIGN cList = TRIM(cList, ",") FileNames = IF cList = "" THEN cPath ELSE cList. END. SET-SIZE(lpstrFile) = 0. END PROCEDURE. /* SelectMultipleFileNames */