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. Pingback: 黒翼猫のコンピュータ日記 2nd Edition

  2. Pingback: 山本隆の開発日誌

  3. Pingback: C++Builder 2010のIndyでメール送信について « 山本隆の開発日誌

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください