Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e487076

Browse files
committed
Add ICustomMarshaler Utf8Marshaler
Refactor PyString_FromStringAndSize Link explains why `MarshalAs(UnmanagedType.LPWStr)` or `CharSet.Unicode` don't work http://stackoverflow.com/a/25128147/5208670
1 parent 74440a6 commit e487076

2 files changed

Lines changed: 51 additions & 17 deletions

File tree

src/runtime/CustomMarshaler.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,49 @@ public static ICustomMarshaler GetInstance(string cookie)
123123
return Instance;
124124
}
125125
}
126+
127+
128+
/// <summary>
129+
/// Custom Marshaler to deal with Managed String to Native
130+
/// conversion on UTF-8. Use on functions that expect UTF-8 encoded
131+
/// strings like `PyUnicode_FromStringAndSize`
132+
/// </summary>
133+
/// <remarks>
134+
/// If instead we used `MarshalAs(UnmanagedType.LPWStr)` the output to
135+
/// `foo` would be `f\x00o\x00o\x00`.
136+
/// </remarks>
137+
public class Utf8Marshaler : MarshalerBase
138+
{
139+
private static readonly MarshalerBase Instance = new Utf8Marshaler();
140+
private static readonly Encoding PyEncoding = Encoding.UTF8;
141+
142+
public override IntPtr MarshalManagedToNative(object managedObj)
143+
{
144+
var s = managedObj as string;
145+
146+
if (s == null)
147+
{
148+
return IntPtr.Zero;
149+
}
150+
151+
byte[] bStr = PyEncoding.GetBytes(s + "\0");
152+
IntPtr mem = Marshal.AllocHGlobal(bStr.Length);
153+
try
154+
{
155+
Marshal.Copy(bStr, 0, mem, bStr.Length);
156+
}
157+
catch (Exception)
158+
{
159+
Marshal.FreeHGlobal(mem);
160+
throw;
161+
}
162+
163+
return mem;
164+
}
165+
166+
public static ICustomMarshaler GetInstance(string cookie)
167+
{
168+
return Instance;
169+
}
170+
}
126171
}

src/runtime/runtime.cs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,23 +1508,12 @@ internal static IntPtr PyBytes_AS_STRING(IntPtr ob)
15081508
return ob + BytesOffset.ob_sval;
15091509
}
15101510

1511-
internal static IntPtr PyString_FromStringAndSize(string value, int length)
1512-
{
1513-
// copy the string into an unmanaged UTF-8 buffer
1514-
int len = Encoding.UTF8.GetByteCount(value);
1515-
byte[] buffer = new byte[len + 1];
1516-
Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, 0);
1517-
IntPtr nativeUtf8 = Marshal.AllocHGlobal(buffer.Length);
1518-
try
1519-
{
1520-
Marshal.Copy(buffer, 0, nativeUtf8, buffer.Length);
1521-
return PyUnicode_FromStringAndSize(nativeUtf8, length);
1522-
}
1523-
finally
1524-
{
1525-
Marshal.FreeHGlobal(nativeUtf8);
1526-
}
1527-
}
1511+
[DllImport(Runtime.dll, EntryPoint = "PyUnicode_FromStringAndSize")]
1512+
internal static extern IntPtr
1513+
PyString_FromStringAndSize(
1514+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string value,
1515+
int size
1516+
);
15281517

15291518
[DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
15301519
ExactSpelling = true, CharSet = CharSet.Unicode)]

0 commit comments

Comments
 (0)