www.digitalmars.com D | English
Last update Sun Feb 6 2005

WindowsでUTFを使う

Dの文字列は、UTF文字列です。 Microsoft Windows の API は通常、入力文字列の受け取り方に応じて、 関数ごとに二つのバージョン - "A" バージョンと "W" バージョンが用意されています。"W" バージョンは UTF-16 を文字列引数の形式として受け取るので、D の wchar[] 文字列と直接対応します。

しかし、比較的初期の Windows では、 多くのAPI関数の "W" バージョンが実装されていません。 かといって、"A" バージョンを使うのも問題があります。"A" バージョンは 環境ごとの様々な文字エンコード方式を扱うので、 UTF-8 形式である D の char[] 文字列と、 直接の互換性を持っていないのです。

この問題に対処する正しい方法は、まず、"W" バージョンに対応した バージョンの Windows であるかどうか判別し、非対応であれば、 wchar[] 文字列を "A" バージョンで扱える形式に変換することです。 この方法は Phobos ランタイムライブラリで使用されており、 以下のようになっています:

private import std.c.windows.windows;
private import std.utf;

int useWfuncs = 1;

static this()
{
    // Win 95, 98, ME では W 関数は実装されていない
    useWfuncs = (GetVersion() < 0x80000000);
}

char* toMBSz(char[] s)
{
    // 最上位ビットが立っている文字があるときのみ変換が必要
    foreach (char c; s)
    {
        if (c >= 0x80)
        {   char[] result;
            int i;
            wchar* ws = std.utf.toUTF16z(s);
            result.length = WideCharToMultiByte(0, 0, ws, -1, null, 0, null, null);
            i = WideCharToMultiByte(0, 0, ws, -1, result, result.length, null, null);
            assert(i == result.length);
            return result;
        }
    }
    return std.string.toStringz(s);
}

uint getAttributes(char[] name)
{
    uint result;

    if (useWfuncs)
        result = GetFileAttributesW(std.utf.toUTF16z(name));
    else
        result = GetFileAttributesA(toMBSz(name));
    return result;
}