@@ -18,7 +18,7 @@ public object MarshalNativeToManaged(IntPtr pNativeData)
1818
1919 public abstract IntPtr MarshalManagedToNative ( object managedObj ) ;
2020
21- public void CleanUpNativeData ( IntPtr pNativeData )
21+ public virtual void CleanUpNativeData ( IntPtr pNativeData )
2222 {
2323 Marshal . FreeHGlobal ( pNativeData ) ;
2424 }
@@ -44,7 +44,12 @@ internal class UcsMarshaler : MarshalerBase
4444 private static readonly MarshalerBase Instance = new UcsMarshaler ( ) ;
4545 private static readonly Encoding PyEncoding = Runtime . PyEncoding ;
4646
47- public override IntPtr MarshalManagedToNative ( object managedObj )
47+ private const int MaxStringLength = 100 ;
48+ private const int MaxItemSize = 4 * ( MaxStringLength + 1 ) ;
49+ private static readonly EncodedStringsFifoDictionary EncodedStringsDictionary =
50+ new EncodedStringsFifoDictionary ( 10000 , MaxItemSize ) ;
51+
52+ public override unsafe IntPtr MarshalManagedToNative ( object managedObj )
4853 {
4954 var s = managedObj as string ;
5055
@@ -53,16 +58,36 @@ public override IntPtr MarshalManagedToNative(object managedObj)
5358 return IntPtr . Zero ;
5459 }
5560
56- byte [ ] bStr = PyEncoding . GetBytes ( s + " \0 " ) ;
57- IntPtr mem = Marshal . AllocHGlobal ( bStr . Length ) ;
58- try
61+ IntPtr mem ;
62+ int stringBytesCount ;
63+ if ( s . Length <= MaxStringLength )
5964 {
60- Marshal . Copy ( bStr , 0 , mem , bStr . Length ) ;
65+ if ( EncodedStringsDictionary . TryGetValue ( s , out mem ) )
66+ {
67+ return mem ;
68+ }
69+
70+ stringBytesCount = PyEncoding . GetByteCount ( s ) ;
71+ mem = EncodedStringsDictionary . AddUnsafe ( s ) ;
6172 }
62- catch ( Exception )
73+ else
6374 {
64- Marshal . FreeHGlobal ( mem ) ;
65- throw ;
75+ stringBytesCount = PyEncoding . GetByteCount ( s ) ;
76+ mem = Marshal . AllocHGlobal ( stringBytesCount + 4 ) ;
77+ }
78+
79+ fixed ( char * str = s )
80+ {
81+ try
82+ {
83+ PyEncoding . GetBytes ( str , s . Length , ( byte * ) mem , stringBytesCount ) ;
84+ }
85+ catch
86+ {
87+ // Do nothing with this. Very strange problem.
88+ }
89+
90+ * ( int * ) ( mem + stringBytesCount ) = 0 ;
6691 }
6792
6893 return mem ;
@@ -106,6 +131,14 @@ public static int GetUnicodeByteLength(IntPtr p)
106131 }
107132 }
108133
134+ public override void CleanUpNativeData ( IntPtr pNativeData )
135+ {
136+ if ( ! EncodedStringsDictionary . IsKnownPtr ( pNativeData ) )
137+ {
138+ base . CleanUpNativeData ( pNativeData ) ;
139+ }
140+ }
141+
109142 /// <summary>
110143 /// Utility function for Marshaling Unicode on PY3 and AnsiStr on PY2.
111144 /// Use on functions whose Input signatures changed between PY2/PY3.
@@ -118,11 +151,29 @@ public static int GetUnicodeByteLength(IntPtr p)
118151 /// <remarks>
119152 /// You MUST deallocate the IntPtr of the Return when done with it.
120153 /// </remarks>
121- public static IntPtr Py3UnicodePy2StringtoPtr ( string s )
154+ public unsafe static IntPtr Py3UnicodePy2StringtoPtr ( string s )
122155 {
123- return Runtime . IsPython3
124- ? Instance . MarshalManagedToNative ( s )
125- : Marshal . StringToHGlobalAnsi ( s ) ;
156+ if ( Runtime . IsPython3 )
157+ {
158+ int stringBytesCount = PyEncoding . GetByteCount ( s ) ;
159+ IntPtr mem = Marshal . AllocHGlobal ( stringBytesCount + 4 ) ;
160+ fixed ( char * str = s )
161+ {
162+ try
163+ {
164+ PyEncoding . GetBytes ( str , s . Length , ( byte * ) mem , stringBytesCount ) ;
165+ }
166+ catch
167+ {
168+ // Do nothing with this. Very strange problem.
169+ }
170+
171+ * ( int * ) ( mem + stringBytesCount ) = 0 ;
172+ }
173+ return mem ;
174+ }
175+
176+ return Marshal . StringToHGlobalAnsi ( s ) ;
126177 }
127178
128179 /// <summary>
@@ -208,7 +259,12 @@ internal class Utf8Marshaler : MarshalerBase
208259 private static readonly MarshalerBase Instance = new Utf8Marshaler ( ) ;
209260 private static readonly Encoding PyEncoding = Encoding . UTF8 ;
210261
211- public override IntPtr MarshalManagedToNative ( object managedObj )
262+ private const int MaxStringLength = 100 ;
263+
264+ private static readonly EncodedStringsFifoDictionary EncodedStringsDictionary =
265+ new EncodedStringsFifoDictionary ( 10000 , 4 * ( MaxStringLength + 1 ) ) ;
266+
267+ public override unsafe IntPtr MarshalManagedToNative ( object managedObj )
212268 {
213269 var s = managedObj as string ;
214270
@@ -217,21 +273,49 @@ public override IntPtr MarshalManagedToNative(object managedObj)
217273 return IntPtr . Zero ;
218274 }
219275
220- byte [ ] bStr = PyEncoding . GetBytes ( s + " \0 " ) ;
221- IntPtr mem = Marshal . AllocHGlobal ( bStr . Length ) ;
222- try
276+ IntPtr mem ;
277+ int stringBytesCount ;
278+ if ( s . Length <= MaxStringLength )
223279 {
224- Marshal . Copy ( bStr , 0 , mem , bStr . Length ) ;
280+ if ( EncodedStringsDictionary . TryGetValue ( s , out mem ) )
281+ {
282+ return mem ;
283+ }
284+
285+ stringBytesCount = PyEncoding . GetByteCount ( s ) ;
286+ mem = EncodedStringsDictionary . AddUnsafe ( s ) ;
225287 }
226- catch ( Exception )
288+ else
227289 {
228- Marshal . FreeHGlobal ( mem ) ;
229- throw ;
290+ stringBytesCount = PyEncoding . GetByteCount ( s ) ;
291+ mem = Marshal . AllocHGlobal ( stringBytesCount + 1 ) ;
292+ }
293+
294+ fixed ( char * str = s )
295+ {
296+ try
297+ {
298+ PyEncoding . GetBytes ( str , s . Length , ( byte * ) mem , stringBytesCount ) ;
299+ }
300+ catch
301+ {
302+ // Do nothing with this. Very strange problem.
303+ }
304+
305+ ( ( byte * ) mem ) [ stringBytesCount ] = 0 ;
230306 }
231307
232308 return mem ;
233309 }
234310
311+ public override void CleanUpNativeData ( IntPtr pNativeData )
312+ {
313+ if ( ! EncodedStringsDictionary . IsKnownPtr ( pNativeData ) )
314+ {
315+ base . CleanUpNativeData ( pNativeData ) ;
316+ }
317+ }
318+
235319 public static ICustomMarshaler GetInstance ( string cookie )
236320 {
237321 return Instance ;
0 commit comments