Data`.cs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace TDMS.Common
  4. {
  5. /// <summary>
  6. /// 面向Channel里存储的数据集合的数据结构;用于将数据集合转换为指针和长度,以便传递给C++的DLL。
  7. /// </summary>
  8. /// <typeparam name="T"></typeparam>
  9. /// <param name="values"></param>
  10. internal class Data<T>(T[] values) : IDisposable where T : struct
  11. {
  12. private readonly T[] _values = values ?? throw new ArgumentNullException(nameof(values));
  13. private UIntPtr _lengthPtr;
  14. private SafeBufferHandle _valuesHandle;
  15. public void Dispose()
  16. {
  17. Dispose(true);
  18. GC.SuppressFinalize(this);
  19. }
  20. public (IntPtr Values, UIntPtr Length) GetValues()
  21. {
  22. if(_valuesHandle is { IsInvalid: false })
  23. {
  24. // 如果已经分配了内存,直接返回
  25. return (_valuesHandle.DangerousGetHandle(), _lengthPtr);
  26. }
  27. _lengthPtr = (UIntPtr)_values.Length;
  28. var size = Marshal.SizeOf<T>();
  29. _valuesHandle = new SafeBufferHandle(size * _values.Length);
  30. try
  31. {
  32. for (var i = 0; i < _values.Length; i++)
  33. {
  34. Marshal.StructureToPtr(_values[i], _valuesHandle.DangerousGetHandle() + i * size, false);
  35. }
  36. }
  37. catch
  38. {
  39. // 如果发生异常,释放已分配的内存
  40. Dispose();
  41. throw;
  42. }
  43. return (_valuesHandle.DangerousGetHandle(), _lengthPtr);
  44. }
  45. protected virtual void Dispose(bool disposing)
  46. {
  47. if(disposing)
  48. {
  49. _valuesHandle?.Dispose();
  50. }
  51. }
  52. ~Data()
  53. {
  54. Dispose(false);
  55. }
  56. }
  57. internal class SafeBufferHandle : SafeHandle
  58. {
  59. public SafeBufferHandle(int size) : base(IntPtr.Zero, true)
  60. {
  61. SetHandle(Marshal.AllocHGlobal(size));
  62. }
  63. public override bool IsInvalid => handle == IntPtr.Zero;
  64. protected override bool ReleaseHandle()
  65. {
  66. if(!IsInvalid)
  67. {
  68. Marshal.FreeHGlobal(handle);
  69. handle = IntPtr.Zero;
  70. }
  71. return true;
  72. }
  73. }
  74. }