フォルダ選択ダイアログ

プロジェクトディレクトリの作成時に標準のフォルダ選択ダイアログを使おうと思って、テストしてました。
使い方忘れがちなのでメモ。

#define NOMINMAX
#include <boost/shared_ptr.hpp>
#include <stdexcept>
#include <windows.h>
#include <shlobj.h>
#include <hamigaki/detail/windows/com_library.hpp>

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "user32.lib")

using namespace hamigaki::detail::windows;

// 「マイドキュメント」のパスを取得する
std::string get_documents_path()
{
    char buf[MAX_PATH];
    if (::SHGetSpecialFolderPathA(0, buf, CSIDL_PERSONAL, FALSE) == FALSE)
        throw std::runtime_error("failed SHGetSpecialFolderPath()");
    return buf;
}

// 初期選択フォルダ指定のためのコールバック関数
int CALLBACK browse_folder_callback(
    ::HWND hwnd, ::UINT uMsg, ::LPARAM lParam, ::LPARAM lpData)
{
    if (uMsg == BFFM_INITIALIZED)
        ::SendMessageA(hwnd, BFFM_SETSELECTION, TRUE, lpData);
    return 0;
}

#include <iostream>

int main()
{
    try
    {
        const com_library using_com;

        const std::string& docs = get_documents_path();

        ::BROWSEINFOA info = {};
        info.lpszTitle = "Select the location of the project:";
        info.ulFlags = BIF_RETURNONLYFSDIRS;
        info.lpfn = &browse_folder_callback;
        info.lParam = reinterpret_cast< ::LPARAM>(docs.c_str());

        boost::shared_ptr< ::ITEMIDLIST> folder(
            ::SHBrowseForFolderA(&info), &CoTaskMemFree
        );
        if (folder.get() == 0)
            return 0;

        char buf[MAX_PATH];
        if (::SHGetPathFromIDListA(folder.get(), buf))
            std::cout << buf << std::endl;
    }
    catch (const std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }
}