// Copyright (c) 2019 Jean-Philippe Bruyère // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using static Vulkan.Vk; namespace Vulkan { public static class ExtensionMethods { #region pinning /// /// list of pinned GCHandles used to pass value from managed to unmanaged code. /// public static Dictionary handles = new Dictionary(); /// /// Unpin the specified object and free the GCHandle associated. /// public static void Unpin (this object obj) { if (!handles.ContainsKey (obj)) { Debug.WriteLine ("Trying to unpin unpinned object: {0}.", obj); return; } handles[obj].Free (); handles.Remove (obj); } /// /// Pin the specified object and return a pointer. MUST be Unpined as soon as possible. /// public static IntPtr Pin (this object obj) { if (handles.ContainsKey (obj)) { Debug.WriteLine ("Trying to pin already pinned object: {0}", obj); return handles[obj].AddrOfPinnedObject (); } GCHandle hnd = GCHandle.Alloc (obj, GCHandleType.Pinned); handles.Add (obj, hnd); return hnd.AddrOfPinnedObject (); } public static IntPtr Pin (this IEnumerable obj) { if (handles.ContainsKey (obj)) Debug.WriteLine ("Pinning already pinned object: {0}", obj); GCHandle hnd = GCHandle.Alloc (obj.ToArray(), GCHandleType.Pinned); handles.Add (obj, hnd); return hnd.AddrOfPinnedObject (); } public static IntPtr Pin (this T[] obj) { if (handles.ContainsKey (obj)) Debug.WriteLine ("Pinning already pinned object: {0}", obj); GCHandle hnd = GCHandle.Alloc (obj, GCHandleType.Pinned); handles.Add (obj, hnd); return hnd.AddrOfPinnedObject (); } public static IntPtr Pin (this string obj) { if (handles.ContainsKey (obj)) { Debug.WriteLine ("Trying to pin already pinned object: {0}", obj); return handles[obj].AddrOfPinnedObject (); } byte[] n = System.Text.Encoding.UTF8.GetBytes(obj +'\0'); GCHandle hnd = GCHandle.Alloc (n, GCHandleType.Pinned); handles.Add (obj, hnd); return hnd.AddrOfPinnedObject (); } public static IntPtr PinPointer (this string obj) { byte[] n = System.Text.Encoding.UTF8.GetBytes(obj +'\0'); GCHandle hnd = GCHandle.Alloc (n, GCHandleType.Pinned); handles.Add (hnd.AddrOfPinnedObject (), hnd); return hnd.AddrOfPinnedObject (); } public static IntPtr PinPointer (this object obj) { #if DEBUG if (obj == null) Debug.WriteLine ("Trying to pin null object: {0}", obj); #endif GCHandle hnd = GCHandle.Alloc (obj, GCHandleType.Pinned); handles.Add (hnd.AddrOfPinnedObject (), hnd); return hnd.AddrOfPinnedObject (); } public static IntPtr PinPointer (this IEnumerable obj) { #if DEBUG if (obj == null) Debug.WriteLine ("Trying to pin null object: {0}", obj); #endif GCHandle hnd = GCHandle.Alloc (obj.ToArray(), GCHandleType.Pinned); handles.Add (hnd.AddrOfPinnedObject (), hnd); return hnd.AddrOfPinnedObject (); } //pin with pinning context public static IntPtr Pin (this object obj, PinnedObjects ctx) { GCHandle hnd = GCHandle.Alloc (obj, GCHandleType.Pinned); ctx.Handles.Add (hnd); return hnd.AddrOfPinnedObject (); } public static IntPtr Pin (this IList obj, PinnedObjects ctx) { GCHandle hnd = GCHandle.Alloc (obj.ToArray (), GCHandleType.Pinned); ctx.Handles.Add (hnd); return hnd.AddrOfPinnedObject (); } public static IntPtr Pin (this T[] obj, PinnedObjects ctx) { GCHandle hnd = GCHandle.Alloc (obj, GCHandleType.Pinned); ctx.Handles.Add (hnd); return hnd.AddrOfPinnedObject (); } public static IntPtr Pin (this string obj, PinnedObjects ctx) { byte[] n = System.Text.Encoding.UTF8.GetBytes (obj + '\0'); GCHandle hnd = GCHandle.Alloc (n, GCHandleType.Pinned); ctx.Handles.Add (hnd); return hnd.AddrOfPinnedObject (); } #endregion } }