This
page details the descriptions of Windows' GetOpenFileName and GetSaveFileName API methods. The related demo code pages show how to
call the APIs, as well as demonstrating how to retrieve the constituent parts of the file string returned.
To access both of the file common dialogs the OPENFILENAME structure is used.
Prior to Windows 2000 this UDT was 76 bytes long, with
sTemplateName as the last member. With the introduction
of Windows XP and the Shell version 5 common dialogs,
the OPENFILENAME structure added three new members
increasing the size of the UDT to 88 bytes:
Public Type OPENFILENAME
nStructSize As Long
hWndOwner As Long
hInstance As Long
sFilter As String
sCustomFilter As String
nMaxCustFilter As Long
nFilterIndex As Long
sFile As String
nMaxFile As Long
sFileTitle As String
nMaxTitle As Long
sInitialDir As String
sDialogTitle As String
flags As Long
nFileOffset As Integer
nFileExtension As Integer
sDefFileExt As String
nCustData As Long
fnHook As Long
sTemplateName As String
pvReserved As Long 'new in Windows 2000 and later
dwReserved As Long 'new in Windows 2000 and later
flagsEx As Long 'new in Windows 2000 and later
End Type
Many of the members in the type are recognizable from the
similar properties exposed by the VB file common control. To assist in understanding the following code, a lengthy discussion of
each member is below. Following that is a discussion on
using this UDT in applications running on pre-Windows
2000 machines.
nStructSize is common among many Windows
UDTs. As more features are added to Windows controls, the number of members of a structure often change. For example,
the definition of the OPENFILENAME structure during Windows 9x
through Windows NT4 did not contain the last three
members. Windows 2000 and later use the three additional parameters added to the end of the type
to provide additional functionality. This type is also
required on Windows 2000 and later when utilizing a hook
to maintain the places bar in the explorer style. By
providing the UDT with a nStructSize member, the receiving API can determine which version of the structure is being used
thus whether to ignore any members beyond the size
passed. See below for a further discussion.
hWndOwner is also common, and specifies
the window owner the dialog, and therefore receives messages from the control or its error messages.
hInstance - If the
OFN_ENABLETEMPLATEHANDLE flag is set in the Flags member, hInstance is a handle to a memory object containing a dialog box
template. If the OFN_ENABLETEMPLATE flag is set, hInstance is a handle to a module that contains a dialog box template named by
the sTemplate member. If neither flag is set, this member is ignored. If the OFN_EXPLORER flag is set, the system uses the
specified template to create a dialog box that is a child of the default Explorer-style dialog box. If the OFN_EXPLORER flag is
not set, the system uses the template to create an old-style dialog box that replaces the default dialog box.
sFilter - buffer containing pairs of
null-terminated filter strings. The last string in the buffer must be terminated by two NULL characters. The first string in each
pair is a display string that describes the filter (for example, "Text Files"), and the second string specifies the
filter pattern (for example, "*.TXT"). To specify multiple filter patterns for a single display string, use a semicolon
to separate the patterns (for example, "*.TXT;*.DOC;*.BAK"). A pattern string can be a combination of valid file name
characters and the asterisk (*) wildcard character. Do not include spaces in the pattern string. The system does not change the
order of the filters. It displays them in the File Types combo box in the order specified in sFilter.
nFilterIndex specifies an index into the
buffer pointed to by sFilter. The system uses the index value to obtain a pair of strings to use as the initial filter
description and filter pattern for the dialog box. The first pair of strings has an index value of 1. When the user closes the
dialog box, the system copies the index of the selected filter strings into this location.
sFile points to a buffer that contains a
filename used to initialize the File Name edit control. The first character of this buffer must be vbNullChar if initialization
is not necessary. When the GetOpenFileName or GetSaveFileName function returns, this buffer contains the drive designator, path,
filename, and extension of the selected file(s). The demo code below passes "Untitled.bas" as the initial filename,
along with a buffer of an additional 1024 chrs for the return selection.
sFileTitle points to a buffer that
receives the file name and extension (without path information) of the selected file. If this member is vbNullChar, the function
does not copy the file name.
Assuming a buffer is passed for both sFile and sFileTitle,
the difference between the these two members can be seen when a multiple file selection dialog is used (flag
OFN_ALLOWMULTISELECT). In a single selection, both sFile and sFileTitle return the same data. But when multiple files are
selected, sFileTitle returns empty, while sFile contains a null-separated string containing the users selection (up to the max
chrs passed in the sFile buffer).
nMaxFile - the size of the buffer
pointed to by sFile. The buffer must be large enough to store the path and file name string or strings, including the terminating
null character. GetOpenFileName and GetSaveFileName return False if the buffer is too small to contain the file selected
information. The buffer should be at least 260 characters long.
nMaxTitle - the size, of the buffer
pointed to by sFileTitle. This member is ignored if sFileTitle is vbNullChr.
sInitialDir is a pointer to a null
terminated string that can specify the initial directory. The algorithm for selecting the initial directory varies on different
platforms (taken from the MSDN).
- Windows 2000/Windows
XP:
- If sFile contains a path, that path is the initial
directory.
- Otherwise, sInitialDir specifies the initial
directory.
- If sInitialDir is NULL and the current directory
contains any files of the specified filter types, the initial directory is the current directory.
- Otherwise, if the application has used an Open or
Save As dialog box in the past, the path most recently used is selected as the initial directory. However, if an
application is not run for a long time, its saved selected path will be discarded.
- Otherwise, the initial directory is the personal
files directory of the current user.
- Otherwise, the initial directory is the Desktop
folder
- Windows 98:
- sInitialDir specifies the initial directory.
- If sInitialDir is NULL and sFile contains a path,
that path is the initial directory.
- Otherwise, if the current directory contains any
files of the specified filter types, the initial directory is the current directory.
- Otherwise, the initial directory is the personal
files directory of the current user.
- Earlier versions of Windows and Windows NT/
2000:
- sInitialDir specifies the initial directory.
- If sInitialDir is NULL and sFile contains a path,
that path is the initial directory.
- Otherwise, the initial directory is the current
directory.
flags - bit flags you can use to
initialize the dialog box. When the dialog box returns, it sets these flags to indicate the user's input. This member can be a
combination of the following flags (within the bounds of the target OS). This is an abbreviated version of the same listing in
the MSDN:
Flag |
Meaning |
OFN_ALLOWMULTISELECT |
Specifies that the File Name
list box allows multiple selections.
If the user selects more than one file, the sFile
buffer returns the path to the current directory followed by the file names of the selected files. The nFileOffset
member is the offset, in bytes or characters, to the first file name, and the nFileExtension member is not
used. For Explorer-style dialog boxes, the directory and file name strings are NULL separated, with an extra NULL
character after the last file name. This format enables the Explorer-style dialog boxes to return long file names
that include spaces. |
OFN_CREATEPROMPT |
If the user specifies a file that
does not exist, this flag causes the dialog box to prompt the user for permission to create the file. If the user
chooses to create the file, the dialog box closes and the function returns the specified name; otherwise, the dialog
box remains open. If you use this flag with the OFN_ALLOWMULTISELECT flag, the dialog box allows the user to specify
only one nonexistent file. |
OFN_ENABLETEMPLATE |
Indicates that the sTemplateName
member is a pointer to the name of a dialog template resource in the module identified by the hInstance
member. |
OFN_ENABLETEMPLATEHANDLE |
Indicates that the hInstance
member identifies a data block that contains a preloaded dialog box template. The system ignores the sTemplateName
if this flag is specified. |
OFN_EXPLORER |
Indicates that any customizations
made to the Open or Save As dialog box use the new Explorer-style customization methods. By default, the Open
and Save As dialog boxes use the Explorer-style user interface regardless of whether this flag is set.
This flag is necessary only if you provide a hook procedure or custom template, or set the OFN_ALLOWMULTISELECT flag. |
OFN_EXTENSIONDIFFERENT |
Specifies that the user typed a
file name extension that differs from the extension specified by sDefFileExt. The function does not use this
flag if sDefFileExt is NULL. |
OFN_FILEMUSTEXIST |
Specifies that the user can type
only names of existing files in the File Name entry field. If this flag is specified and the user
enters an invalid name, the dialog box procedure displays a warning in a message box. If this flag is specified, the
OFN_PATHMUSTEXIST flag is also used. |
OFN_HIDEREADONLY |
Hides the Read Only
check box. |
OFN_LONGNAMES |
For old-style dialog boxes, this
flag causes the dialog box to use long file names. If this flag is not specified, or if the OFN_ALLOWMULTISELECT flag
is also set, old-style dialog boxes use short file names (8.3 format) for file names with spaces. Explorer-style
dialog boxes ignore this flag and always display long file names. |
OFN_NOCHANGEDIR |
Restores the current directory to
its original value if the user changed the directory while searching for files. |
OFN_NODEREFERENCELINKS |
Directs the dialog box to return
the path and file name of the selected shortcut (.LNK) file. If this value is not specified, the dialog box returns
the path and file name of the file referenced by the shortcut. |
OFN_NOLONGNAMES |
For old-style dialog boxes, this
flag causes the dialog box to use short file names (8.3 format). Explorer-style dialog boxes ignore this flag and
always display long file names. |
OFN_NONETWORKBUTTON |
Hides and disables the Network
button. |
OFN_NOREADONLYRETURN |
Specifies that the returned file
does not have the Read Only check box selected and is not in a write-protected directory, Important:
This value is define in the header files as &H8000, which unfortunately is -32768 in VB. The
correct value required 32768, so an ampersand (&) must be appended to this value to force VB to cast this to a
Long. This is even true if the constant is defined As Long in the declare. If you use this constant in
your apps and the file dialog either does not appear or the app crashes without an error, check this value. |
OFN_NOTESTFILECREATE |
Specifies that the file is not
created before the dialog box is closed. This flag should be specified if the application saves the file on a create-non-modify
network share. When an application specifies this flag, the library does not check for write protection, a full disk,
an open drive door, or network protection. Applications using this flag must perform file operations carefully,
because a file cannot be reopened once it is closed. |
OFN_NOVALIDATE |
Specifies that the common dialog
boxes allow invalid characters in the returned file name. Typically, the calling application uses a hook procedure
that checks the file name by using the FILEOKSTRING message. If the text box in the edit control is empty or
contains nothing but spaces, the lists of files and directories are updated. If the text box in the edit control
contains anything else, nFileOffset and nFileExtension are set to values generated by parsing the text.
No default extension is added to the text, nor is text copied to the buffer specified by sFileTitle.
If the value specified by nFileOffset is less than
zero, the file name is invalid. Otherwise, the file name is valid, and nFileExtension and nFileOffset
can be used as if the OFN_NOVALIDATE flag had not been specified. |
OFN_OVERWRITEPROMPT |
Causes the Save As
dialog box to generate a message box if the selected file already exists. The user must confirm whether to overwrite
the file. |
OFN_PATHMUSTEXIST |
Specifies that the user can type
only valid paths and file names. If this flag is used and the user types an invalid path and file name in the File
Name entry field, the dialog box function displays a warning in a message box. |
OFN_READONLY |
Causes the Read Only
check box to be selected initially when the dialog box is created. This flag indicates the state of the Read Only
check box when the dialog box is closed. |
OFN_SHAREAWARE |
Specifies that if a call to the OpenFile
function fails because of a network sharing violation, the error is ignored and the dialog box returns the selected
file name. If this flag is not set, the dialog box notifies your hook procedure when a network sharing violation
occurs for the file name specified by the user. If you set the OFN_EXPLORER flag, the dialog box sends the CDN_SHAREVIOLATION
message to the hook procedure. If you do not set OFN_EXPLORER, the dialog box sends the SHAREVISTRING
registered message to the hook procedure. |
OFN_SHAREFALLTHROUGH |
Used with a SHAREVISTRING notification sent to a
hook procedure: Accept the file name |
OFN_SHAREWARN |
Used with a SHAREVISTRING notification sent to a
hook procedure: Reject the file name and
displays a warning message (the same result as
if there were no hook procedure). |
OFN_SHARENOWARN |
Used with a SHAREVISTRING notification sent to a
hook procedure: Reject the file name but do not
warn the user. The application is responsible
for displaying a warning message. |
OFN_SHOWHELP |
Causes the dialog box to display
the Help button. The hwndOwner member must specify the window to receive the HELPMSGSTRING
registered messages that the dialog box sends when the user clicks the Help button. An Explorer-style dialog
box sends a CDN_HELP notification message to your hook procedure when the user clicks the Help button. |
Flag |
Meaning |
OFN_DONTADDTORECENT |
Windows 2000/XP
or later: Prevents
the system from adding a link to the selected file in the file system directory that contains the user's most
recently used documents. To retrieve the location of this directory, call the SHGetSpecialFolderLocation
function with the CSIDL_RECENT flag. |
OFN_ENABLEHOOK |
Enables the hook function
specified in the fnHook member. |
OFN_ENABLEINCLUDENOTIFY |
Windows 2000/XP
or later: Causes
the dialog box to send CDN_INCLUDEITEM notification messages to your OFNHookProc hook procedure when
the user opens a folder. The dialog box sends a notification for each item in the newly opened folder. These messages
enable you to control which items the dialog box displays in the folder's item list. |
OFN_ENABLESIZING |
Windows 2000/XP
or later, Windows 98:
Enables the Explorer-style dialog box to be resized using either the mouse or the keyboard. By default, the
Explorer-style Open and Save As dialog boxes allow the dialog box to be resized regardless of
whether this flag is set. This flag is necessary only if you provide a hook procedure or custom template. The
old-style dialog box does not permit resizing. |
OFN_FORCESHOWHIDDEN |
Windows 2000/XP
or later: Forces the
showing of system and hidden files, thus overriding the user setting to show or not show hidden files. However, a
file that is marked both system and hidden is not shown. |
nFileOffset specifies the zero-based
offset from the beginning of the path to the file name in the string pointed to by sFIle. For example, if sFIle points to the
following string, "c:\dir1\dir2\file.ext", this member contains the value 13 to indicate the offset of the "file.ext"
string. If the user selects more than one file, nFileOffset is the offset to the first file name.
nFileExtension specifies the zero-based
offset in chrs from the beginning of the path to the file name extension in the string pointed to by sFIle. For example, if sFIle
points to the following string, "c:\dir1\dir2\file.ext", this member contains the value 18. If the user did not type an
extension and sDEfFileExt is NULL, this member specifies an offset to the terminating null character. If the user typed
"." as the last character in the file name, this member specifies zero.
sDefFileExt is a pointer to a buffer
that contains the default extension. GetOpenFileName and GetSaveFileName append this extension to the file name if the user fails
to type an extension. This string can be any length, but only the first three characters are appended. The string should not
contain a period. If this member is NULL and the user fails to type an extension, no extension is appended.x
fnHook - address to a hook (callback).
This member is ignored unless the Flags member includes the OFN_ENABLEHOOK flag.
sCustomFilter, nMaxCustFilter, nCustData,
sTemplateName are not covered in this demo. The MSDN has full information on these members.
API Return Values:
If the user specifies a file name and clicks the OK
button, the return value is nonzero. The buffer pointed to by the sFIle member of the OPENFILENAME structure contains the full
path and file name specified by the user. If the user cancels or closes the Open dialog box or an error occurs, the return value
is zero.
Note too that the GetOpenFileName and GetSaveFileName
dialogs only provide the means for the user to chose files. Although the File Save function may ask to overwrite an existing
file, no actual overwriting will occur -- coding a file save method is the responsibility of the developer.
For a discussion on OPENFILENAME structure issues
specific to Windows 2000/Windows XP, see GetOpenFileName: File Dialog Centering using a Callback.
With the descriptions out of the way, the code to
implement the common dialogs is straightforward.
GetOpenFileName: File Open Common Dialog Basics
GetSaveFileName: File Save Common Dialog Basics
For a discussion on modifying the OPENFILENAME structure in
order to display the new Windows 2000 or Windows XP-style
Open and Save dialogs, please see the comments section in
the page
GetOpenFileName: File Dialog Centering using a Callback
(note: a hook is not required to display this new-style
dialog - it just so happens that page is the one I chose to
explain this on.)
Windows' New
Open and Save Dialog Style
Beginning with Windows 2000, the OPENFILENAME structure
was extended
to include three additional parameters specific to Windows 2000 and
Windows XP. These additions change the size of the structure passed as the
.nStructSize member which Windows uses to determine whether it should display the old or new-style dialogs.
However,
passing the new extended structure on a Win9x or NT4 system will result in the
Open File or Save File dialog not being displayed at all.
Thankfully, because of the nStructSize parameter, you can go ahead and
define the type with the new members regardless of the system, and then
during the call identify the operating
system in use and modify the value passed as the nStructSize parameter as
appropriately.
To assure that the
new dialog appears as expected, you must ensure that Len(OFN) is passed
as the nStructSize parameter, and likewise to ensure the dialog appears
on lower versions of windows, you can pass Len(OFN - 12) (12 = 3 longs
of 4 bytes each).
Probably the best way to ensure the correct value is passed
is through declaration of three variables in your code:
Public OSV_VERSION_LENGTH as Long
Private Const OSV_LENGTH As Long = 76
Private Const OSVEX_LENGTH As Long = 88
Then use a routine to assign one of the two OSV length
values to a variable and assign that to
nStructSize.
|