最近写音乐播放器练手。音乐需要一个添加音乐文件的对话框,便在msdn上找到了一个新姿势,就是Common Item Dialog.
MSDN链接:http://msdn.microsoft.com/en-us/library/windows/desktop/bb776913(v=vs.85).aspx
按照msdn的说法,Common Item Dialog用来代替以前Common File Dialog去打开或保存文件。Common Item Dialog需要win vista以上操作系统, 拥有Open dialog 和 Save dialog.
先给出一个简单的例子,这个例子是我用来打开音乐文件的:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//打开文件窗口 std::vector<std::wstring> showOpenFile() { HRESULT hr = S_OK; std::vector<std::wstring> filePaths; IFileOpenDialog *fileDlg = NULL; hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&fileDlg)); if (FAILED(hr)) return filePaths; ON_SCOPE_EXIT([&] { fileDlg->Release(); }); IKnownFolderManager *pkfm = NULL; hr = CoCreateInstance(CLSID_KnownFolderManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pkfm)); if (FAILED(hr)) return filePaths; ON_SCOPE_EXIT([&] { pkfm->Release(); }); IKnownFolder *pKnownFolder = NULL; hr = pkfm->GetFolder(FOLDERID_PublicMusic, &pKnownFolder); if (FAILED(hr)) return filePaths; ON_SCOPE_EXIT([&] { pKnownFolder->Release(); }); IShellItem *psi = NULL; hr = pKnownFolder->GetShellItem(0, IID_PPV_ARGS(&psi)); if (FAILED(hr)) return filePaths; ON_SCOPE_EXIT([&] { psi->Release(); }); hr = fileDlg->AddPlace(psi, FDAP_BOTTOM); COMDLG_FILTERSPEC rgSpec[] = { { L"音乐文件", L"*.mp3;*.wav;" } }; fileDlg->SetFileTypes(1, rgSpec); DWORD dwOptions; fileDlg->GetOptions(&dwOptions); fileDlg->SetOptions(dwOptions | FOS_ALLOWMULTISELECT); hr = fileDlg->Show(NULL); if (SUCCEEDED(hr)) { IShellItemArray *pRets; hr = fileDlg->GetResults(&pRets); if (SUCCEEDED(hr)) { DWORD count; pRets->GetCount(&count); for (DWORD i = 0; i < count; i++) { IShellItem *pRet; LPWSTR nameBuffer; pRets->GetItemAt(i, &pRet); pRet->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &nameBuffer); filePaths.push_back(std::wstring(nameBuffer)); pRet->Release(); CoTaskMemFree(nameBuffer); } pRets->Release(); } } return filePaths; }
ps:我使用了头文件如下:
#include <Shlobj.h> #include <Shobjidl.h> #include <iostream> #include <vector>
该函数返回一个文件列表的容器,储存的文件的绝对路径。
其中ON_SCOPE_EXIT宏是引用http://www.cnblogs.com/fuzhe1989/p/3524249.html 中的资源管理。
大致说明如下:
- 创建一个IFileOpenDialog接口指针的实例 fileDlg。
- IKnownFolderManager *pkfm, IKnownFolder *pKnownFolder 两个接口是用来设置默认的路径的,此例把默认路径设置为用户目录下的音乐文件夹。
- 设置文件类型。这里用到了IFileOpenDialog接口的SetFileTypes方法,该方法参数如下:
HRESULT SetFileTypes( [in] UINT cFileTypes, [in] const COMDLG_FILTERSPEC *rgFilterSpec );
第一个参数 cFileTypes是第二个参数数组元素的个数。
参数 rgFilterSpec 用来设置文件类型,例如:
COMDLG_FILTERSPEC rgSpec[] = { { szJPG, L"*.jpg;*.jpeg" }, { szBMP, L"*.bmp" }, { szAll, L"*.*" }, };
- 因为本例添加音乐文件需要支持添加多个文件,因此设置允许选择多个文件。方法如下:
DWORD dwOptions; fileDlg->GetOptions(&dwOptions); fileDlg->SetOptions(dwOptions | FOS_ALLOWMULTISELECT);
- 接下来就可以调用IFileOpenDialog接口的Show()方法了。用户选择后,如果是单个文件,调用GetResult([out] IShellItem **ppsi)方法获得选中的文件,如果是选择了多个文件,调用GetResults([out] IShellItemArray **ppenum)方法。区别在于前者获取IShellItem接口,后者获取IShellItemArray接口。
IShellItemArray基本上就是IShellItem接口数组,根据其方法名字就很容易使用。因此说下IShellItem.
IShellItem可以看成将文件路径封装起来的接口,可以通过调用其GetDisplayName([in] SIGDN sigdnName, [out] LPWSTR *ppszName) 方法。第一个参数sigdnName决定了返回文件字符串的格式,此处我们使用SIGDN_DESKTOPABSOLUTEPARSING参数,返回文件的绝对路径。 不过要记得释放返回的字符串,释放方法为使用CoTaskMemFree()函数。
基本上到此就完成了我们的目的...不过确实..使用起来有点那么麻烦..所以我是自己封装成函数了..