最近在做Windows 开发过程中遇到一个问题,需要打开文件对话框和另存为对话框,获取所选文件的路径信息,这部分很容易就实现了,可当另存为文件时如何获得格式不同文件的扩展名却遇到了一点问题,经过一番资料搜索和官方文档查阅,遂解决。先说心得,windows API 相关的问题还是要直接查询微软官方文档来的快,上面解释的很清楚,不要被英文和那些奇奇怪怪的定义吓到,自己动手实现几次就明白是怎么回事了。东拉西扯,进入正题,
Windows 打开和另存为对话框如下所示,
(1) 打开对话框

(2)另存为对话框

这里用一个例子说明几个概念,文件目录,文件路径,文件名,如下图所示,在F盘Demo文件夹下有一个名为"Test"的txt文件
文件Test.txt的文件名是“Test”
文件目录是 “F:\Demo";
文件路径是:“F:\Demo\Test.txt";
文件扩展名是:“.txt”

这打开“打开”对话框以及打开“另存为对话框”这两个两个窗口涉及到的API分别为
GetOpenFileName()
GetSaveFileName()
微软官方的文档的建议是这两个API已经过时了,建议使用 IFileOpenDialog 或者IFileSaveDialog,这个不是本文的主题,有兴趣的朋友可以去官网查询新方法的用法,此处暂且不表。
以GetOpenFileName() 为例,做以解释。官方文档给出的函数定义是

BOOL GetOpenFileNameA(LPOPENFILENAMEA Arg1
);

参数 Arg1 类型 LPOPENFILENAME
(小提示,如果觉得官方文档大段的英文看起来很费劲,可以用chrome浏览器自带的翻译功能,鼠标右键有翻译选项,翻译的结果也八九不离十)关于类型LPOPENFILENAME 文档给出的解释是:
A pointer to an OPENFILENAME structure that contains information used to initialize the dialog box. When GetSaveFileName returns, this structure contains information about the user’s file selection.(一个指向OPENFILENAME结构的指针,该结构包含用于初始化对话框的信息。当GetSaveFileName返回时,此结构包含有关用户文件选择的信息。)
因此我们知道GetOpenFileNameA的参数我们需要传入的是一个指向 OPENFILENAME 结构的指针,马不停蹄的我们要立即看看这个OPENFILENAME 结构的内容是什么,因为只有知道他的结构我们才能知道如何初始化我们的结构体指针。如果经常使用Windows API 你就会发现这是很常见的模式。 不同的开发人员有不同的需要,Windows 把框架丢给你,让你自己定义,比如我们打开的窗口的标题,窗口的模态,保存文件类型的数目,是否允许多选,等等。这也是我们初始化这个结构体的意义所在。

点进OPENFILENAME 的链接,我们看到如下结构体定义

typedef struct tagOFNA {DWORD         lStructSize;HWND          hwndOwner;HINSTANCE     hInstance;LPCSTR        lpstrFilter;LPSTR         lpstrCustomFilter;DWORD         nMaxCustFilter;DWORD         nFilterIndex;LPSTR         lpstrFile;DWORD         nMaxFile;LPSTR         lpstrFileTitle;DWORD         nMaxFileTitle;LPCSTR        lpstrInitialDir;LPCSTR        lpstrTitle;DWORD         Flags;WORD          nFileOffset;WORD          nFileExtension;LPCSTR        lpstrDefExt;LPARAM        lCustData;LPOFNHOOKPROC lpfnHook;LPCSTR        lpTemplateName;LPEDITMENU    lpEditInfo;LPCSTR        lpstrPrompt;void          *pvReserved;DWORD         dwReserved;DWORD         FlagsEx;
} OPENFILENAMEA, *LPOPENFILENAMEA;

文档里面每一项都解释的很清楚,这里就不做一一解读了。挑其中几个用的比较多的解释一下。
lStructSize:结构的长度,以字节为单位。此参数使用 sizeof (OPENFILENAME)。
hwndOwner:拥有该对话框的窗口的句柄。这个成员可以是任何有效的窗口句柄。如果对话框里有没有所有者,它可以为 NULL。
lpstrFilter:筛选器,这个关键字很常用,他决定着对话框的文件类型。这个关键字通常由两对字符串构成,每一对中的第一个字符串是一个显示字符串,描述了该筛选器 (例如,“文本文件”),和第二个字符串指定筛选器模式 (例如,"*.TXT")。例如

