potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。

C++20&Win API Win APIで文字列をA/W変換する

Win APIMultiByteToWideChar関数、WideCharToMultiByte関数でstringwstringを相互変換するコードです。テストはしていません。

C++20からは標準ライブラリのコンバーターが非推奨なので自作するか外部ライブラリを使用する必要があります。

#include <bit>
#include <string>

#define STRICT
#define NOMINMAX
#include <Windows.h>

namespace stdw32
{
    std::wstring to_wstring(std::string_view s, DWORD flags = 0)
    {
        auto ret = ::MultiByteToWideChar(CP_ACP, 0, std::bit_cast<LPCCH>(s.data()),
            s.size(), nullptr, 0);
        if (ret == 0) return {};
        std::wstring buf(ret, L'\0');
        ret = ::MultiByteToWideChar(CP_ACP, 0, std::bit_cast<LPCCH>(s.data()),
            s.size(), buf.data(), ret);
        return std::move(buf);
    }

    std::wstring to_wstring(std::u8string_view s, DWORD flags = 0)
    {
        auto ret = ::MultiByteToWideChar(CP_UTF8, 0, std::bit_cast<LPCCH>(s.data()),
            s.size(), nullptr, 0);
        if (ret == 0) return {};
        std::wstring buf(ret, L'\0');
        ret = ::MultiByteToWideChar(CP_UTF8, 0, std::bit_cast<LPCCH>(s.data()),
            s.size(), buf.data(), ret);
        if (ret == 0) return {};
        return std::move(buf);
    }

    std::string to_string(
        std::wstring_view s,
        DWORD flags = 0,
        std::string_view defChar = {},
        LPBOOL usedDefChar = nullptr)
    {
        auto ret = ::WideCharToMultiByte(CP_ACP, 0, s.data(), s.size(),
            nullptr, 0, defChar.data(), usedDefChar);
        if (ret == 0) return {};
        std::string buf(ret, L'\0');
        ret = ::WideCharToMultiByte(CP_ACP, 0, s.data(), s.size(),
            buf.data(), ret, defChar.data(), usedDefChar);
        if (ret == 0) return {};
        return std::move(buf);
    }

    std::u8string to_u8string(
        std::wstring_view s,
        DWORD flags = 0,
        std::string_view defChar = {},
        LPBOOL usedDefChar = nullptr)
    {
        auto ret = ::WideCharToMultiByte(CP_UTF8, 0, s.data(), s.size(),
            nullptr, 0, defChar.data(), usedDefChar);
        if (ret == 0) return {};
        std::u8string buf(ret, L'\0');
        ret = ::WideCharToMultiByte(CP_UTF8, 0, s.data(), s.size(),
            std::bit_cast<char*>(buf.data()), ret, defChar.data(), usedDefChar);
        if (ret == 0) return {};
        return std::move(buf);
    }
}

int main()
{
    auto s1{ stdw32::to_wstring("abcあ🍎") };
    auto s2{ stdw32::to_wstring(u8"abcあ🍎") };
    auto s3{ stdw32::to_string(L"abcあ🍎") };
    auto s4{ stdw32::to_u8string(L"abcあ🍎") };

    return 0;
}