2013-05-25 16 views
5

Diğer dillere (java, C#, python) bağlanabilen taşınabilir bir C++ kütüphanesi yazıyorum. Bu bağlamaları SWIG yardımıyla yapıyorum.C# utf8 dizeleriyle SWIG anlaşması nasıl yapılır?

C++ ile yazılmış bir sınıf var:

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

Ve C# tarafında böyle bir şey var:

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

yudum bir utf8 yapmaz dışında her şeyi iyi yapar < => MySlass çağrıları sırasında utf16 dize dönüşümü.

Bununla ne yapabilirim? Özel bir typemaps yazmak biraz karmaşık görünüyor ve eğer mevcut tek çözüm ise bu konuda yardıma ihtiyacım var.

cevap

4

my own very similar question ürününü aşağıdaki gibi cevaplayabiliyorum. Sanırım (test etmediğim halde) bunun durumunuz için de hiçbir değişiklik olmadan çalışabileceğini düşünüyorum. Tek fark, std :: string kullanıyorum ve char * kullanıyor olmanızdır, ancak SWIG'in bunları da aynı şekilde ele aldığını düşünüyorum.

Bağlantılı Kodlar Proje makalesinde bulunan David Jeske yardım (read: genius!) Yardımı ile, bu soruyu en sonunda yanıtlayabildim.

C# kitaplığınızda bu sınıfa (David Jeske'nin kodundan) ihtiyacınız olacak.

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

ve hat 61 üzerinde

, bu satırı değiştirin: bu hat ile

%typemap(imtype) string "string" 

: Bu satırı yerine hat 24 yudum yönettiği "std_string.i", içinde Sonra

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

, Bu satırda:

%typemap(imtype) const string & "string" 

Bu satırda:

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

Her şey işe yarıyor. Bunun nasıl çalıştığını iyi anlamak için bağlantılı makaleyi okuyun.