PageRenderTime 52ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/IronPython/IronPython.Modules/_ctypes/_ctypes.cs

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