ofn.lpstrFiler = TEXT("所有文件\0*.*\0\0");

我们打开的对话框保存类型如下所示,

如果我们想要在一个条目内有多个格式选择,以分号分割,例如我们只想打开txt或者doc文件,以此类推;

ofn.lpstrFiler = TEXT("所有文件\0*.txt;*.doc*\0\0");

如果我们想显示多个条目,实现如下图效果,

则继续添加筛选器即可,例如

ofn.lpstrFilter = TEXT("所有文件\0*.*\0文本 文件(*.txt)\0*.txt*\0图片(*.jpg)\0*.jpg*\0\0");

nFilterIndex:在文件类型控件中当前选定的筛选器的索引。 如果你有3条筛选器,这个值指定为2, 则打开对话框时默认显示的文件类型是第二条筛选器。 这个值还有一个重要的应用就是如果当我们设置了对话框回调函数时,这个值保存着用户的筛选器选择,有了他我们便可以知道用户选择文件的对应的扩展名。(在另存为对话框)
nMaxFile:以字符数计算,lpstrFile 所指向的缓冲区的大小。缓冲区必须足够大以存储的路径和文件名称字符串或字符串,包括终止 NULL 字符。缓冲区应至少 256 个字符长。
lpstrInitialDir:初始目录。留空由系统选择,但选择的初始目录的算法在不同系统上各不相同。
lpstrTitle:要放在对话框的标题栏中的字符串。如果此成员为 NULL,则系统使用默认标题 。
lpstrFile:用来初始化文件名称的文件名称的编辑控件。
当使用 GetOpenFileName时, 如过只允许选择单个文件,该缓冲区包含驱动器符、 路径、 文件名称和所选文件的扩展名, 如果设置可以多选文件,则lpstrFile 包含当前选择文件的目录,后面跟着对应所选的多个文件的文件名已经扩展名。
而当使用GetSaveFileName时,lpstrFile 只包含当前文件目录以及文件名,并没有包含文件扩展名,这是和打开文件对话框不同的地方,如果我们希望获取用户选择的对应文件的文件扩展名,需要通过设置lpfnHook 回调函数来获取这一参数,后面会说到。
Flags: 设置对话框风格标志位。如果希望实现多选文件,则可以设置标志位为

ofn.Flags = OFN_EXPLORER |OFN_ALLOWMULTISELECT;

一定要有OFN_EXPLOER, 否则窗口风格会变。下面上代码

int main()
{OPENFILENAME ofn = { 0 };TCHAR strFilename[MAX_PATH] = { 0 }; //用于接收文件名ofn.lStructSize = sizeof(OPENFILENAME);ofn.lpstrFile = strFilename;ofn.lpstrFilter =TEXT("Cpp(*.cpp)\0*.cpp*\0文本(*.txt)\0*.txt*\0图片(*.jpg)\0*.jpg*\0\0");ofn.nMaxFile = MAX_PATH;ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY |OFN_NOCHANGEDIR |OFN_PATHMUSTEXIST| OFN_ALLOWMULTISELECT;//ofn.lpfnHook = (LPOFNHOOKPROC)SaveAsHookPrc;TCHAR * pszFileName;CString szDirectory;CString szFileName;CStringArray szMultiFliePath; //如果允许多选,该array中记录着所有被选中的文件路径。if (GetOpenFileName(&ofn)){pszFileName = ofn.lpstrFile;szDirectory = pszFileName; //如果只允许单选, 缓冲区ofn.lpstrFile包含完整的文件路径(包括文件名以及扩展名)//如果允许多选,缓冲区ofn.lpstrFile指针包含内容分为两个部分,第一部分是选择文件所在的目录,第二部分是选择的所有文件名,每个文件名以“\0”作为分隔;//缓冲区中的最后一个字符串以两个空字符终止,因此可以通过移动指针来判断是否包含多个文件pszFileName = pszFileName + szDirectory.GetLength() + 1;while (*pszFileName){szFileName = pszFileName;szMultiFliePath.Add(szDirectory + pszFileName);pszFileName = pszFileName + szFileName.GetLength() + 1;}}return true;
}

