Skip to content
 

Windows 2000でWideCharToMultiByte関数を使うと、ISO-2022-JPのバイト数を間違う

前回のUnicodeStringをJIS(ISO-2022-JP)に変換すると文字が減るの続き。

UnicodeStringをJISコードに変換すると文字が減るという問題です。

AnsiStringT<50220> jis1 = L"文字コード"; //=> 文字コ

Windows 2000におけるWin32APIのWideCharToMultiByte関数の動作がおかしいようです。
WideCharToMultiByte関数は、ISO-2022-JPに変換したときの正しいバイト数を返しません。

なお、Windows XP以降では問題ありませんでした。

次のソースコードは、ユニコード文字列をJIS(ISO-2022-JP)コードに変換したときのバイト数を取得する処理です。

const int codepage = 50220;
UnicodeString WCharSource = L"abcテスト";
int SrcChars = WCharSource.Length();
int DestBytes = WideCharToMultiByte(codepage, 0, WCharSource.c_str(), SrcChars, NULL, 0, NULL, NULL);

WideCharToMultiByte関数は、変換後の文字列を受け取るために必要なバッファのサイズ(バイト数)を返します。

上のコードでは12バイト必要ですが、この関数は「9」を返します。3バイト足りません。

3バイトというと、エスケープシーケンスが思い当たります。
JISコードではエスケープシーケンスを用いて、文字集合を切り替えます。

エスケープシーケンスの計算が正しいか試してみました。

const int codepage = 50222;
UnicodeString WCharSource = L"abcテストabc";
int SrcChars = WCharSource.Length();
int DestBytes = WideCharToMultiByte(codepage, 0, WCharSource.c_str(), SrcChars, NULL, 0, NULL, NULL);

WideCharToMultiByte関数は「12」を返します。6バイト足りません。

const int codepage = 50220;
UnicodeString WCharSource = L"abcテストabcテスト";
int SrcChars = WCharSource.Length();
int DestBytes = WideCharToMultiByte(codepage, 0, WCharSource.c_str(), SrcChars, NULL, 0, NULL, NULL);

WideCharToMultiByte関数は「18」を返します。9バイト足りません。
やはりエスケープシーケンスが考慮されていないようです。

原因がわかりましたので、対策も簡単です。
Windows2000でISO-2022-JPに変換するときはバッファを多めにとればいいのです。

さて、問題のUnicodeStringからAnsiStringT<50220>への変換ですが、 System.pasの_LStrFromPWCharLen関数かCharFromWChar関数で、 文字のバイト数を取得するときに、 OSがWindows2000かつコードページが50220ならば、 バッファのバイト数を増やして文字を取得し、取得後に不要な部分を切り捨てればいいと思います。
とても汚いコードになりそうです。

調べてみると、同じような問題に遭遇している方がいらっしゃいました。
komatの古往今来: ALM2Thunderbird 1.0の動作OSについて」では、Windows 2000環境で変換に失敗するという問題に遭遇されています。
「Windows API関数のWideCharToMultiByteとMultiByteToWideCharの動作に問題がある」とありますが、おそらく同じ問題でしょう。

関連記事:

  1. Windows XPでWideCharToMultiByte関数を使い、ISO-2022-JPに変換するときの注意点
  2. UnicodeStringをJIS(ISO-2022-JP)に変換すると文字が減る
  3. RawByteStringの動作のテスト
  4. AnsiStringTの代入の挙動を調べる
  5. AnsiStringTのコンストラクタの挙動を調べる

2 Comments

  1. 【バグ】WideCharToMultiByte の動作がOSごとに違う!

    Windows 2000でWideCharToMultiByte関数を使うと、ISO-2022-JPのバイト数を間違う という記事を見かけたので、調べてみたところ、もっと深い違いがあったのでまとめてみました。

  2. Windows XPでWideCharToMultiByte関数を使い、ISO-2022-JPに変換するときの注意点

    前回の記事「Windows 2000でWideCharToMultiByte関数を使うと、ISO-2022-JPのバイト数を間違う」では、
    Windows 2000におけるWideCharToMultiByte関数の問題を調べました。

    今回はWideCharToMultiByte関数のWindows XP…

Leave a Reply