如何使SWIG在C#中处理utf8字符串? [英] How to make SWIG deal with utf8 strings in C#?
问题描述
我正在编写一个可移植的C ++库,其中包含对其他语言(java,C#,python)的绑定.我正在 SWIG 的帮助下进行绑定.
I'm writing a portable C++ library with bindings to other languages (java, C#, python). I'm making those bindings with help of SWIG.
我有一个用C ++编写的类:
I have a class written in C++:
class MyClass
{
public:
const char* get_value() const; // returns utf8-string
void set_value(const char* value); // gets utf8-string
private:
// ...
};
在C#端我有类似的东西:
And I have something like that on C# side:
public class MyClass
{
public string get_value();
public void set_value(string value);
}
SWIG可以很好地完成所有工作,除了在调用MyClass的过程中不进行utf8 ltf =
SWIG does everything well, except that it doesn't make an utf8 <=> utf16 string conversion during the calls to MyClass.
我该怎么办?编写自定义类型映射看起来有些复杂,如果这是唯一可用的解决方案,我需要帮助.
What can I do with that? Writing a custom typemaps looks a bit complicated, and I need help with that if it is the only available solution.
推荐答案
I was able to answer my own very similar question as follows. I think (although I haven't tested) that this might work for your situation too with no changes. The only difference is that I'm using std::string, and you're using char*, but I think SWIG already treats these the same way.
在 David Jeske 在链接的代码项目"文章中,我终于能够回答这个问题.
With the help (read: genius!) of David Jeske in the linked Code Project article, I have finally been able to answer this question.
您将在C#库中需要此类(来自David Jeske的代码).
You'll need this class (from David Jeske's code) in your C# library.
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;
}
}
然后,在Swig的"std_string.i"的第24行中,替换此行:
Then, in Swig's "std_string.i", on line 24 replace this line:
%typemap(imtype) string "string"
有这行:
%typemap(imtype, inattributes="[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]", outattributes="[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]") string "string"
并在第61行上,替换此行:
and on line 61, replace this line:
%typemap(imtype) const string & "string"
有这行:
%typemap(imtype, inattributes="[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]", outattributes="[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]") string & "string"
瞧瞧,一切正常.阅读链接的文章,以更好地了解其工作原理.
Lo and behold, everything works. Read the linked article for a good understanding of how this works.
这篇关于如何使SWIG在C#中处理utf8字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!