2021/03/07
Windows ini ファイルは時代遅れという意見もあるが、構造がシンプルであることから素人手作業での取り回しがきわめて容易という利点は未だに失われていないと思います。
訳あって ini ファイルの読み込みを ANSI/UNICODE ポータブルに記述する必要があり、あとで参照するときの便利帳としてコードを置いておくことにします。
tstring
, tcout
, _TCHAR
, _T
マクロ等といったものの備忘録も兼ねています。
Windows 10 の場合。
GetPrivateProfileString
でキー(左辺)と値(右辺)を区切る区切り文字は '=' だけが有効。
GetPrivateProfileString
では、値の「文字数」を 32768 で割った余りと、バッファ長指定から1を減じた値の、どちらか短いほうまでの文字数が読み込まれる。
GetPrivateProfileString
では、値の「バイト数」を 65535 で割った余りと、バッファ長指定から1を減じた値の、どちらか短いほうまでの文字数が読み込まれる。一見仕様外に見えるが、2バイト文字を仮定すれば 32767「文字」+1バイトである。
GetPrivateProfileString
実行後の GetLastError()
がエラーコード 234 (ERROR_MORE_DATA: バッファ不足)を返してこないので、そういう尻切れを把握することはできない。
GetPrivateProfileSection
でも基本同じだが、このときバッファの確保長をキーの長さ+区切りだけ大きくしたバッファを用意しておかないと尻切れになる。しかし、それをいちいち確保するのは見通しが悪い。よって、キーの値(右辺)が欲しい場合は GetPrivateProfileSection
で得た要素から分離するのではなく GetPrivateProfileString
で読み込むのが正しい。
GetPrivateProfileSectionNames
は(十分確認できていないが)セクション名列挙の読み込み総文字数・総バイト数が用意したバッファに収まれば 64KiB 以遠のセクション名も見つけ出してくれる模様だが、GetPrivateProfileSection
では当該セクションの総文字数・総バイト数が用意したバッファに収まらない範囲のキー・値は見つけられないので、ini ファイル全体を巡回できない場合がある。その場合でもセクション名とキー名が両方とも既知ならば 64KiB 以遠でも GetPrivateProfileSection
で値を読むことはできる。…そもそもそんな馬鹿でかい(仕様外) ini ファイルを作るなというのはさておき。
GetPrivateProfileString
で「該当するキーが見つからなかった」という結果を明示的に知りたいときは、デフォルト文字列として CRLF を与えておけばよい。理由は、Win32API の ini file 関数群では行末 CRLF が行読み込みの時に取り除かれるため、読み込みが成功した場合に結果バッファに CRLF が入ってくることはあり得ないから。なお、キーが存在して値が空の場合は結果のバッファが空文字列となる( '\0'
のみが入る)ことで判別可能である。
この例では、読み込めた値は GetPrivateProfileSection
で得たものから左辺(キー)と右辺(値)の分離を行っているが、上記の通りこの処置はあまり良くない。値の取得はあくまで「存在しないセクションやキーのテスト」のコメントがある箇所のように GetPrivateProfileString
で行うのがベターである。
|
ちなみに ANSI/UNICODE 両対応において _T マクロは非ASCII文字を含む文字列リテラルに必須だが、ASCII文字だけでできている文字列リテラルには必須ではない模様です。
UNICODE
と _UNICODE
UNICODE コンパイルを指定するにあたり、マクロ UNICODE
と _UNICODE
のどっちを定義すればいいんだ?という疑問を調べたら、これらは対象物が違うので両方とも定義する必要がある。stackoverflow によると UNICODE
は Win32API 関係(~A と ~W の切り替え)、_UNICODE
は C/C++ runtime ヘッダ関係に寄与するとのこと。
具体的には cl /EHsc /MD /W4 /DUNICODE /D_UNICODE foobar.cpp
等とする。
今回の事例では、Win32API と CRT の両者にまたがる処置が必要なので、少なくとも片方が定義されていれば UNICODE コンパイルであると認識させるのが適切なようだ。
たしかこれと類似の話が TCHAR
と _TCHAR
の関係性にもあった気がする。
また TEXT()
と _T()
は異なるヘッダ(winnt.h と tchar.h)で定義されているため UNICODE
と _UNICODE
が片方しか定義されていない場合はヘッダによって挙動が異なってしまうので要注意。UNICODE
と _UNICODE
が両方とも定義されていれば実質的には同じになるとのこと。
_T()
と TEXT()
の違いやソースの文字コード - ホイール欲しい ハンドル欲しい
_T()
と TEXT()
の違いについて参考文献と本文記述を追加。
トップページ /
計算機関係の雑多なこと /
Windows ini file と ANSI/UNICODE ポータビリティー
このサイトについて・著者連絡先