自护意识

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

最近写音乐播放器练手。音乐需要一个添加音乐文件的对话框,便在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.

 

先给出一个简单的例子,这个例子是我用来打开音乐文件的:

    //打开文件窗口
    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;
    }
View Code

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()函数。

基本上到此就完成了我们的目的...不过确实..使用起来有点那么麻烦..所以我是自己封装成函数了..

 

 

posted on 2014-01-22 10:04  自护意识  阅读(1029)  评论(0编辑  收藏  举报