它通常与 GetOpenFileName 和 GetSaveFileName 这两个函数配合使用。

(图片来源网络,侵删)
核心概念
OpenFileName 本身不是一个函数,而是一个结构体,它的作用是向 Windows 系统传递“你希望这个文件选择对话框长什么样、有什么功能”的配置信息,当用户在对话框中点击“确定”或“取消”后,这个结构体里的一些成员变量会被系统填充上用户的选择结果。
使用它的完整流程是:
- 定义一个
OPENFILENAME结构体变量。 - 初始化这个结构体的各个成员,告诉你的需求(比如对话框标题、默认文件类型等)。
- 调用
GetOpenFileName()或GetSaveFileName()函数,并将这个结构体变量的地址作为参数传入。 - 检查函数的返回值,并根据结构体中被填充的成员来获取用户的选择。
必需的头文件和库
在使用之前,请确保你的代码包含了正确的头文件,并且在链接时指定了正确的库。
#include <windows.h> // 包含 OPENFILENAME 结构体和相关函数的定义 #include <commdlg.h> // 包含一些对话框相关的常量定义 #pragma comment(lib, "comdlg32.lib") // 告诉链接器链接 comdlg32.lib 这个库
OPENFILENAME 结构体的关键成员
这个结构体有很多成员,但大部分情况下,你只需要设置其中几个核心的即可。

