@@ -18,7 +18,7 @@ public object MarshalNativeToManaged(IntPtr pNativeData)
18
18
19
19
public abstract IntPtr MarshalManagedToNative ( object managedObj ) ;
20
20
21
- public void CleanUpNativeData ( IntPtr pNativeData )
21
+ public virtual void CleanUpNativeData ( IntPtr pNativeData )
22
22
{
23
23
Marshal . FreeHGlobal ( pNativeData ) ;
24
24
}
@@ -44,7 +44,12 @@ internal class UcsMarshaler : MarshalerBase
44
44
private static readonly MarshalerBase Instance = new UcsMarshaler ( ) ;
45
45
private static readonly Encoding PyEncoding = Runtime . PyEncoding ;
46
46
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 )
48
53
{
49
54
var s = managedObj as string ;
50
55
@@ -53,16 +58,36 @@ public override IntPtr MarshalManagedToNative(object managedObj)
53
58
return IntPtr . Zero ;
54
59
}
55
60
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 )
59
64
{
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 ) ;
61
72
}
62
- catch ( Exception )
73
+ else
63
74
{
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 ;
66
91
}
67
92
68
93
return mem ;
@@ -106,6 +131,14 @@ public static int GetUnicodeByteLength(IntPtr p)
106
131
}
107
132
}
108
133
134
+ public override void CleanUpNativeData ( IntPtr pNativeData )
135
+ {
136
+ if ( ! EncodedStringsDictionary . IsKnownPtr ( pNativeData ) )
137
+ {
138
+ base . CleanUpNativeData ( pNativeData ) ;
139
+ }
140
+ }
141
+
109
142
/// <summary>
110
143
/// Utility function for Marshaling Unicode on PY3 and AnsiStr on PY2.
111
144
/// Use on functions whose Input signatures changed between PY2/PY3.
@@ -118,11 +151,29 @@ public static int GetUnicodeByteLength(IntPtr p)
118
151
/// <remarks>
119
152
/// You MUST deallocate the IntPtr of the Return when done with it.
120
153
/// </remarks>
121
- public static IntPtr Py3UnicodePy2StringtoPtr ( string s )
154
+ public unsafe static IntPtr Py3UnicodePy2StringtoPtr ( string s )
122
155
{
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 ) ;
126
177
}
127
178
128
179
/// <summary>
@@ -208,7 +259,12 @@ internal class Utf8Marshaler : MarshalerBase
208
259
private static readonly MarshalerBase Instance = new Utf8Marshaler ( ) ;
209
260
private static readonly Encoding PyEncoding = Encoding . UTF8 ;
210
261
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 )
212
268
{
213
269
var s = managedObj as string ;
214
270
@@ -217,21 +273,49 @@ public override IntPtr MarshalManagedToNative(object managedObj)
217
273
return IntPtr . Zero ;
218
274
}
219
275
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 )
223
279
{
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 ) ;
225
287
}
226
- catch ( Exception )
288
+ else
227
289
{
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 ;
230
306
}
231
307
232
308
return mem ;
233
309
}
234
310
311
+ public override void CleanUpNativeData ( IntPtr pNativeData )
312
+ {
313
+ if ( ! EncodedStringsDictionary . IsKnownPtr ( pNativeData ) )
314
+ {
315
+ base . CleanUpNativeData ( pNativeData ) ;
316
+ }
317
+ }
318
+
235
319
public static ICustomMarshaler GetInstance ( string cookie )
236
320
{
237
321
return Instance ;
0 commit comments