Windowsプログラミングをしていると、「バッファにめいっぱい文字列を取得し、バッファが足りなければ切り捨てます。取得できた文字数を返します」というインターフェースのAPIがたくさん出てきます。LoadString
だとかGetWindowText
だとか。事前に必要なバッファサイズがわからず、取得結果の文字数がバッファ一杯だったことで、「もしかして切り捨てられた残りがあるかも?」とわかるというインターフェース、出会うたびにうんざりさせられます。
バッファは何文字分確保しましょう? 十分に大きく? その十分っていくらですか…?
そのうんざりを解決してくれるユーティリティ関数challenge_get_string
を用意しましたのでお役立てください。
(引数..., バッファポインタ, バッファサイズ) -> 取得文字数
というシグネチャの関数を、全部取得できるまでバッファを拡大しながらリトライします。
文字の型(char
かwchar_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::string
とstd::wstring
をUNICODE
マクロに応じて使い分けるstd::tstring
なんて自前で定義したりしつつ。