“另存为”对话框的使用方法与“打开”对话框的使用方法类似,这里要重点说明的是如何获取另存为对话框的文件扩展名。因为使用GetSaveFileName() 如果用户没有键入文件的扩展名,ofn对象的文件缓冲区并不包含文件的扩展名,
如下图所示

如果用户不手动添加文件扩展名“.txt”,ofn.lpstrFile 文件缓冲区只能得到不包含文件扩展名的文件路径。
如果我们想实现自动根据用户选择的文件扩展来添加扩展名,可以通过添加回调函数到ofn.lpfnHook的方法来获取用户的选择的nFilterIndex. 其中nFilterIndex的值与 ofn.lpstrFilter 设定的顺序一样。例如,

ofn.lpstrFilter =TEXT("Cpp(*.cpp)\0*.cpp*\0文本(*.txt)\0*.txt*\0图片(*.jpg)\0*.jpg*\0\0");

当用户选择第一项(Cpp)时,nFilterIndex为1,选择第二项(文本)时,nFilterIndex =2, 以此类推。
当用户选择了不同的文件名扩展,windows会讲用户选择响应一个CDN_TYPECHANGE消息,而该消息包含在WM_NOTIFY中,同时CDN_TYPECHANGE消息包含一个指向OFNOTIFY的结构指针,该结构指针里包含了我们所需要的对象LPOPENFILENAMEA 指针。代码如下
设置nFlag 为

ofn.Flags = OFN_EXPLORER| OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK;

同时添加回调函数:CbGetFileExtension();

