A game framework written with osu! in mind.
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2// See the LICENCE file in the repository root for full licence text.
3
4using System;
5using System.Runtime.InteropServices;
6
7namespace osu.Framework.Allocation
8{
9 /// <summary>
10 /// Wrapper on <see cref="GCHandle" /> that supports the <see cref="IDisposable" /> pattern.
11 /// </summary>
12 public struct ObjectHandle<T> : IDisposable
13 where T : class
14 {
15 /// <summary>
16 /// The pointer from the <see cref="GCHandle" />, if it is allocated. Otherwise <see cref="IntPtr.Zero" />.
17 /// </summary>
18 public IntPtr Handle => handle.IsAllocated ? GCHandle.ToIntPtr(handle) : IntPtr.Zero;
19
20 /// <summary>
21 /// The address of target object, if it is allocated and pinned. Otherwise <see cref="IntPtr.Zero" />.
22 /// Note: This is not the same as the <see cref="Handle" />.
23 /// </summary>
24 public IntPtr Address => handle.IsAllocated ? handle.AddrOfPinnedObject() : IntPtr.Zero;
25
26 public bool IsAllocated => handle.IsAllocated;
27
28 private GCHandle handle;
29
30 private readonly bool fromPointer;
31
32 /// <summary>
33 /// Wraps the provided object with a <see cref="GCHandle" />, using the given <see cref="GCHandleType" />.
34 /// </summary>
35 /// <param name="target">The target object to wrap.</param>
36 /// <param name="handleType">The handle type to use.</param>
37 public ObjectHandle(T target, GCHandleType handleType)
38 {
39 handle = GCHandle.Alloc(target, handleType);
40 fromPointer = false;
41 }
42
43 /// <summary>
44 /// Recreates an <see cref="ObjectHandle{T}" /> based on the passed <see cref="IntPtr" />.
45 /// Disposing this object will not free the handle, the original object must be disposed instead.
46 /// </summary>
47 /// <param name="handle">Handle.</param>
48 public ObjectHandle(IntPtr handle)
49 {
50 this.handle = GCHandle.FromIntPtr(handle);
51 fromPointer = true;
52 }
53
54 /// <summary>
55 /// Gets the object being referenced.
56 /// Returns true if successful and populates <paramref name="target"/> with the referenced object.
57 /// Returns false If the handle is not allocated or the target is not of type <typeparamref name="T"/>.
58 /// </summary>
59 /// <param name="target">Populates this parameter with the targeted object.</param>
60 public bool GetTarget(out T target)
61 {
62 if (!handle.IsAllocated)
63 {
64 target = default;
65 return false;
66 }
67
68 try
69 {
70 if (handle.Target is T value)
71 {
72 target = value;
73 return true;
74 }
75 }
76 catch (InvalidOperationException)
77 {
78 }
79
80 target = default;
81 return false;
82 }
83
84 #region IDisposable Support
85
86 public void Dispose()
87 {
88 if (!fromPointer && handle.IsAllocated)
89 handle.Free();
90 }
91
92 #endregion
93 }
94}