diff --git a/Mediapipe.Net/Core/Disposable.cs b/Mediapipe.Net/Core/Disposable.cs
new file mode 100644
index 0000000..5c132e5
--- /dev/null
+++ b/Mediapipe.Net/Core/Disposable.cs
@@ -0,0 +1,63 @@
+// Copyright (c) homuler and Vignette
+// This file is part of MediaPipe.NET.
+// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
+
+
+using System;
+using System.Threading;
+
+namespace Mediapipe.Net.Core;
+
+///
+/// based on OpenCvSharp
+///
+public abstract class Disposable : IDisposable
+{
+ private volatile int disposeSignaled = 0;
+
+ public bool IsDisposed { get; protected set; }
+ protected bool IsOwner { get; private set; }
+
+ protected Disposable() : this(true) { }
+
+ protected Disposable(bool isOwner)
+ {
+ IsDisposed = false;
+ IsOwner = isOwner;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Interlocked.Exchange(ref disposeSignaled, 1) != 0)
+ return;
+
+ IsDisposed = true;
+
+ if (disposing)
+ DisposeManaged();
+
+ DisposeUnmanaged();
+ }
+
+ ~Disposable()
+ {
+ Dispose(false);
+ }
+
+ protected virtual void DisposeManaged() { }
+ protected virtual void DisposeUnmanaged() { }
+
+ public void TransferOwnership() => IsOwner = false;
+
+ public void ThrowIfDisposed()
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException(GetType().FullName);
+ }
+}
diff --git a/Mediapipe.Net/Core/IMpResourceHandle.cs b/Mediapipe.Net/Core/IMpResourceHandle.cs
new file mode 100644
index 0000000..15f5c23
--- /dev/null
+++ b/Mediapipe.Net/Core/IMpResourceHandle.cs
@@ -0,0 +1,28 @@
+// Copyright (c) homuler and Vignette
+// This file is part of MediaPipe.NET.
+// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
+
+using System;
+
+namespace Mediapipe.Net.Core;
+
+public interface IMpResourceHandle : IDisposable
+{
+ IntPtr MpPtr { get; }
+
+ ///
+ /// Relinquish the ownership, and release the resource it owns if necessary.
+ /// This method should be called only if the underlying native api moves the pointer.
+ ///
+ ///
+ /// If the object itself is no longer used, call instead.
+ ///
+ void ReleaseMpResource();
+
+ ///
+ /// Relinquish the ownership
+ ///
+ void TransferOwnership();
+
+ bool OwnsResource();
+}
diff --git a/Mediapipe.Net/Core/InternalException.cs b/Mediapipe.Net/Core/InternalException.cs
new file mode 100644
index 0000000..8700f07
--- /dev/null
+++ b/Mediapipe.Net/Core/InternalException.cs
@@ -0,0 +1,12 @@
+// Copyright (c) homuler and Vignette
+// This file is part of MediaPipe.NET.
+// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
+
+using System;
+
+namespace Mediapipe.Net.Core;
+
+public class InternalException : Exception
+{
+ public InternalException(string message) : base(message) { }
+}
diff --git a/Mediapipe.Net/Core/MediapipeException.cs b/Mediapipe.Net/Core/MediapipeException.cs
new file mode 100644
index 0000000..38e3320
--- /dev/null
+++ b/Mediapipe.Net/Core/MediapipeException.cs
@@ -0,0 +1,12 @@
+// Copyright (c) homuler and Vignette
+// This file is part of MediaPipe.NET.
+// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
+
+using System;
+
+namespace Mediapipe.Net.Core;
+
+public class MediapipeException : Exception
+{
+ public MediapipeException(string message) : base(message) { }
+}
diff --git a/Mediapipe.Net/Core/MediapipeNetException.cs b/Mediapipe.Net/Core/MediapipeNetException.cs
new file mode 100644
index 0000000..c476eac
--- /dev/null
+++ b/Mediapipe.Net/Core/MediapipeNetException.cs
@@ -0,0 +1,12 @@
+// Copyright (c) homuler and Vignette
+// This file is part of MediaPipe.NET.
+// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
+
+using System;
+
+namespace Mediapipe.Net.Core;
+
+public class MediapipeNetException : Exception
+{
+ public MediapipeNetException(string message) : base(message) { }
+}
diff --git a/Mediapipe.Net/Core/MpResourceHandle.cs b/Mediapipe.Net/Core/MpResourceHandle.cs
new file mode 100644
index 0000000..35208a2
--- /dev/null
+++ b/Mediapipe.Net/Core/MpResourceHandle.cs
@@ -0,0 +1,76 @@
+// Copyright (c) homuler and Vignette
+// This file is part of MediaPipe.NET.
+// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
+
+using System;
+using System.Runtime.InteropServices;
+using Mediapipe.Net.Native;
+using static Mediapipe.Net.Native.MpReturnCodeExtension;
+
+namespace Mediapipe.Net.Core;
+
+public abstract class MpResourceHandle : Disposable, IMpResourceHandle
+{
+ protected IntPtr Ptr;
+
+ protected MpResourceHandle(bool isOwner = true) : this(IntPtr.Zero, isOwner) { }
+
+ protected MpResourceHandle(IntPtr ptr, bool isOwner = true) : base(isOwner)
+ {
+ Ptr = ptr;
+ }
+
+ #region IMpResourceHandle
+ public IntPtr MpPtr
+ {
+ get
+ {
+ ThrowIfDisposed();
+ return Ptr;
+ }
+ }
+
+ public void ReleaseMpResource()
+ {
+ if (OwnsResource())
+ DeleteMpPtr();
+
+ TransferOwnership();
+ }
+
+ public bool OwnsResource() => IsOwner && Ptr != IntPtr.Zero;
+ #endregion
+
+ protected override void DisposeUnmanaged()
+ {
+ if (OwnsResource())
+ DeleteMpPtr();
+
+ ReleaseMpPtr();
+ base.DisposeUnmanaged();
+ }
+
+ ///
+ /// Forgets the pointer address.
+ /// After calling this method, will return false.
+ ///
+ protected void ReleaseMpPtr() => Ptr = IntPtr.Zero;
+
+ ///
+ /// Release the memory (call `delete` or `delete[]`) whether or not it owns it.
+ ///
+ /// In most cases, this method should not be called directly.
+ protected abstract void DeleteMpPtr();
+
+ protected delegate MpReturnCode StringOutFunc(IntPtr ptr, out IntPtr strPtr);
+ protected string? MarshalStringFromNative(StringOutFunc func)
+ {
+ func(MpPtr, out IntPtr strPtr).Assert();
+ GC.KeepAlive(this);
+
+ string? str = Marshal.PtrToStringAnsi(strPtr);
+ UnsafeNativeMethods.delete_array__PKc(strPtr);
+
+ return str;
+ }
+}
diff --git a/Mediapipe.Net/Core/SharedPtrHandle.cs b/Mediapipe.Net/Core/SharedPtrHandle.cs
new file mode 100644
index 0000000..b688eed
--- /dev/null
+++ b/Mediapipe.Net/Core/SharedPtrHandle.cs
@@ -0,0 +1,18 @@
+// Copyright (c) homuler and Vignette
+// This file is part of MediaPipe.NET.
+// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
+
+using System;
+
+namespace Mediapipe.Net.Core;
+
+public abstract class SharedPtrHandle : MpResourceHandle
+{
+ protected SharedPtrHandle(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { }
+
+ /// The owning pointer
+ public abstract IntPtr Get();
+
+ /// Release the owning pointer
+ public abstract void Reset();
+}
diff --git a/Mediapipe.Net/Core/UniquePtrHandle.cs b/Mediapipe.Net/Core/UniquePtrHandle.cs
new file mode 100644
index 0000000..c749515
--- /dev/null
+++ b/Mediapipe.Net/Core/UniquePtrHandle.cs
@@ -0,0 +1,18 @@
+// Copyright (c) homuler and Vignette
+// This file is part of MediaPipe.NET.
+// MediaPipe.NET is licensed under the MIT License. See LICENSE for details.
+
+using System;
+
+namespace Mediapipe.Net.Core;
+
+public abstract class UniquePtrHandle : MpResourceHandle
+{
+ protected UniquePtrHandle(IntPtr ptr, bool isOwner = true) : base(ptr, isOwner) { }
+
+ /// The owning pointer
+ public abstract IntPtr Get();
+
+ /// Release the owning pointer
+ public abstract IntPtr Release();
+}