2013-05-25 15 views
5

Piszę przenośną bibliotekę C++ z powiązaniami z innymi językami (java, C#, python). Tworzę te wiązania za pomocą SWIG.Jak utworzyć transakcję SWIG z ciągami utf8 w języku C#?

Mam klasy napisany w C++:

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

I mam coś takiego w C# strony:

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

SWIG robi wszystko dobrze, poza tym, że nie robi się utf8 < => Konwersja ciągu utf16 podczas wywołań do MyClass.

Co mogę z tym zrobić? Napisanie niestandardowej mapy wygląda nieco skomplikowanie i potrzebuję pomocy, jeśli jest to jedyne dostępne rozwiązanie.

Odpowiedz

4

Udało mi się odpowiedzieć w następujący sposób: my own very similar question. Wydaje mi się (chociaż nie testowałem), że może to również zadziałać w twojej sytuacji, bez żadnych zmian. Jedyną różnicą jest to, że używam std :: string i korzystasz z char *, ale myślę, że SWIG traktuje je już tak samo.

Dzięki pomocy (czytaj: geniusz!) Z David Jeske w dołączonym artykule Code Project, w końcu byłem w stanie odpowiedzieć na to pytanie.

Będziesz potrzebować tej klasy (z kodu Davida Jeskego) w bibliotece C#.

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

Następnie w łyk za "std_string.i", na linii 24 zastąpić ten wiersz:

%typemap(imtype) string "string" 

z tej linii:

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

a na linii 61, zastąpi tę linię :

%typemap(imtype) const string & "string" 

z tym wierszem:

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

Lo i oto, wszystko działa. Przeczytaj połączony artykuł, aby dobrze zrozumieć, jak to działa.

Powiązane problemy