如何使SWIG处理C#中的utf8字符串?

时间:2013-05-25 13:08:51

标签: c# utf-8 swig

我正在编写一个可移植的C ++库,其中包含与其他语言(java,C#,python)的绑定。我正在SWIG的帮助下制作这些绑定。

我有一个用C ++编写的类:

class MyClass
{
public:
    const char* get_value() const;              // returns utf8-string
    void        set_value(const char* value);   // gets utf8-string
private:
    // ...
};

我在C#方面有类似的东西:

public class MyClass
{
    public string get_value();
    public void   set_value(string value);
}

SWIG做得很好,除了它没有制作utf8< =>调用MyClass时的utf16字符串转换。

我该怎么办?编写自定义类型映射看起来有点复杂,如果它是唯一可用的解决方案,我需要帮助。

1 个答案:

答案 0 :(得分:5)

我能够回答my own very similar question如下。我认为(虽然我没有经过测试),这可能对您的情况有效,没有任何变化。唯一的区别是我使用std :: string,并且您正在使用char *,但我认为SWIG已经以同样的方式对待它们。

在链接的Code Project文章中David Jeske的帮助(阅读:天才!),我终于能够回答这个问题了。

您需要在C#库中使用此课程(来自David Jeske的代码)。

public class UTF8Marshaler : ICustomMarshaler {
    static UTF8Marshaler static_instance;

    public IntPtr MarshalManagedToNative(object managedObj) {
        if (managedObj == null)
            return IntPtr.Zero;
        if (!(managedObj is string))
            throw new MarshalDirectiveException(
                   "UTF8Marshaler must be used on a string.");

        // not null terminated
        byte[] strbuf = Encoding.UTF8.GetBytes((string)managedObj); 
        IntPtr buffer = Marshal.AllocHGlobal(strbuf.Length + 1);
        Marshal.Copy(strbuf, 0, buffer, strbuf.Length);

        // write the terminating null
        Marshal.WriteByte(buffer + strbuf.Length, 0); 
        return buffer;
    }

    public unsafe object MarshalNativeToManaged(IntPtr pNativeData) {
        byte* walk = (byte*)pNativeData;

        // find the end of the string
        while (*walk != 0) {
            walk++;
        }
        int length = (int)(walk - (byte*)pNativeData);

        // should not be null terminated
        byte[] strbuf = new byte[length];  
        // skip the trailing null
        Marshal.Copy((IntPtr)pNativeData, strbuf, 0, length); 
        string data = Encoding.UTF8.GetString(strbuf);
        return data;
    }

    public void CleanUpNativeData(IntPtr pNativeData) {
        Marshal.FreeHGlobal(pNativeData);            
    }

    public void CleanUpManagedData(object managedObj) {
    }

    public int GetNativeDataSize() {
        return -1;
    }

    public static ICustomMarshaler GetInstance(string cookie) {
        if (static_instance == null) {
            return static_instance = new UTF8Marshaler();
        }
        return static_instance;
    }
}

然后,在第24行的Swig" std_string.i"中替换此行:

%typemap(imtype) string "string"

这一行:

%typemap(imtype, inattributes="[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]", outattributes="[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]") string "string"

并在第61行上,替换此行:

%typemap(imtype) const string & "string"

这一行:

%typemap(imtype, inattributes="[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]", outattributes="[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]") string & "string"

瞧,一切正常。阅读链接的文章,以便更好地了解其工作原理。