Win32 APIで使われるSTRRET
型の出力引数をstd::wstring
型で受け取るクラスのコードです。
// out_STRRET_into_wstring.hpp #include <string> // 同じwstringを受け取るインスタンスを同時に使用しないでください。 // 次のようなコードは不適切です。 // // std::wstring s1 {...}; // f(out_STRRET_into_wstring(s1), out_STRRET_into_wstring(s1)) // class out_STRRET_into_wstring { private: std::wstring& result; LPCITEMIDLIST pidl; STRRET sr; out_STRRET_into_wstring() = delete; out_STRRET_into_wstring(out_STRRET_into_wstring&) = delete; out_STRRET_into_wstring(out_STRRET_into_wstring&&) = delete; public: out_STRRET_into_wstring(std::wstring& result, LPCITEMIDLIST pidl = nullptr) : result{ result }, pidl{ pidl }, sr{} {} ~out_STRRET_into_wstring() { LPWSTR psz; if (SUCCEEDED(StrRetToStrW(&sr, pidl, &psz))) { try { result.assign(psz); } catch (...) { result.clear(); } CoTaskMemFree(psz); } else { result.clear(); } } constexpr operator STRRET* () { return &sr; } };
使用例
#include <iostream> #include <string> #pragma comment(lib, "shlwapi.lib") #define STRICT #define NOMINMAX #include <Windows.h> #include <ShlObj.h> #include <Shlwapi.h> #include <wil/com.h> #include "out_STRRET_into_wstring.hpp" using namespace std; using namespace wil; using unique_itemidlist = unique_any<LPITEMIDLIST, decltype(&CoTaskMemFree), &CoTaskMemFree>; int main() { auto coinit{ CoInitializeEx(COINIT_APARTMENTTHREADED) }; if (!coinit) return 0; com_ptr<IShellFolder> desktop; THROW_IF_FAILED(SHGetDesktopFolder(desktop.put())); com_ptr<IEnumIDList> enumIdList; THROW_IF_FAILED(desktop->EnumObjects(nullptr, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &enumIdList)); wcout.imbue(locale("japanese", locale::ctype)); for (;;) { unique_itemidlist pidl; ULONG fetched; HRESULT hr = enumIdList->Next(1, pidl.put(), &fetched); if (hr != S_OK) { THROW_IF_FAILED(hr); break; } wstring display_name; THROW_IF_FAILED(desktop->GetDisplayNameOf(pidl.get(), SHGDN_NORMAL, out_STRRET_into_wstring(display_name, pidl.get()))); wcout << display_name << endl; } }