Windows操作系统为一些常用功能提供了一些通用对话框(Common Dialog Box),比如,在不同应用程序中运行打开文件、选择字体、选择颜色等操作时,不同程序显示的对话框的模样都是一样。这些对话框是操作系统提供的,实现对话框的代码封装在Comdlg32.dll库文件中,由于不同版本的Comdlg32.dll在设计上可能有所不同,所以不同版本的Windows下对话框会有所不同。
Windows提供多种通用对话框,每种通用对话框都使用一个专用的函数来创建和显示,另外,提供一个数据结构供初始化对话框使用,并在同一个数据结构中返回用户在对话框中输入的数据。
“打开”文件和“保存”文件对话框
显示“打开”文件对话框的函数是GetOpenFileName,显示“保存”文件对话框的函数是GetSaveFileName。这两个函数可以让用户选择驱动器、目录,以及一个文件名。但这两个对话框不对文件进行任何操作,也就是说,它们仅给用户提供一个统一的界面来“选择”文件,获取文件名以后,对文件的打开、读写等操作还需要程序自己解决。
函数原型如下:
BOOL WINAPI GetOpenFileName(
__inout LPOPENFILENAME lpofn
);
BOOL WINAPI GetSaveFileName(
__inout LPOPENFILENAME lpofn
);
其中lpofn参数是一个指针,指向一个OPENFILENAME结构,程序在调用函数前需要在结构中填写初始化数据,两个函数使用的结构是一样的,只是初始化数据不同而已:
typedef struct tagOFN {
DWORD lStructSize; //结构的长度
HWND hwndOwner; //所属窗口,可以为NULL
HINSTANCE hInstance; //
LPCTSTR lpstrFilter; //文件筛选字符串
LPTSTR lpstrCustomFilter; //
DWORD nMaxCustFilter; //
DWORD nFilterIndex; //
LPTSTR lpstrFile; //全路径的文件名缓冲区
DWORD nMaxFile; //文件名缓冲区长度
LPTSTR lpstrFileTitle; //不包含路径的文件名缓冲区
DWORD nMaxFileTitle; //文件名缓冲区的长度
LPCTSTR lpstrInitialDir; //初始目录
LPCTSTR lpstrTitle; //对话框标题
DWORD Flags; //标志
WORD nFileOffset; //文件名在字符串中的起始位置
WORD nFileExtension; //扩展名在字符串中的起始位置
LPCTSTR lpstrDefExt; //默认扩展名
LPARAM lCustData; //
LPOFNHOOKPROC lpfnHook; //
LPCTSTR lpTemplateName; //
#if (_WIN32_WINNT >= 0x0500)
void *pvReserved;
DWORD dwReserved;
DWORD FlagsEx;
#endif
} OPENFILENAME, *LPOPENFILENAME;
结构中重要字段说明:
lpStrFilter---指定文件名筛选字符串,该字段决定了对话框中“文件类型”下拉式列表框的内容,字符串可以由多组内容组成,每组包括一个说明字符串和一个筛选字符串,字符串最后用两个0结束。如下,字符串将在列表中显示两项内容,选择不同项目时分别列出“.txt”文件或者所有文件“*.*”:
'Text Files(*.txt)', 0, '*.txt', 0, 'All Files(*.*)', 0, '*.*', 0, 0
lpstrFile---指向一个包含文件名的缓冲区。如果这个缓冲区中已经包含了一个文件名,那么对话框初始化时显示的是这个文件名。当用户选择一个新文件时,函数在这里返回新的文件名。
nFileOffset---返回文件名字符串中文件名的起始位置,如当用户选择了文件“C:/dir1/file.txt”是,将返回8。
Flags---该字段决定对话框的不同行为,它可以是下列值的组合:
OFN_ALLOWMULTISELECT //允许同时选择多个文件名
OFN_CREATEPROMPT //如果用户输入一个不存在的文件名,对话框向用户提示“是否建立文件”
OFN_FILEMUSTEXIST //用户只能选择一个已经存在的文件名,
//使用这个标志时必须同时使用OFN_PATHMUSTEXIST
OFN_HIDEREADONLY //对话框中不显示“以只读方式打开”复选框
OFN_OVERWRITEPROMPT //在“保存”文件对话框使用时,当选择一个已经存在的文件时,
//对话框会提示“是否覆盖文件”
OFN_PATHMUSTEXIST //用户输入用户名时,路径必须存在
OFN_READONLY //对话框中“以只读方式”复选框初始化时处于选中状态
调用显示“打开”或“保存”文件对话框时,函数会停留直到对话框关闭为止,当用户单击了对话框中的“确定”按钮时,函数返回TRUE,用户单击“取消”按钮退出时,函数返回FALSE,程序可以由此判断是否需要继续进行打开或保存文件操作。
打开对话框代码片段如下:
OPENFILENAME ofn; // common dialog box structure
char szFile[260]; // buffer for file name
HWND hwnd; // owner window
HANDLE hf; // file handle
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
// Set lpstrFile[0] to '/0' so that GetOpenFileName does not
// use the contents of szFile to initialize itself.
ofn.lpstrFile[0] = '/0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = "All/0*.*/0Text/0*.TXT/0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
// Display the Open dialog box.
if (GetOpenFileName(&ofn)==TRUE)
hf = CreateFile(ofn.lpstrFile,
GENERIC_READ,
0,
(LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
打开保存对话框的实例代码片段如下:
// Obtain a handle to a reference device context.
hdcRef = GetDC(hWnd);
// Determine the picture frame dimensions.
// iWidthMM is the display width in millimeters.
// iHeightMM is the display height in millimeters.
// iWidthPels is the display width in pixels.
// iHeightPels is the display height in pixels
iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE);
iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE);
iWidthPels = GetDeviceCaps(hdcRef, HORZRES);
iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
// Retrieve the coordinates of the client
// rectangle, in pixels.
GetClientRect(hWnd, &rect);
// Convert client coordinates to .01-mm units.
// Use iWidthMM, iWidthPels, iHeightMM, and
// iHeightPels to determine the number of
// .01-millimeter units per pixel in the x-
// and y-directions.
rect.left = (rect.left * iWidthMM * 100)/iWidthPels;
rect.top = (rect.top * iHeightMM * 100)/iHeightPels;
rect.right = (rect.right * iWidthMM * 100)/iWidthPels;
rect.bottom = (rect.bottom * iHeightMM * 100)/iHeightPels;
// Load the filename filter from the string table.
LoadString(hInst, IDS_FILTERSTRING,
(LPSTR)szFilter, sizeof(szFilter));
// Replace the '%' separators that are embedded
// between the strings in the string-table entry
// with '/0'.
for (i=0; szFilter[i]!='/0'; i++)
if (szFilter[i] == '%')
szFilter[i] = '/0';
// Load the dialog title string from the table.
LoadString(hInst, IDS_TITLESTRING,
(LPSTR)szTitle, sizeof(szTitle));
// Initialize the OPENFILENAME members.
szFile[0] = '/0';
Ofn.lStructSize = sizeof(OPENFILENAME);
Ofn.hwndOwner = hWnd;
Ofn.lpstrFilter = szFilter;
Ofn.lpstrFile= szFile;
Ofn.nMaxFile = sizeof(szFile)/ sizeof(*szFile);
Ofn.lpstrFileTitle = szFileTitle;
Ofn.nMaxFileTitle = sizeof(szFileTitle);
Ofn.lpstrInitialDir = (LPSTR)NULL;
Ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
Ofn.lpstrTitle = szTitle;
// Display the Filename common dialog box. The
// filename specified by the user is passed
// to the CreateEnhMetaFile function and used to
// store the metafile on disk.
GetSaveFileName(&Ofn);
// Load the description from the string table.
LoadString(hInst, IDS_DESCRIPTIONSTRING,
(LPSTR)szDescription, sizeof(szDescription));
// Replace the '%' string separators that are
// embedded between strings in the string-table
// entry with '/0'.
for (i=0; szDescription[i]!='/0'; i++)
{
if (szDescription[i] == '%')
szDescription[i] = '/0';
}
// Create the metafile device context.
hdcMeta = CreateEnhMetaFile(hdcRef,
(LPTSTR) Ofn.lpstrFile,
&rect, (LPSTR)szDescription);
if (!hdcMeta)
errhandler("CreateEnhMetaFile", hWnd);
// Release the reference device context.
ReleaseDC(hWnd, hdcRef);