LoginSignup
7
5

More than 5 years have passed since last update.

Unity でアンマネージドな文字列の扱いに気をつけよう

Posted at

マネージドコードとアンマネージドコードで文字列をやり取りする際、 UnitySendMessageMarshalAs(UnmanagedType.LPStr) を利用することが多いと思いますが、この際、文字列のエンコーディングを考えないと文字化けを起こします。

UnitySendMessageMarshalAs(UnmanagedType.LPStr) はデバイスの locale に依存してエンコードが行われます。元の文字列が UTF-8 で iOS や Android デバイスなら問題無いですが、日本語に設定されている Windows Phone だと UTF-8 のバイト列を CP932 としてエンコードしてしまいます。

様々なデバイスでアンマネージドな文字列を正しく取得するためには、次のような方法が考えられます。

C#
[DllImport(LIBNAME)] static extern IntPtr get_string_ptr();
[DllImport(LIBNAME)] static extern void get_rawdata(IntPtr ptr, out IntPtr data, out Int32 size);
[DllImport(LIBNAME)] static extern void purge_string_ptr(IntPtr ptr);

void Sample() {
    string text = null;

    var ptr = get_string_ptr();
    if (ptr != IntPtr.Zero) {
        IntPtr data;
        Int32 size;
        get_rawdata(ptr, out data, out size);

        if (data != IntPtr.Zero && size > 0) {
            var buffer = new byte[(int)size];
            Marshal.Copy(data, buffer, 0, (int)size);
            text = Text.Encoding.UTF8.GetString(buffer);
        }
        purge_string_ptr(ptr);
    }
    Debug.Log("text: " + text);
}
C++
extern "C" {
    const string *get_string_ptr() {
        return new string("ほげほげ : utf-8 string");
    }

    void get_rawdata(const string *ptr, const void **data, int32_t *size) {
        *data = nullptr;
        *size = 0;
        if (ptr) {
            *data = ptr->data();
            *size = ptr->size();
        }
    }

    void purge_string_ptr(string *ptr) {
        if (ptr) {
            delete ptr;
        }
    }
}

メモリのアドレスから、バイト配列としてマーシャリングし、マネージドなバイト列からエンコーディングを指定して文字列を取得します。

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5