iooiau.net

LoadString() の便利な使い方

LoadString() 関数はリソースから文字列を読み込む関数ですが、あまり知られていない[要出典]使い方があります。

LoadString() で文字列を読み込む際、通常は以下のように固定長のバッファを確保して読み込むことが多いと思います。


TCHAR szText[256];
LoadString(hInstance, IDS_TEXT, szText, sizeof(szText) / sizeof(TCHAR));

この場合、読み込む文字列の最大長が予め分かっていることが前提になります。
では、任意の長さの文字列を読み込むにはどうすればいいでしょうか。

LoadString() は戻り値でコピーした長さ(終端ナル文字を含まない)を返すので、バッファが不足していた場合はバッファを増やして再度読み込んでみるという方法もあります。
そのようなことをしようとしている例(ただし、このコードは間違っているので実際には意図通りに動作しない)

しかし、そんなことをしなくても直接的に文字列を読み込む方法があります。

LoadString() の最後の引数(バッファ長)を0にすると、リソースのデータへのポインタを直接返してくれます。


LPCTSTR pText;
int Length = LoadString(hInstance, IDS_TEXT, (LPTSTR)&pText, 0);
/* pText に長さ Length の文字列へのポインタが返ってくる */

この仕様を利用する上で二つ注意点があります。

一つ目は、返されたバッファに書き込みを行ってはいけません。
const なポインタを渡すようにしましょう。
また、ここで返されるメモリ領域はプロセスの終了時に OS によって解放されるので、プログラム側では解放しません。

二つ目は、ここで返ってくる文字列はナル終端されていません。
正確にいえば、リソーススクリプトに書いた文字列がそのまま返されるので、リソーススクリプトで明示的にナル終端していればナル終端されているし、そうでなければナル終端されていないということです。


STRINGTABLE
BEGIN
    1 "ナル終端されていない"
    2 "ナル終端されている\0"
END

これを見ると使いづらい感じがしますが、LoadString() で読み込んだ文字列を std::string や std::string_view などに詰めたい場合に便利に使えます。


LPCTSTR pText;
int Length = LoadString(hInstance, IDS_TEXT, (LPTSTR)&pText, 0);
// string のコンストラクタで指定する
std::basic_string<TCHAR> String(pText, Length);
// もしくは assign で代入する
String.assign(pText, Length);
// string_view にも入れられる
std::basic_string_view<TCHAR> View(pText, Length);