-
Notifications
You must be signed in to change notification settings - Fork 751
Refactor Managed-Native conversion - ICustomMarshaler #407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6667669
d01f25f
74440a6
e487076
ccd4521
07f87de
edafdf2
78939c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
|
||
namespace Python.Runtime | ||
{ | ||
/// <summary> | ||
/// Abstract class defining boiler plate methods that | ||
/// Custom Marshalers will use. | ||
/// </summary> | ||
public abstract class MarshalerBase : ICustomMarshaler | ||
{ | ||
public object MarshalNativeToManaged(IntPtr pNativeData) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public abstract IntPtr MarshalManagedToNative(object managedObj); | ||
|
||
public void CleanUpNativeData(IntPtr pNativeData) | ||
{ | ||
Marshal.FreeHGlobal(pNativeData); | ||
} | ||
|
||
public void CleanUpManagedData(object managedObj) | ||
{ | ||
// Let GC deal with it | ||
} | ||
|
||
public int GetNativeDataSize() | ||
{ | ||
return IntPtr.Size; | ||
} | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Custom Marshaler to deal with Managed String to Native | ||
/// conversion differences on UCS2/UCS4. | ||
/// </summary> | ||
public class StrMarshaler : MarshalerBase | ||
{ | ||
private static readonly MarshalerBase Instance = new StrMarshaler(); | ||
private static readonly Encoding PyEncoding = Runtime.PyEncoding; | ||
|
||
public override IntPtr MarshalManagedToNative(object managedObj) | ||
{ | ||
var s = managedObj as string; | ||
|
||
if (s == null) | ||
{ | ||
return IntPtr.Zero; | ||
} | ||
|
||
byte[] bStr = PyEncoding.GetBytes(s + "\0"); | ||
IntPtr mem = Marshal.AllocHGlobal(bStr.Length); | ||
try | ||
{ | ||
Marshal.Copy(bStr, 0, mem, bStr.Length); | ||
} | ||
catch (Exception) | ||
{ | ||
Marshal.FreeHGlobal(mem); | ||
throw; | ||
} | ||
|
||
return mem; | ||
} | ||
|
||
public static ICustomMarshaler GetInstance(string cookie) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the purpose of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its part of the implementation of the interface. On the link below scroll down to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Our old There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh, i see on Mono: // The Utf32Marshaler was written Jonathan Pryor and has been placed in the PUBLIC DOMAIN. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @vmuriart so is custom marshalling dependent on COM interop now?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. I think that line is in reference that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is previous Mono implemented Marshalled string not a null-terminating like you added here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. because it didn't do the |
||
{ | ||
return Instance; | ||
} | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Custom Marshaler to deal with Managed String Arrays to Native | ||
/// conversion differences on UCS2/UCS4. | ||
/// </summary> | ||
public class StrArrayMarshaler : MarshalerBase | ||
{ | ||
private static readonly MarshalerBase Instance = new StrArrayMarshaler(); | ||
private static readonly Encoding PyEncoding = Runtime.PyEncoding; | ||
|
||
public override IntPtr MarshalManagedToNative(object managedObj) | ||
{ | ||
var argv = managedObj as string[]; | ||
|
||
if (argv == null) | ||
{ | ||
return IntPtr.Zero; | ||
} | ||
|
||
int totalStrLength = argv.Sum(arg => arg.Length + 1); | ||
int memSize = argv.Length * IntPtr.Size + totalStrLength * Runtime.UCS; | ||
|
||
IntPtr mem = Marshal.AllocHGlobal(memSize); | ||
try | ||
{ | ||
// Preparing array of pointers to strings | ||
IntPtr curStrPtr = mem + argv.Length * IntPtr.Size; | ||
for (var i = 0; i < argv.Length; i++) | ||
{ | ||
byte[] bStr = PyEncoding.GetBytes(argv[i] + "\0"); | ||
Marshal.Copy(bStr, 0, curStrPtr, bStr.Length); | ||
Marshal.WriteIntPtr(mem + i * IntPtr.Size, curStrPtr); | ||
curStrPtr += bStr.Length; | ||
} | ||
} | ||
catch (Exception) | ||
{ | ||
Marshal.FreeHGlobal(mem); | ||
throw; | ||
} | ||
|
||
return mem; | ||
} | ||
|
||
public static ICustomMarshaler GetInstance(string cookie) | ||
{ | ||
return Instance; | ||
} | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Custom Marshaler to deal with Managed String to Native | ||
/// conversion on UTF-8. Use on functions that expect UTF-8 encoded | ||
/// strings like `PyUnicode_FromStringAndSize` | ||
/// </summary> | ||
/// <remarks> | ||
/// If instead we used `MarshalAs(UnmanagedType.LPWStr)` the output to | ||
/// `foo` would be `f\x00o\x00o\x00`. | ||
/// </remarks> | ||
public class Utf8Marshaler : MarshalerBase | ||
{ | ||
private static readonly MarshalerBase Instance = new Utf8Marshaler(); | ||
private static readonly Encoding PyEncoding = Encoding.UTF8; | ||
|
||
public override IntPtr MarshalManagedToNative(object managedObj) | ||
{ | ||
var s = managedObj as string; | ||
|
||
if (s == null) | ||
{ | ||
return IntPtr.Zero; | ||
} | ||
|
||
byte[] bStr = PyEncoding.GetBytes(s + "\0"); | ||
IntPtr mem = Marshal.AllocHGlobal(bStr.Length); | ||
try | ||
{ | ||
Marshal.Copy(bStr, 0, mem, bStr.Length); | ||
} | ||
catch (Exception) | ||
{ | ||
Marshal.FreeHGlobal(mem); | ||
throw; | ||
} | ||
|
||
return mem; | ||
} | ||
|
||
public static ICustomMarshaler GetInstance(string cookie) | ||
{ | ||
return Instance; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no exception throwing here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what you mean? like re-throwing the
Exception
? That part was meant to de-allocate the memory in case something goes wrong, otherwise keep it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't failing on Marshal.Copy need to be thrown as Exception? If not, how is this handled later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll
throw
the exception again.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the throw in the latest commit