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

Skip to content

Commit 946b9a0

Browse files
committed
Add template to generate PInvoke-based implementation
1 parent 908f0f0 commit 946b9a0

File tree

5 files changed

+523
-670
lines changed

5 files changed

+523
-670
lines changed
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
using System;
2+
using System.Linq;
3+
using System.Runtime.InteropServices;
4+
using System.Text;
5+
6+
namespace Python.Runtime.Native
7+
{
8+
/// <summary>
9+
/// Abstract class defining boiler plate methods that
10+
/// Custom Marshalers will use.
11+
/// </summary>
12+
internal abstract class MarshalerBase : ICustomMarshaler
13+
{
14+
#if UCS2 && PYTHON2
15+
internal static Encoding PyEncoding = Encoding.Unicode;
16+
internal static int UCS = 2;
17+
#else
18+
internal static Encoding PyEncoding = Encoding.UTF32;
19+
internal static int UCS = 4;
20+
#endif
21+
22+
public object MarshalNativeToManaged(IntPtr pNativeData)
23+
{
24+
throw new NotImplementedException();
25+
}
26+
27+
public abstract IntPtr MarshalManagedToNative(object managedObj);
28+
29+
public void CleanUpNativeData(IntPtr pNativeData)
30+
{
31+
Marshal.FreeHGlobal(pNativeData);
32+
}
33+
34+
public void CleanUpManagedData(object managedObj)
35+
{
36+
// Let GC deal with it
37+
}
38+
39+
public int GetNativeDataSize()
40+
{
41+
return IntPtr.Size;
42+
}
43+
}
44+
45+
46+
/// <summary>
47+
/// Custom Marshaler to deal with Managed String to Native
48+
/// conversion differences on UCS2/UCS4.
49+
/// </summary>
50+
internal class UcsMarshaler : MarshalerBase
51+
{
52+
private static readonly MarshalerBase Instance = new UcsMarshaler();
53+
54+
public override IntPtr MarshalManagedToNative(object managedObj)
55+
{
56+
var s = managedObj as string;
57+
58+
if (s == null)
59+
{
60+
return IntPtr.Zero;
61+
}
62+
63+
byte[] bStr = PyEncoding.GetBytes(s + "\0");
64+
IntPtr mem = Marshal.AllocHGlobal(bStr.Length);
65+
try
66+
{
67+
Marshal.Copy(bStr, 0, mem, bStr.Length);
68+
}
69+
catch (Exception)
70+
{
71+
Marshal.FreeHGlobal(mem);
72+
throw;
73+
}
74+
75+
return mem;
76+
}
77+
78+
public static ICustomMarshaler GetInstance(string cookie)
79+
{
80+
return Instance;
81+
}
82+
83+
public static string PtrToStringUni(IntPtr p)
84+
{
85+
if (p == IntPtr.Zero)
86+
{
87+
return null;
88+
}
89+
90+
int size = GetUnicodeByteLength(p);
91+
var buffer = new byte[size];
92+
Marshal.Copy(p, buffer, 0, size);
93+
return PyEncoding.GetString(buffer, 0, size);
94+
}
95+
96+
public static int GetUnicodeByteLength(IntPtr p)
97+
{
98+
var len = 0;
99+
while (true)
100+
{
101+
#if UCS2 && PYTHON2
102+
int c = Marshal.ReadInt16(p, len * 2);
103+
#else
104+
int c = Marshal.ReadInt32(p, len * 4);
105+
#endif
106+
107+
if (c == 0)
108+
{
109+
return len * UCS;
110+
}
111+
checked
112+
{
113+
++len;
114+
}
115+
}
116+
}
117+
118+
/// <summary>
119+
/// Utility function for Marshaling Unicode on PY3 and AnsiStr on PY2.
120+
/// Use on functions whose Input signatures changed between PY2/PY3.
121+
/// Ex. Py_SetPythonHome
122+
/// </summary>
123+
/// <param name="s">Managed String</param>
124+
/// <returns>
125+
/// Ptr to Native String ANSI(PY2)/Unicode(PY3/UCS2)/UTF32(PY3/UCS4.
126+
/// </returns>
127+
/// <remarks>
128+
/// You MUST deallocate the IntPtr of the Return when done with it.
129+
/// </remarks>
130+
public static IntPtr Py3UnicodePy2StringtoPtr(string s)
131+
{
132+
#if PYTHON2
133+
return Marshal.StringToHGlobalAnsi(s);
134+
#else
135+
return Instance.MarshalManagedToNative(s);
136+
#endif
137+
}
138+
139+
/// <summary>
140+
/// Utility function for Marshaling Unicode IntPtr on PY3 and
141+
/// AnsiStr IntPtr on PY2 to Managed Strings. Use on Python functions
142+
/// whose return type changed between PY2/PY3.
143+
/// Ex. Py_GetPythonHome
144+
/// </summary>
145+
/// <param name="p">Native Ansi/Unicode/UTF32 String</param>
146+
/// <returns>
147+
/// Managed String
148+
/// </returns>
149+
public static string PtrToPy3UnicodePy2String(IntPtr p)
150+
{
151+
#if PYTHON2
152+
return Marshal.PtrToStringAnsi(p);
153+
#else
154+
return PtrToStringUni(p);
155+
#endif
156+
}
157+
}
158+
159+
160+
/// <summary>
161+
/// Custom Marshaler to deal with Managed String Arrays to Native
162+
/// conversion differences on UCS2/UCS4.
163+
/// </summary>
164+
internal class StrArrayMarshaler : MarshalerBase
165+
{
166+
private static readonly MarshalerBase Instance = new StrArrayMarshaler();
167+
168+
public override IntPtr MarshalManagedToNative(object managedObj)
169+
{
170+
var argv = managedObj as string[];
171+
172+
if (argv == null)
173+
{
174+
return IntPtr.Zero;
175+
}
176+
177+
int totalStrLength = argv.Sum(arg => arg.Length + 1);
178+
int memSize = argv.Length * IntPtr.Size + totalStrLength * UCS;
179+
180+
IntPtr mem = Marshal.AllocHGlobal(memSize);
181+
try
182+
{
183+
// Preparing array of pointers to strings
184+
IntPtr curStrPtr = mem + argv.Length * IntPtr.Size;
185+
for (var i = 0; i < argv.Length; i++)
186+
{
187+
byte[] bStr = PyEncoding.GetBytes(argv[i] + "\0");
188+
Marshal.Copy(bStr, 0, curStrPtr, bStr.Length);
189+
Marshal.WriteIntPtr(mem + i * IntPtr.Size, curStrPtr);
190+
curStrPtr += bStr.Length;
191+
}
192+
}
193+
catch (Exception)
194+
{
195+
Marshal.FreeHGlobal(mem);
196+
throw;
197+
}
198+
199+
return mem;
200+
}
201+
202+
public static ICustomMarshaler GetInstance(string cookie)
203+
{
204+
return Instance;
205+
}
206+
}
207+
208+
209+
/// <summary>
210+
/// Custom Marshaler to deal with Managed String to Native
211+
/// conversion on UTF-8. Use on functions that expect UTF-8 encoded
212+
/// strings like `PyUnicode_FromStringAndSize`
213+
/// </summary>
214+
/// <remarks>
215+
/// If instead we used `MarshalAs(UnmanagedType.LPWStr)` the output to
216+
/// `foo` would be `f\x00o\x00o\x00`.
217+
/// </remarks>
218+
internal class Utf8Marshaler : MarshalerBase
219+
{
220+
private static readonly MarshalerBase Instance = new Utf8Marshaler();
221+
private static new readonly Encoding PyEncoding = Encoding.UTF8;
222+
223+
public override IntPtr MarshalManagedToNative(object managedObj)
224+
{
225+
var s = managedObj as string;
226+
227+
if (s == null)
228+
{
229+
return IntPtr.Zero;
230+
}
231+
232+
byte[] bStr = PyEncoding.GetBytes(s + "\0");
233+
IntPtr mem = Marshal.AllocHGlobal(bStr.Length);
234+
try
235+
{
236+
Marshal.Copy(bStr, 0, mem, bStr.Length);
237+
}
238+
catch (Exception)
239+
{
240+
Marshal.FreeHGlobal(mem);
241+
throw;
242+
}
243+
244+
return mem;
245+
}
246+
247+
public static ICustomMarshaler GetInstance(string cookie)
248+
{
249+
return Instance;
250+
}
251+
}
252+
}

0 commit comments

Comments
 (0)