// This function retrieves a native image handle from the native API. // // If this is the first time calling the property, we construct a new wrapper // If the handle is for an Image we have already constructed a wrapper for, we return the existing wrapper // If the handle is for a different Image, or if the wrapper has already been disposed, we construct a new wrapper and dispose the old one private Image GetImageWrapperAndDisposePrevious(Func <BodyTrackingNativeMethods.k4abt_frame_t, NativeMethods.k4a_image_t> nativeMethod, ref Image cache) { // Lock must be held to ensure the Image in cache is not replaced while we are inspecting it // It is still possible for that Image to be accessed or Disposed while this lock is held lock (this) { if (this.disposedValue) { throw new ObjectDisposedException(nameof(Capture)); } NativeMethods.k4a_image_t image = nativeMethod(this.handle); // This try block ensures that we close image try { if (cache != null) { IntPtr imageHandle = image.DangerousGetHandle(); // Only attempt to access cache in this try block try { // If cache was disposed before we called the native accessor (by the caller or another thread), // the handle could have been reused and the values would incorrectly match. However, cache.DangerousGetHandle() // will throw an exception, and we will correctly construct a new image wrapper. if (cache.DangerousGetHandle().DangerousGetHandle() != imageHandle) { // The image has changed, invalidate the current image and construct a new wrapper cache.Dispose(); cache = null; } } catch (ObjectDisposedException) { // If cache has been disposed by the caller or another thread we will discard // it and construct a new wrapper cache = null; } } if (cache == null && !image.IsInvalid) { // Construct a new wrapper and return it // The native function may have returned cache = new Image(image); // Since we have wrapped image, it is now owned by the UnsafeImage object and we should no longer close it image = null; } } finally { // Ensure the native handle is closed if we have a failure creating the Image object if (image != null) { image.Close(); } } return(cache); } }
internal Image(NativeMethods.k4a_image_t handle) { this.handle = handle; }