#include <afx.h>
#include <windows.h>
#include <commdlg.h>
#include <iostream>
#include <string>
#include <cstring>
using namespace std;static int g_nFilterIndex(0); // 记录用户选择的index.
void GetFilterInde(OFNOTIFY* pFile)
{switch (pFile->lpOFN->nFilterIndex){case 1:g_nFilterIndex = 1;break;case 2:g_nFilterIndex = 2;break;case 3:g_nFilterIndex = 3;break;default:break;}}
UINT_PTR CALLBACK CbGetFileExtension(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{switch (uMsg){case WM_NOTIFY:{   NMHDR *pHdr = (NMHDR*)lParam;switch (pHdr->code){case CDN_TYPECHANGE:GetFilterInde((OFNOTIFY*)pHdr);break;default:break;}break;}default:break;}return 0;
}
int main()
{OPENFILENAME ofn = { 0 };TCHAR strFilename[MAX_PATH] = { 0 };ofn.lStructSize = sizeof(OPENFILENAME);ofn.lpstrFile = strFilename;ofn.lpstrFilter = TEXT("Cpp(*.cpp)\0*.cpp*\0文本(*.txt)\0*.txt*\0图片(*.jpg)\0*.jpg*\0\0");ofn.nMaxFile = MAX_PATH;ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST |OFN_ENABLEHOOK;ofn.lpfnHook = &CbGetFileExtension; //添加回调函数CString szFilePath;CStringArray szMultiFliePath;if (GetSaveFileName(&ofn)){szFilePath = ofn.lpstrFile;switch (g_nFilterIndex){case 1:szFilePath = szFilePath + ".cpp";case 2:szFilePath = szFilePath + ".txt";break;case 3:szFilePath = szFilePath + ".jpg";break;default:break;}}return true;
}

[C++]Windows API 打开/另存为对话框文件路径以及扩展名的获取相关推荐

  1. Windows系统下常见的文件类型及其扩展名

    今天小陈给大家分享一本书上的一个实用表(常见的文件类型及其扩展名)

  2. 文件路径,文件名,扩展名 常用操作

    string filePath = @"E:\Randy0528\中文目录\JustTest.rar"; Response.Write("文件路径:"+file ...

  3. 强悍的命令行 —— basename 去掉路径和扩展名 dirname 获取路径

    sudo mkdir ~/test sudo touch !$/test.txt 1. basename 1.1 去掉路径 $ basename ~/test/test.txt test.txt 1. ...

  4. c语言删除文件 Windows,基于Windows API实现遍历所有文件并删除的方法

    本文实例讲述了基于Windows API实现遍历所有文件并删除的方法.分享给大家供大家参考.具体分析如下: 最近一直在学windows API,弄了一些好玩的东西(有点恶作剧了,请大家谨慎使用)... ...

  5. vb获取服务器文件路径,vb打开ftp服务器文件路径

    vb打开ftp服务器文件路径 内容精选 换一换 该任务指导用户使用Loader将数据从HDFS/OBS导出到SFTP服务器.创建或获取该任务中创建Loader作业的业务用户和密码.确保用户已授权访问作 ...

  6. Windows API的时间结构体、时间转换及时间获取

    Windows API的时间结构体.时间转换及时间获取   时间格式:DosDateTime <====>FileTime <====> SystemTime |        ...

  7. windows服务器设置文件属性设置去掉隐藏已知文件类型的扩展名(即文件后缀名可见)

    摘要: 1.文件后缀名不可见,系统运维过程容易发生同名不同后缀的文件操作混淆的情况 2.windows系统默认是文件后缀名不可见 3.所以需要更改一下配置. 4.操作步骤如下图: (1)点击组织-文件 ...

  8. 计算机如何把文件设为隐藏,已知文件类型的扩展名如何设置显示与隐藏?

    当你想把文件扩展名隐藏或是显示的时候,有木有突然感觉有那么一瞬间皱着眉头过呢?当你想要设置显示与隐藏扩展名的时候却莫名其妙的发现"隐藏已知文件类型的扩展名"这一项选不见了,心理莫名 ...

  9. NO21 Llinux的文件种类与扩展名--文件权限--软硬链接--Linux删除文件原理

    Linux的文件种类与扩展名 一.文件种类: 1.普通文件(regular file)第一个字符为[ - ] 包括: ①纯文本档(ASCII):这是Linux系统中最多的一种文件类型,称为纯文本档.是 ...

最新文章

  1. Twitter团队最新研究:快速高效的可扩展图神经网络SIGN
  2. Linux下ibus-sunpinyin的安装及翻页快捷键设置!
  3. solr5.5在centos7上的安装
  4. idea远程debug调试阿里云ECS
  5. android 全局 socket,学习Android socket通信之如何解决中文乱码
  6. python的指针跟c的区别_ctypes中的LP_x*指针和*p指针有什么区别?(以及与结构的奇怪交互)...
  7. 稳健估计/M估计/最小二乘法
  8. Go语言init函数你必须记住的六个特征
  9. 苹果iOS 13正式版推送:深色模式来了 速度再次提升!
  10. 搜狗输入法语音转文字的体验点
  11. GIMP基本功能和教程!
  12. TCP 协议报文格式
  13. 智工教育:公务员考试这些知识点你会背了吗?
  14. 自动驾驶硬件系统架构概述
  15. 中国涂料工业协会:世界十大涂料品牌2011年度报告
  16. 在线CAD平台,MxCAD云图 2021.01.20更新,在线CAD软件
  17. 面试笔记:面经-网易考拉
  18. html病毒DropFileName,王国平博客-HTML 感染 DropFileName = “svchost.exe” Ramnit 蠕虫病毒 查杀解决办法...
  19. 一种通过物理分离实现WSUS伸缩性的方案
  20. Pycharm2018永久破解方法

热门文章

  1. 二维等高线图转三维地形图
  2. 【Spring】Bean注册和注入
  3. mysql 查询条件是中文时,无法查询的解决办法
  4. linux 链接库文件出现“undefined reference to 问题的解决方法
  5. Android淘宝电影日期滚动栏的实现
  6. 通过亚马逊云新用户入门学习计划快速上手云上无服务器化的MySQL数据库
  7. 开发文档--编程规约
  8. 2020第五空间 hate-php rosb 交流
  9. 2022-2028年中国半导体测试设备行业市场专项调研及投资前景研究报告
  10. SQL Server中查询时显示行号的方法