2013-05-25 29 views
5

Tôi đang viết một thư viện C++ di động với các ràng buộc với các ngôn ngữ khác (java, C#, python). Tôi đang thực hiện những ràng buộc đó với sự giúp đỡ của SWIG.Làm thế nào để giao dịch SWIG với chuỗi utf8 trong C#?

Tôi có một lớp học viết bằng C++:

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

Và tôi có một cái gì đó như thế trên C# bên:

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

SWIG làm mọi thứ tốt, ngoại trừ việc nó không làm cho một utf8 < => chuyển đổi chuỗi utf16 trong các cuộc gọi đến MyClass.

Tôi có thể làm gì với điều đó? Viết một typemaps tùy chỉnh trông hơi phức tạp, và tôi cần trợ giúp với nó nếu nó là giải pháp duy nhất có sẵn.

Trả lời

4

Tôi có thể trả lời my own very similar question như sau. Tôi nghĩ rằng (mặc dù tôi đã không thử nghiệm) rằng điều này có thể làm việc cho tình hình của bạn quá với không có thay đổi. Sự khác biệt duy nhất là tôi đang sử dụng std :: string, và bạn đang sử dụng char *, nhưng tôi nghĩ SWIG đã xử lý những điều này theo cùng một cách.

Với sự trợ giúp (đọc: thiên tài!) Của David Jeske trong bài viết về Dự án mã được liên kết, cuối cùng tôi đã có thể trả lời câu hỏi này.

Bạn sẽ cần lớp này (từ mã của David Jeske) trong thư viện C# của bạn.

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; 
    } 
} 

Sau đó, trong "std_string.i" Uống một lân, trên dòng 24 thay thế dòng này:

%typemap(imtype) string "string" 

với dòng này:

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

và trên đường 61, thay thế dòng này :

%typemap(imtype) const string & "string" 

với dòng này:

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

Xin xem mọi thứ hoạt động. Đọc bài viết được liên kết để hiểu rõ cách thức hoạt động của tính năng này.

Các vấn đề liên quan