Windows7でVB6のStrConv関数を使ってSJISからUnicodeへ変換するときに発生する問題

問題

Windows7になってAPIの挙動が変わったせいなのか、VB6 の StrConv関数の挙動が WindowsXP の頃と変わっている。*1

Shift-JIS を扱うプログラムではバイト単位に文字列を操作したいという要求が多いので、例えば「先頭5バイト」などといった場合、次のような書き方が多いと思う。 StrConv( LeftB ( StrConv ( [originalStrings], vbUniCode), 5), vbFromUnicode) Vista まではこれで問題がないのだけど、Windows7ではStrconv関数内部で呼び出されているAPIの挙動が変化したので、これで抽出した場合でも2バイト文字の先頭1バイトは残ってしまう。VistaまではStrconv関数の処理結果として2バイト文字の先頭だけが残るようなケースでは、その部分を除去してくれていたのだけどWindows7ではそうならずにそのまま返却されてくるんだよねぇ。

てすとぶろぐ: Windows 7 における VB6 の Strconv 関数の挙動

上記と同じ理由で以下のような「ANSI/SJIS表現で任意のバイトに収まる文字列を切り出す」*2処理で問題が発生する。

' 文字列"abcあいう"から、「ANSI/SJISで6バイト」に収まる範囲を切り出す
strconv(midb(strconv("abcあいう", vbFromUnicode), 1, 6), vbUnicode)

このコードでは文字列("abcあいう")から6バイト切り出したとき、その末尾に2バイト文字である"い"の先頭バイトだけが含まれる状態となる。WindowsXPで上記コードを実行したときは、そのような変換できない文字はNULL文字(&h0000)に変換されていた。しかし、Windows7では"・"(&h30FB)に置換されてしまう。

それぞれ実行結果をみてみる。

実行結果(WindowsXP):

? strconv(midb(strconv("abcあいう", vbFromUnicode), 1, 6), vbUnicode)
abcあ

実行結果(Windows7):

? strconv(midb(strconv("abcあいう", vbFromUnicode), 1, 6), vbUnicode)
abcあ・

というように、Windows7では末尾に余計な"・"が付加されてしまい。ANSI/SJISに変換したとき6バイトに収まらない内容になってしまい、いろいろなトラブルの元となってしまう。

解決

この問題の解決策として、StrConv関数に代わるものを作ってみた。関数の作成にあたっては、以下のページがたいへん参考になった。
Classic VB - Does Visual Basic 6 support Unicode? - VBForums

実行してみる。

実行結果(Windows7):

? StrConvToUnicode(midb(strconv("abcあいう", vbFromUnicode), 1, 6))
abcあ

*1:Vistaでは確認していないためよくわからない。が、ネットの情報によるとWindows7から挙動が変わっているっぽい。

*2:VB6では文字列の内部表現はUnicode(UTF-16)となっているので、上記のように一旦 ロケールに応じた ANSI/DBCS の表現に変換した後、任意のバイト数で切り出し、再度 Unicode のバイト列に戻すという方法を取る。