マネージドコードとアンマネージドコードで文字列をやり取りする際、 UnitySendMessage
や MarshalAs(UnmanagedType.LPStr)
を利用することが多いと思いますが、この際、文字列のエンコーディングを考えないと文字化けを起こします。
UnitySendMessage
や MarshalAs(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;
}
}
}
メモリのアドレスから、バイト配列としてマーシャリングし、マネージドなバイト列からエンコーディングを指定して文字列を取得します。