using System;
using System.Runtime.InteropServices;
namespace TDMS.Common
{
///
/// 面向Channel里存储的数据集合的数据结构;用于将数据集合转换为指针和长度,以便传递给C++的DLL。
///
///
///
internal class Data(T[] values) : IDisposable where T : struct
{
private readonly T[] _values = values ?? throw new ArgumentNullException(nameof(values));
private UIntPtr _lengthPtr;
private SafeBufferHandle _valuesHandle;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public (IntPtr Values, UIntPtr Length) GetValues()
{
if(_valuesHandle is { IsInvalid: false })
{
// 如果已经分配了内存,直接返回
return (_valuesHandle.DangerousGetHandle(), _lengthPtr);
}
_lengthPtr = (UIntPtr)_values.Length;
var size = Marshal.SizeOf();
_valuesHandle = new SafeBufferHandle(size * _values.Length);
try
{
for (var i = 0; i < _values.Length; i++)
{
Marshal.StructureToPtr(_values[i], _valuesHandle.DangerousGetHandle() + i * size, false);
}
}
catch
{
// 如果发生异常,释放已分配的内存
Dispose();
throw;
}
return (_valuesHandle.DangerousGetHandle(), _lengthPtr);
}
protected virtual void Dispose(bool disposing)
{
if(disposing)
{
_valuesHandle?.Dispose();
}
}
~Data()
{
Dispose(false);
}
}
internal class SafeBufferHandle : SafeHandle
{
public SafeBufferHandle(int size) : base(IntPtr.Zero, true)
{
SetHandle(Marshal.AllocHGlobal(size));
}
public override bool IsInvalid => handle == IntPtr.Zero;
protected override bool ReleaseHandle()
{
if(!IsInvalid)
{
Marshal.FreeHGlobal(handle);
handle = IntPtr.Zero;
}
return true;
}
}
}