LoginSignup
2
3

More than 5 years have passed since last update.

バッファが足りないと結果が切り捨てられる文字列取得関数を自動リトライするユーティリティ関数

Last updated at Posted at 2015-11-04

Windowsプログラミングをしていると、「バッファにめいっぱい文字列を取得し、バッファが足りなければ切り捨てます。取得できた文字数を返します」というインターフェースのAPIがたくさん出てきます。LoadStringだとかGetWindowTextだとか。事前に必要なバッファサイズがわからず、取得結果の文字数がバッファ一杯だったことで、「もしかして切り捨てられた残りがあるかも?」とわかるというインターフェース、出会うたびにうんざりさせられます。
バッファは何文字分確保しましょう? 十分に大きく? その十分っていくらですか…?

そのうんざりを解決してくれるユーティリティ関数challenge_get_stringを用意しましたのでお役立てください。
(引数..., バッファポインタ, バッファサイズ) -> 取得文字数 というシグネチャの関数を、全部取得できるまでバッファを拡大しながらリトライします。

文字の型(charwchar_tかでしょう)が指定必須の型パラメータで、残りの型パラメータ(関数ポインタの型、関数に渡す引数の型)は省略可能です。

// バッファが足りないと結果が切り捨てられる文字列取得関数を、バッファを拡大しながら呼び出し続けて全内容を取得します
template<typename TChar, typename PFunc, typename... TParams>
std::basic_string<TChar> challenge_get_string(PFunc f, TParams... params)
{
    vector<TChar> buf(256);
    size_t result_len;
    for (;; buf.resize(buf.size() * 2))
    {
        result_len = f(params..., buf.data(), buf.size());
        if (result_len < buf.size() - 1) break;
    }
    return std::basic_string<TChar>(buf.data(), result_len);
}

すると以下のようにLoadStringだとかGetWindowTextをスマートに呼び出せるわけです。

// ウィンドウのキャプションを取得します
std::wstring get_window_text(HWND hWnd)
{
    return challenge_get_string<wchar_t>(&GetWindowTextW, hWnd);
}

// リソースから文字列を取得します
std::wstring load_resource_string(UINT id)
{
    return challenge_get_string<wchar_t>(&LoadStringW, GetModuleHandle(NULL), id);
}

challenge_get_stringはC++汎用で書いてありますが、Windows開発に特化するならTCharを型引数にせずTCHAR決め打ちにした方がテンプレート引数が不要になってすっきりするかもしれません。std::stringstd::wstringUNICODEマクロに応じて使い分けるstd::tstringなんて自前で定義したりしつつ。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3