(图片来源网络,侵删)
| 成员 | 类型 | 描述 |
|---|---|---|
lStructSize |
DWORD |
必须设置,结构体的大小(以字节为单位),这有助于 Windows API 处理不同版本的兼容性,通常设置为 sizeof(OPENFILENAME)。 |
hwndOwner |
HWND |
可选,对话框所有者窗口的句柄,如果设置为 NULL,对话框没有所有者,如果设置了,对话框会居中于该窗口。 |
lpstrFilter |
LPCSTR |
非常重要,文件类型过滤器,这是一个以双 NULL 结尾的字符串数组,格式为:"描述1\0过滤器1\0描述2\0过滤器2\0\0"。"Text Files\0*.txt\0All Files\0*.*\0\0"。 |
lpstrFile |
LPSTR |
非常重要,用于存放用户选择的文件路径的缓冲区,你必须预先分配足够大的空间(char szFile[MAX_PATH];),对话框打开时,这里可以显示默认路径。 |
nMaxFile |
DWORD |
必须设置。lpstrFile 缓冲区的大小,通常设置为 MAX_PATH。 |
lpstrFileTitle |
LPSTR |
可选,用于存放用户选择的文件名(不带路径)的缓冲区,如果为 NULL,则系统会自动计算。 |
nMaxFileTitle |
DWORD |
必须设置(lpstrFileTitle 不为 NULL)。lpstrFileTitle 缓冲区的大小。 |
lpstrInitialDir |
LPCSTR |
可选,对话框打开时显示的初始目录,如果为 NULL,则使用当前工作目录。 |
lpstrTitle |
LPCSTR |
可选,对话框窗口的标题,如果为 NULL,则使用默认标题(如“打开”或“另存为”)。 |
Flags |
DWORD |
非常重要,控制对话框行为的标志位,可以使用 组合多个标志,常用值见下方表格。 |
nFilterIndex |
WORD |
可选,默认选中的过滤器索引(从1开始),如果用户选择了“所有文件”,这个值不会改变。 |
Flags 常用标志位:
| 标志位 | 值 | 描述 |
|---|---|---|
OFN_FILEMUSTEXIST |
0x00001000 |
强制用户只能输入已存在的文件名。 |
OFN_PATHMUSTEXIST |
0x00000800 |
强制用户只能输入有效的路径。 |
OFN_HIDEREADONLY |
0x00000004 |
隐藏“只读”复选框。 |
OFN_OVERWRITEPROMPT |
0x00000002 |
在保存对话框中,如果文件已存在,则提示是否覆盖。 |
OFN_EXPLORER |
0x00080000 |
使用新的资源管理器风格的对话框(默认)。 |
OFN_READONLY |
0x00000001 |
如果用户勾选了“只读”复选框,则此标志位在返回时会被设置。 |
完整示例代码
下面是一个完整的示例,演示如何创建一个“打开文件”对话框。
#include <windows.h>
#include <tchar.h> // 为了方便使用 TCHAR,推荐使用
#include <commdlg.h>
#pragma comment(lib, "comdlg32.lib")
// 简单的 Windows 程序,只显示一个消息框
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
// 1. 定义并初始化 OPENFILENAME 结构体
OPENFILENAME ofn;
TCHAR szFile[MAX_PATH] = { 0 }; // 用于存放完整文件路径的缓冲区
// 清零结构体
ZeroMemory(&ofn, sizeof(ofn));
// 2. 设置结构体成员
ofn.lStructSize = sizeof(ofn); // 结构体大小
ofn.hwndOwner = NULL; // 所有者窗口句柄
ofn.lpstrFile = szFile; // 文件路径缓冲区
ofn.nMaxFile = MAX_PATH; // 缓冲区大小
ofn.lpstrFilter = _T("Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"); // 过滤器
ofn.nFilterIndex = 1; // 默认选择第一个过滤器
ofn.lpstrFileTitle = NULL; // 不需要单独的文件名缓冲区
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = _T("C:\\"); // 初始目录
ofn.lpstrTitle = _T("请选择一个文本文件"); // 对话框标题
ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; // 标志位
// 3. 调用 GetOpenFileName 函数
// 如果用户点击“确定”,函数返回 TRUE
// 如果用户点击“取消”或出错,函数返回 FALSE
if (GetOpenFileName(&ofn)) {
// 4. 处理用户的选择
MessageBox(NULL, szFile, _T("你选择的文件"), MB_OK);
} else {
// 用户取消或出错
// CommDlgExtendedError() 函数可以获取具体的错误码
DWORD err = CommDlgExtendedError();
if (err == 0) {
// 用户点击了“取消”
MessageBox(NULL, _T("用户取消了操作。"), _T("提示"), MB_OK);
} else {
// 发生了其他错误
TCHAR errMsg[256];
_stprintf_s(errMsg, _T("发生错误,错误码: %d"), err);
MessageBox(NULL, errMsg, _T("错误"), MB_OK | MB_ICONERROR);
}
}
return 0;
}
代码解释:
TCHAR和_T():为了代码能同时支持 ASCII 和 Unicode,Windows 推荐使用TCHAR类型。_T()宏会根据项目设置自动转换为普通字符串(char)或宽字符字符串(wchar_t)。ZeroMemory(&ofn, sizeof(ofn)):这是一个好习惯,可以将结构体所有成员初始化为 0,避免使用未初始化的内存。GetOpenFileName(&ofn):这是核心函数调用,它是一个模态对话框,会阻塞你的程序,直到用户关闭它。szFile:在调用GetOpenFileName之前,szFile通常是空的,调用成功后,它会被填充上用户选择的完整文件路径,C:\my_folder\my_document.txt。- 错误处理:
GetOpenFileName返回FALSE不一定代表用户取消,也可能是发生了错误(比如内存不足),需要调用CommDlgExtendedError()来区分:- 返回 0:用户点击了“取消”。
- 返回非 0:发生了具体错误。
GetSaveFileName 的用法
GetSaveFileName 的用法和 GetOpenFileName 几乎完全一样,只是它用于“保存文件”对话框,主要区别在于 Flags 的使用。
保存文件示例片段:
OPENFILENAME ofn;
TCHAR szFile[MAX_PATH] = { 0 };
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFile = szFile;
ofn.nMaxFile = MAX_PATH;
// ... (其他成员设置)
// 保存对话框通常需要提示覆盖
ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT; // 关键标志位
// 调用 GetSaveFileName
if (GetSaveFileName(&ofn)) {
// 用户点击了“保存”,szFile 中是用户想保存的文件名
// 注意:这个文件此时还不存在,你需要自己创建并写入内容
MessageBox(NULL, szFile, _T("你将保存为文件"), MB_OK);
}
| 步骤 | 动作 | 关键点 |
|---|---|---|
| 1 | 包含头文件 | #include <windows.h>, #include <commdlg.h> |
| 2 | 链接库 | #pragma comment(lib, "comdlg32.lib") |
| 3 | 定义缓冲区 | TCHAR szFile[MAX_PATH]; |
| 4 | 定义并清零结构体 | OPENFILENAME ofn; ZeroMemory(&ofn, sizeof(ofn)); |
| 5 | 配置结构体 | 设置 lStructSize, lpstrFile, nMaxFile, lpstrFilter, Flags 等。 |
| 6 | 调用函数 | GetOpenFileName(&ofn) 或 GetSaveFileName(&ofn)。 |
| 7 | 检查返回值 | 如果为 TRUE,从 lpstrFile 获取路径,如果为 FALSE,用 CommDlgExtendedError() 检查原因。 |
掌握了 OPENFILENAME 结构体的用法,你就可以在 C 语言程序中轻松实现标准的文件打开和保存功能了。

(图片来源网络,侵删)
