Initial commit
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CeresSharp.Native;
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for managing GCHandle resources and ensuring proper cleanup.
|
||||
/// Provides utilities for tracking and disposing of pinned handles.
|
||||
/// </summary>
|
||||
internal sealed class ResourceManager : IDisposable
|
||||
{
|
||||
private readonly List<GCHandle> _handles = new List<GCHandle>();
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a GCHandle to be managed and disposed.
|
||||
/// </summary>
|
||||
/// <param name="handle">The GCHandle to track.</param>
|
||||
/// <exception cref="ObjectDisposedException">Thrown when the manager is disposed.</exception>
|
||||
public void AddHandle(GCHandle handle)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(nameof(ResourceManager));
|
||||
|
||||
lock (_handles)
|
||||
{
|
||||
_handles.Add(handle);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds multiple GCHandles to be managed and disposed.
|
||||
/// </summary>
|
||||
/// <param name="handles">The GCHandles to track.</param>
|
||||
/// <exception cref="ObjectDisposedException">Thrown when the manager is disposed.</exception>
|
||||
public void AddHandles(IEnumerable<GCHandle> handles)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(nameof(ResourceManager));
|
||||
|
||||
lock (_handles)
|
||||
{
|
||||
_handles.AddRange(handles);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pins an array and adds the handle to the manager.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The unmanaged type of the array elements.</typeparam>
|
||||
/// <param name="array">The array to pin.</param>
|
||||
/// <returns>The pinned GCHandle.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when array is null.</exception>
|
||||
/// <exception cref="ObjectDisposedException">Thrown when the manager is disposed.</exception>
|
||||
public GCHandle PinArray<T>(T[] array) where T : unmanaged
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
AddHandle(handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all handles as an array (for safe enumeration during disposal).
|
||||
/// </summary>
|
||||
/// <returns>Array of GCHandles.</returns>
|
||||
public GCHandle[] GetHandlesSnapshot()
|
||||
{
|
||||
lock (_handles)
|
||||
{
|
||||
return _handles.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all handles without disposing them.
|
||||
/// Useful when ownership is transferred to another object.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
lock (_handles)
|
||||
{
|
||||
_handles.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
// Get snapshot to avoid issues during enumeration
|
||||
var handlesToFree = GetHandlesSnapshot();
|
||||
|
||||
lock (_handles)
|
||||
{
|
||||
_handles.Clear();
|
||||
}
|
||||
|
||||
// Free handles outside the lock
|
||||
foreach (var handle in handlesToFree)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (handle.IsAllocated)
|
||||
handle.Free();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore errors during cleanup - handles may already be freed
|
||||
}
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user