如何使SWIG处理c#中的utf8字符串
本文关键字:中的 utf8 字符串 处理 何使 SWIG | 更新日期: 2023-09-27 18:15:13
我正在编写一个可移植的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做得很好,除了在调用MyClass期间不进行utf8 <=> utf16字符串转换。
我该怎么办?编写自定义typemaps看起来有点复杂,如果这是唯一可用的解决方案,我需要帮助。
我可以这样回答我自己非常相似的问题。我认为(虽然我还没有测试),这可能适用于你的情况下,没有任何变化。唯一的区别是我使用std::string,而你使用char*,但我认为SWIG已经以相同的方式对待它们了。
在David Jeske在链接的Code Project文章中的帮助下(阅读:天才!),我终于能够回答这个问题了。
你需要在你的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;
}
}
然后,在Swig的"std_string。,在第24行替换这一行:
%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"
瞧,一切都正常。阅读链接的文章,以更好地理解这是如何工作的。