PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/_ctypes/_ctypes.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 766 lines | 534 code | 138 blank | 94 comment | 91 complexity | 0257ab1eb17c204359a6be3a48bf8a63 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.ComponentModel;
  19. using System.Reflection;
  20. using System.Reflection.Emit;
  21. using System.Runtime.CompilerServices;
  22. using System.Runtime.InteropServices;
  23. using System.Security;
  24. using System.Security.Permissions;
  25. using System.Threading;
  26. using Microsoft.Scripting.Runtime;
  27. using IronPython.Runtime;
  28. using IronPython.Runtime.Operations;
  29. using IronPython.Runtime.Types;
  30. #if CLR2
  31. using Microsoft.Scripting.Math;
  32. #else
  33. using System.Numerics;
  34. #endif
  35. #if !SILVERLIGHT
  36. [assembly: PythonModule("_ctypes", typeof(IronPython.Modules.CTypes))]
  37. namespace IronPython.Modules {
  38. /// <summary>
  39. /// Provides support for interop with native code from Python code.
  40. /// </summary>
  41. public static partial class CTypes {
  42. private static readonly object _lock = new object(); // lock for creating dynamic module for unsafe code
  43. private static readonly object _pointerTypeCacheKey = new object(); // key for system state for the pointer type cache
  44. private static readonly object _conversion_mode = new object(); // key for system state current conversion mode
  45. private static Dictionary<object, RefCountInfo> _refCountTable; // dictionary used to maintain a ref count on objects
  46. private static ModuleBuilder _dynamicModule; // the dynamic module we generate unsafe code into
  47. private static Dictionary<int, Type> _nativeTypes = new Dictionary<int, Type>(); // native types of the specified size for marshalling
  48. private static StringAtDelegate _stringAt = StringAt, _wstringAt = WStringAt; // delegates for wchar/char functions we hand addresses out to (just keeping it alive)
  49. private static CastDelegate _cast = Cast; // delegate for cast function whose address we hand out (just keeping it alive)
  50. public const string __version__ = "1.1.0";
  51. [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  52. private delegate IntPtr CastDelegate(IntPtr data, IntPtr obj, IntPtr type);
  53. [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  54. private delegate IntPtr StringAtDelegate(IntPtr addr, int length);
  55. [SpecialName]
  56. public static void PerformModuleReload(PythonContext/*!*/ context, PythonDictionary/*!*/ dict) {
  57. context.EnsureModuleException("ArgumentError", dict, "ArgumentError", "_ctypes");
  58. context.EnsureModuleException("COMError", dict, "COMError", "_ctypes");
  59. // TODO: Provide an implementation which is coordinated with our _refCountTable
  60. context.SystemState.__dict__["getrefcount"] = null;
  61. PythonDictionary pointerTypeCache = new PythonDictionary();
  62. dict["_pointer_type_cache"] = pointerTypeCache;
  63. context.SetModuleState(_pointerTypeCacheKey, pointerTypeCache);
  64. if (Environment.OSVersion.Platform == PlatformID.Win32NT ||
  65. Environment.OSVersion.Platform == PlatformID.Win32S ||
  66. Environment.OSVersion.Platform == PlatformID.Win32Windows ||
  67. Environment.OSVersion.Platform == PlatformID.WinCE) {
  68. context.SetModuleState(_conversion_mode, PythonTuple.MakeTuple("mbcs", "ignore"));
  69. } else {
  70. context.SetModuleState(_conversion_mode, PythonTuple.MakeTuple("ascii", "strict"));
  71. }
  72. }
  73. #region Public Functions
  74. /// <summary>
  75. /// Gets a function which casts the specified memory. Because this is used only
  76. /// w/ Python API we use a delegate as the return type instead of an actual address.
  77. /// </summary>
  78. public static object _cast_addr {
  79. get {
  80. return Marshal.GetFunctionPointerForDelegate(_cast).ToPython();
  81. }
  82. }
  83. /// <summary>
  84. /// Implementation of our cast function. data is marshalled as a void*
  85. /// so it ends up as an address. obj and type are marshalled as an object
  86. /// so we need to unmarshal them.
  87. /// </summary>
  88. private static IntPtr Cast(IntPtr data, IntPtr obj, IntPtr type) {
  89. GCHandle objHandle = GCHandle.FromIntPtr(obj);
  90. GCHandle typeHandle = GCHandle.FromIntPtr(type);
  91. try {
  92. CData cdata = objHandle.Target as CData;
  93. PythonType pt = (PythonType)typeHandle.Target;
  94. CData res = (CData)pt.CreateInstance(pt.Context.SharedContext);
  95. if (IsPointer(pt)) {
  96. res._memHolder = new MemoryHolder(IntPtr.Size);
  97. if (IsPointer(DynamicHelpers.GetPythonType(cdata))) {
  98. res._memHolder.WriteIntPtr(0, cdata._memHolder.ReadIntPtr(0));
  99. } else {
  100. res._memHolder.WriteIntPtr(0, data);
  101. }
  102. if (cdata != null) {
  103. res._memHolder.Objects = cdata._memHolder.Objects;
  104. res._memHolder.AddObject(IdDispenser.GetId(cdata), cdata);
  105. }
  106. } else {
  107. if (cdata != null) {
  108. res._memHolder = new MemoryHolder(data, ((INativeType)pt).Size, cdata._memHolder);
  109. } else {
  110. res._memHolder = new MemoryHolder(data, ((INativeType)pt).Size);
  111. }
  112. }
  113. return GCHandle.ToIntPtr(GCHandle.Alloc(res));
  114. } finally {
  115. typeHandle.Free();
  116. objHandle.Free();
  117. }
  118. }
  119. private static bool IsPointer(PythonType pt) {
  120. SimpleType simpleType;
  121. return pt is PointerType || ((simpleType = pt as SimpleType) != null && (simpleType._type == SimpleTypeKind.Pointer || simpleType._type == SimpleTypeKind.CharPointer || simpleType._type == SimpleTypeKind.WCharPointer));
  122. }
  123. public static object _memmove_addr {
  124. get {
  125. return NativeFunctions.GetMemMoveAddress().ToPython();
  126. }
  127. }
  128. public static object _memset_addr {
  129. get {
  130. return NativeFunctions.GetMemSetAddress().ToPython();
  131. }
  132. }
  133. public static object _string_at_addr {
  134. get {
  135. return Marshal.GetFunctionPointerForDelegate(_stringAt).ToPython();
  136. }
  137. }
  138. public static object _wstring_at_addr {
  139. get {
  140. return Marshal.GetFunctionPointerForDelegate(_wstringAt).ToPython();
  141. }
  142. }
  143. public static int CopyComPointer(object src, object dest) {
  144. throw new NotImplementedException("CopyComPointer");
  145. }
  146. public static string FormatError() {
  147. return FormatError(get_last_error());
  148. }
  149. public static string FormatError(int errorCode) {
  150. return new Win32Exception(errorCode).Message;
  151. }
  152. public static void FreeLibrary(int handle) {
  153. FreeLibrary(new IntPtr(handle));
  154. }
  155. public static void FreeLibrary(BigInteger handle) {
  156. FreeLibrary(new IntPtr((long)handle));
  157. }
  158. public static void FreeLibrary(IntPtr handle) {
  159. NativeFunctions.FreeLibrary(handle);
  160. }
  161. public static object LoadLibrary(string library, [DefaultParameterValue(0)]int mode) {
  162. IntPtr res = NativeFunctions.LoadDLL(library, mode);
  163. if (res == IntPtr.Zero) {
  164. throw PythonOps.OSError("cannot load library {0}", library);
  165. }
  166. return res.ToPython();
  167. }
  168. // Provided for Posix compat.
  169. public static object dlopen(string library, [DefaultParameterValue(0)]int mode) {
  170. return LoadLibrary(library, mode);
  171. }
  172. /// <summary>
  173. /// Returns a new type which represents a pointer given the existing type.
  174. /// </summary>
  175. public static PythonType POINTER(CodeContext/*!*/ context, PythonType type) {
  176. PythonContext pc = PythonContext.GetContext(context);
  177. PythonDictionary dict = (PythonDictionary)pc.GetModuleState(_pointerTypeCacheKey);
  178. lock (dict) {
  179. object res;
  180. if (!dict.TryGetValue(type, out res)) {
  181. string name;
  182. if (type == null) {
  183. name = "c_void_p";
  184. } else {
  185. name = "LP_" + type.Name;
  186. }
  187. dict[type] = res = MakePointer(context, name, PythonOps.MakeDictFromItems(new object[] { type, "_type_" }));
  188. }
  189. return res as PythonType;
  190. }
  191. }
  192. private static PointerType MakePointer(CodeContext context, string name, PythonDictionary dict) {
  193. return new PointerType(context,
  194. name,
  195. PythonTuple.MakeTuple(_Pointer),
  196. dict
  197. );
  198. }
  199. public static PythonType POINTER(CodeContext/*!*/ context, [NotNull]string name) {
  200. PythonType res = MakePointer(context, name, new PythonDictionary());
  201. PythonContext pc = PythonContext.GetContext(context);
  202. PythonDictionary dict = (PythonDictionary)pc.GetModuleState(_pointerTypeCacheKey);
  203. lock (dict) {
  204. dict[Builtin.id(res)] = res;
  205. }
  206. return res;
  207. }
  208. /// <summary>
  209. /// Converts an address acquired from PyObj_FromPtr or that has been
  210. /// marshaled as type 'O' back into an object.
  211. /// </summary>
  212. public static object PyObj_FromPtr(IntPtr address) {
  213. GCHandle handle = GCHandle.FromIntPtr(address);
  214. object res = handle.Target;
  215. handle.Free();
  216. return res;
  217. }
  218. /// <summary>
  219. /// Converts an object into an opaque address which can be handed out to
  220. /// managed code.
  221. /// </summary>
  222. public static IntPtr PyObj_ToPtr(object obj) {
  223. return GCHandle.ToIntPtr(GCHandle.Alloc(obj));
  224. }
  225. /// <summary>
  226. /// Decreases the ref count on an object which has been increased with
  227. /// Py_INCREF.
  228. /// </summary>
  229. public static void Py_DECREF(object key) {
  230. EnsureRefCountTable();
  231. lock (_refCountTable) {
  232. RefCountInfo info;
  233. if (!_refCountTable.TryGetValue(key, out info)) {
  234. // dec without an inc
  235. throw new InvalidOperationException();
  236. }
  237. info.RefCount--;
  238. if (info.RefCount == 0) {
  239. info.Handle.Free();
  240. _refCountTable.Remove(key);
  241. }
  242. }
  243. }
  244. /// <summary>
  245. /// Increases the ref count on an object ensuring that it will not be collected.
  246. /// </summary>
  247. public static void Py_INCREF(object key) {
  248. EnsureRefCountTable();
  249. lock (_refCountTable) {
  250. RefCountInfo info;
  251. if (!_refCountTable.TryGetValue(key, out info)) {
  252. _refCountTable[key] = info = new RefCountInfo();
  253. // TODO: this only works w/ blittable types, what to do for others?
  254. info.Handle = GCHandle.Alloc(key, GCHandleType.Pinned);
  255. }
  256. info.RefCount++;
  257. }
  258. }
  259. // for testing purposes only
  260. public static PythonTuple _buffer_info(CData data) {
  261. return data.GetBufferInfo();
  262. }
  263. public static void _check_HRESULT(int hresult) {
  264. if (hresult < 0) {
  265. throw PythonOps.WindowsError("ctypes function returned failed HRESULT: {0}", PythonOps.Hex((BigInteger)(uint)hresult));
  266. }
  267. }
  268. public static void _unpickle() {
  269. }
  270. /// <summary>
  271. /// returns address of C instance internal buffer.
  272. ///
  273. /// It is the callers responsibility to ensure that the provided instance will
  274. /// stay alive if memory in the resulting address is to be used later.
  275. /// </summary>
  276. public static object addressof(CData data) {
  277. return data._memHolder.UnsafeAddress.ToPython();
  278. }
  279. /// <summary>
  280. /// Gets the required alignment of the given type.
  281. /// </summary>
  282. public static int alignment(PythonType type) {
  283. INativeType nativeType = type as INativeType;
  284. if (nativeType == null) {
  285. throw PythonOps.TypeError("this type has no size");
  286. }
  287. return nativeType.Alignment;
  288. }
  289. /// <summary>
  290. /// Gets the required alignment of an object.
  291. /// </summary>
  292. public static int alignment(object o) {
  293. return alignment(DynamicHelpers.GetPythonType(o));
  294. }
  295. public static object byref(CData instance, [DefaultParameterValue(0)]int offset) {
  296. if (offset != 0) {
  297. // new in 2.6
  298. throw new NotImplementedException("byref w/ arg");
  299. }
  300. return new NativeArgument(instance, "P");
  301. }
  302. public static object call_cdeclfunction(CodeContext context, int address, PythonTuple args) {
  303. return call_cdeclfunction(context, new IntPtr(address), args);
  304. }
  305. public static object call_cdeclfunction(CodeContext context, BigInteger address, PythonTuple args) {
  306. return call_cdeclfunction(context, new IntPtr((long)address), args);
  307. }
  308. public static object call_cdeclfunction(CodeContext context, IntPtr address, PythonTuple args) {
  309. CFuncPtrType funcType = GetFunctionType(context, FUNCFLAG_CDECL);
  310. _CFuncPtr func = (_CFuncPtr)funcType.CreateInstance(context, address);
  311. return PythonOps.CallWithArgsTuple(func, new object[0], args);
  312. }
  313. public static void call_commethod() {
  314. }
  315. public static object call_function(CodeContext context, int address, PythonTuple args) {
  316. return call_function(context, new IntPtr(address), args);
  317. }
  318. public static object call_function(CodeContext context, BigInteger address, PythonTuple args) {
  319. return call_function(context, new IntPtr((long)address), args);
  320. }
  321. public static object call_function(CodeContext context, IntPtr address, PythonTuple args) {
  322. CFuncPtrType funcType = GetFunctionType(context, FUNCFLAG_STDCALL);
  323. _CFuncPtr func = (_CFuncPtr)funcType.CreateInstance(context, address);
  324. return PythonOps.CallWithArgsTuple(func, new object[0], args);
  325. }
  326. private static CFuncPtrType GetFunctionType(CodeContext context, int flags) {
  327. // Ideally we should cache these...
  328. SimpleType resType = new SimpleType(
  329. context,
  330. "int",
  331. PythonTuple.MakeTuple(DynamicHelpers.GetPythonTypeFromType(typeof(SimpleCData))), PythonOps.MakeHomogeneousDictFromItems(new object[] { "i", "_type_" }));
  332. CFuncPtrType funcType = new CFuncPtrType(
  333. context,
  334. "func",
  335. PythonTuple.MakeTuple(DynamicHelpers.GetPythonTypeFromType(typeof(_CFuncPtr))),
  336. PythonOps.MakeHomogeneousDictFromItems(new object[] { FUNCFLAG_STDCALL, "_flags_", resType, "_restype_" }));
  337. return funcType;
  338. }
  339. public static int get_errno() {
  340. return 0;
  341. }
  342. public static int get_last_error() {
  343. return Marshal.GetLastWin32Error();
  344. }
  345. /// <summary>
  346. /// Returns a pointer instance for the given CData
  347. /// </summary>
  348. public static Pointer pointer(CodeContext/*!*/ context, CData data) {
  349. PythonType ptrType = POINTER(context, DynamicHelpers.GetPythonType(data));
  350. return (Pointer)ptrType.CreateInstance(context, data);
  351. }
  352. public static void resize(CData obj, int newSize) {
  353. if (newSize < obj.NativeType.Size) {
  354. throw PythonOps.ValueError("minimum size is {0}", newSize);
  355. }
  356. MemoryHolder newMem = new MemoryHolder(newSize);
  357. obj._memHolder.CopyTo(newMem, 0, Math.Min(obj._memHolder.Size, newSize));
  358. obj._memHolder = newMem;
  359. }
  360. public static PythonTuple/*!*/ set_conversion_mode(CodeContext/*!*/ context, string encoding, string errors) {
  361. // TODO: Need an atomic update for module state
  362. PythonContext pc = PythonContext.GetContext(context);
  363. PythonTuple prev = (PythonTuple)pc.GetModuleState(_conversion_mode);
  364. pc.SetModuleState(_conversion_mode, PythonTuple.MakeTuple(encoding, errors));
  365. return prev;
  366. }
  367. public static void set_errno() {
  368. }
  369. public static void set_last_error(int errorCode) {
  370. NativeFunctions.SetLastError(errorCode);
  371. }
  372. public static int @sizeof(PythonType/*!*/ type) {
  373. INativeType simpleType = type as INativeType;
  374. if (simpleType == null) {
  375. throw PythonOps.TypeError("this type has no size");
  376. }
  377. return simpleType.Size;
  378. }
  379. public static int @sizeof(object/*!*/ instance) {
  380. CData cdata = instance as CData;
  381. if (cdata != null && cdata._memHolder != null) {
  382. return cdata._memHolder.Size;
  383. }
  384. return @sizeof(DynamicHelpers.GetPythonType(instance));
  385. }
  386. #endregion
  387. #region Public Constants
  388. public const int FUNCFLAG_STDCALL = 0;
  389. public const int FUNCFLAG_CDECL = 1;
  390. public const int FUNCFLAG_HRESULT = 2;
  391. public const int FUNCFLAG_PYTHONAPI = 4;
  392. public const int FUNCFLAG_USE_ERRNO = 8;
  393. public const int FUNCFLAG_USE_LASTERROR = 16;
  394. public const int RTLD_GLOBAL = 0;
  395. public const int RTLD_LOCAL = 0;
  396. #endregion
  397. #region Implementation Details
  398. /// <summary>
  399. /// Gets the ModuleBuilder used to generate our unsafe call stubs into.
  400. /// </summary>
  401. private static ModuleBuilder DynamicModule {
  402. get {
  403. if (_dynamicModule == null) {
  404. lock (_lock) {
  405. if (_dynamicModule == null) {
  406. var attributes = new[] {
  407. new CustomAttributeBuilder(typeof(UnverifiableCodeAttribute).GetConstructor(Type.EmptyTypes), new object[0]),
  408. //PermissionSet(SecurityAction.Demand, Unrestricted = true)
  409. new CustomAttributeBuilder(typeof(PermissionSetAttribute).GetConstructor(new Type[] { typeof(SecurityAction) }),
  410. new object[]{ SecurityAction.Demand },
  411. new PropertyInfo[] { typeof(PermissionSetAttribute).GetProperty("Unrestricted") },
  412. new object[] { true }
  413. )
  414. };
  415. string name = typeof(CTypes).Namespace + ".DynamicAssembly";
  416. var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(name), AssemblyBuilderAccess.Run, attributes);
  417. assembly.DefineVersionInfoResource();
  418. _dynamicModule = assembly.DefineDynamicModule(name);
  419. }
  420. }
  421. }
  422. return _dynamicModule;
  423. }
  424. }
  425. /// <summary>
  426. /// Given a specific size returns a .NET type of the equivalent size that
  427. /// we can use when marshalling these values across calls.
  428. /// </summary>
  429. private static Type/*!*/ GetMarshalTypeFromSize(int size) {
  430. lock (_nativeTypes) {
  431. Type res;
  432. if (!_nativeTypes.TryGetValue(size, out res)) {
  433. int sizeRemaining = size;
  434. TypeBuilder tb = DynamicModule.DefineType("interop_type_size_" + size,
  435. TypeAttributes.Public | TypeAttributes.SequentialLayout | TypeAttributes.Sealed | TypeAttributes.Serializable,
  436. typeof(ValueType),
  437. size);
  438. while (sizeRemaining > 8) {
  439. tb.DefineField("field" + sizeRemaining, typeof(long), FieldAttributes.Private);
  440. sizeRemaining -= 8;
  441. }
  442. while (sizeRemaining > 4) {
  443. tb.DefineField("field" + sizeRemaining, typeof(int), FieldAttributes.Private);
  444. sizeRemaining -= 4;
  445. }
  446. while (sizeRemaining > 0) {
  447. tb.DefineField("field" + sizeRemaining, typeof(byte), FieldAttributes.Private);
  448. sizeRemaining--;
  449. }
  450. _nativeTypes[size] = res = tb.CreateType();
  451. }
  452. return res;
  453. }
  454. }
  455. /// <summary>
  456. /// Shared helper between struct and union for getting field info and validating it.
  457. /// </summary>
  458. private static void GetFieldInfo(INativeType type, object o, out string fieldName, out INativeType cdata, out int? bitCount) {
  459. PythonTuple pt = o as PythonTuple;
  460. if (pt.Count != 2 && pt.Count != 3) {
  461. throw PythonOps.AttributeError("'_fields_' must be a sequence of pairs");
  462. }
  463. fieldName = pt[0] as string;
  464. if (fieldName == null) {
  465. throw PythonOps.TypeError("first item in _fields_ tuple must be a string, got", PythonTypeOps.GetName(pt[0]));
  466. }
  467. cdata = pt[1] as INativeType;
  468. if (cdata == null) {
  469. throw PythonOps.TypeError("second item in _fields_ tuple must be a C type, got {0}", PythonTypeOps.GetName(pt[0]));
  470. } else if (cdata == type) {
  471. throw StructureCannotContainSelf();
  472. }
  473. StructType st = cdata as StructType;
  474. if (st != null) {
  475. st.EnsureFinal();
  476. }
  477. if (pt.Count != 3) {
  478. bitCount = null;
  479. } else {
  480. bitCount = CheckBits(cdata, pt);
  481. }
  482. }
  483. /// <summary>
  484. /// Verifies that the provided bit field settings are valid for this type.
  485. /// </summary>
  486. private static int CheckBits(INativeType cdata, PythonTuple pt) {
  487. int bitCount = Converter.ConvertToInt32(pt[2]);
  488. SimpleType simpType = cdata as SimpleType;
  489. if (simpType == null) {
  490. throw PythonOps.TypeError("bit fields not allowed for type {0}", ((PythonType)cdata).Name);
  491. }
  492. switch (simpType._type) {
  493. case SimpleTypeKind.Object:
  494. case SimpleTypeKind.Pointer:
  495. case SimpleTypeKind.Single:
  496. case SimpleTypeKind.Double:
  497. case SimpleTypeKind.Char:
  498. case SimpleTypeKind.CharPointer:
  499. case SimpleTypeKind.WChar:
  500. case SimpleTypeKind.WCharPointer:
  501. throw PythonOps.TypeError("bit fields not allowed for type {0}", ((PythonType)cdata).Name);
  502. }
  503. if (bitCount <= 0 || bitCount > cdata.Size * 8) {
  504. throw PythonOps.ValueError("number of bits invalid for bit field");
  505. }
  506. return bitCount;
  507. }
  508. /// <summary>
  509. /// Shared helper to get the _fields_ list for struct/union and validate it.
  510. /// </summary>
  511. private static IList<object>/*!*/ GetFieldsList(object fields) {
  512. IList<object> list = fields as IList<object>;
  513. if (list == null) {
  514. throw PythonOps.TypeError("class must be a sequence of pairs");
  515. }
  516. return list;
  517. }
  518. private static Exception StructureCannotContainSelf() {
  519. return PythonOps.AttributeError("Structure or union cannot contain itself");
  520. }
  521. /// <summary>
  522. /// Helper function for translating from memset to NT's FillMemory API.
  523. /// </summary>
  524. private static IntPtr StringAt(IntPtr src, int len) {
  525. string res;
  526. if (len == -1) {
  527. res = MemoryHolder.ReadAnsiString(src, 0);
  528. } else {
  529. res = MemoryHolder.ReadAnsiString(src, 0, len);
  530. }
  531. return GCHandle.ToIntPtr(GCHandle.Alloc(res));
  532. }
  533. /// <summary>
  534. /// Helper function for translating from memset to NT's FillMemory API.
  535. /// </summary>
  536. private static IntPtr WStringAt(IntPtr src, int len) {
  537. string res;
  538. if (len == -1) {
  539. res = Marshal.PtrToStringUni(src);
  540. } else {
  541. res = Marshal.PtrToStringUni(src, len);
  542. }
  543. return GCHandle.ToIntPtr(GCHandle.Alloc(res));
  544. }
  545. private static IntPtr GetHandleFromObject(object dll, string errorMsg) {
  546. IntPtr intPtrHandle;
  547. object dllHandle = PythonOps.GetBoundAttr(DefaultContext.Default, dll, "_handle");
  548. BigInteger intHandle;
  549. if (!Converter.TryConvertToBigInteger(dllHandle, out intHandle)) {
  550. throw PythonOps.TypeError(errorMsg);
  551. }
  552. intPtrHandle = new IntPtr((long)intHandle);
  553. return intPtrHandle;
  554. }
  555. private static void ValidateArraySizes(ArrayModule.array array, int offset, int size) {
  556. ValidateArraySizes(array.__len__() * array.itemsize, offset, size);
  557. }
  558. private static void ValidateArraySizes(Bytes bytes, int offset, int size) {
  559. ValidateArraySizes(bytes.Count, offset, size);
  560. }
  561. private static void ValidateArraySizes(int arraySize, int offset, int size) {
  562. if (offset < 0) {
  563. throw PythonOps.ValueError("offset cannot be negative");
  564. } else if (arraySize < size + offset) {
  565. throw PythonOps.ValueError("Buffer size too small ({0} instead of at least {1} bytes)",
  566. arraySize,
  567. size
  568. );
  569. }
  570. }
  571. // TODO: Move these to an Ops class
  572. public static object GetCharArrayValue(_Array arr) {
  573. return arr.NativeType.GetValue(arr._memHolder, arr, 0, false);
  574. }
  575. public static void SetCharArrayValue(_Array arr, object value) {
  576. arr.NativeType.SetValue(arr._memHolder, 0, value);
  577. }
  578. public static void DeleteCharArrayValue(_Array arr, object value) {
  579. throw PythonOps.TypeError("cannot delete char array value");
  580. }
  581. public static object GetWCharArrayValue(_Array arr) {
  582. return arr.NativeType.GetValue(arr._memHolder, arr, 0, false);
  583. }
  584. public static void SetWCharArrayValue(_Array arr, object value) {
  585. arr.NativeType.SetValue(arr._memHolder, 0, value);
  586. }
  587. public static object DeleteWCharArrayValue(_Array arr) {
  588. throw PythonOps.TypeError("cannot delete wchar array value");
  589. }
  590. public static object GetWCharArrayRaw(_Array arr) {
  591. return ((ArrayType)arr.NativeType).GetRawValue(arr._memHolder, 0);
  592. }
  593. public static void SetWCharArrayRaw(_Array arr, object value) {
  594. PythonBuffer buf = value as PythonBuffer;
  595. if (buf != null && buf._object is string) {
  596. value = buf.ToString();
  597. }
  598. arr.NativeType.SetValue(arr._memHolder, 0, value);
  599. }
  600. public static object DeleteWCharArrayRaw(_Array arr) {
  601. throw PythonOps.TypeError("cannot delete wchar array raw");
  602. }
  603. class RefCountInfo {
  604. public int RefCount;
  605. public GCHandle Handle;
  606. }
  607. /// <summary>
  608. /// Emits the marshalling code to create a CData object for reverse marshalling.
  609. /// </summary>
  610. private static void EmitCDataCreation(INativeType type, ILGenerator method, List<object> constantPool, int constantPoolArgument) {
  611. LocalBuilder locVal = method.DeclareLocal(type.GetNativeType());
  612. method.Emit(OpCodes.Stloc, locVal);
  613. method.Emit(OpCodes.Ldloca, locVal);
  614. constantPool.Add(type);
  615. method.Emit(OpCodes.Ldarg, constantPoolArgument);
  616. method.Emit(OpCodes.Ldc_I4, constantPool.Count - 1);
  617. method.Emit(OpCodes.Ldelem_Ref);
  618. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("CreateCData"));
  619. }
  620. private static void EnsureRefCountTable() {
  621. if (_refCountTable == null) {
  622. Interlocked.CompareExchange(ref _refCountTable, new Dictionary<object, RefCountInfo>(), null);
  623. }
  624. }
  625. #endregion
  626. }
  627. }
  628. #endif