// Основан на примере GpuInterop Avalonia // https://github.com/AvaloniaUI/Avalonia/blob/5f3dbae22244e830b464fc680c6c28ca124be41a/samples/GpuInterop/VulkanDemo/ByteString.cs using System.Runtime.InteropServices; namespace GSS2.Vulkan; unsafe sealed class ByteString : IDisposable { private bool _disposedValue; private readonly byte* _pointer; public ByteString(string s) { _pointer = (byte*)Marshal.StringToHGlobalAnsi(s); } private void Dispose(bool disposing) { if (!_disposedValue) { Marshal.FreeHGlobal(new IntPtr(_pointer)); _disposedValue = true; } } ~ByteString() => Dispose(disposing: false); public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } public static implicit operator byte*(ByteString obj) => obj._pointer; } unsafe sealed class ByteStringList : IDisposable { private bool _disposedValue; private readonly List _list; private readonly byte** _pointer; public int Count => _list.Count; public ByteStringList(IEnumerable list) { _list = list.Select(x => new ByteString(x)).ToList(); _pointer = (byte**)Marshal.AllocHGlobal(IntPtr.Size * _list.Count + 1); for (var c = 0; c < _list.Count; c++) _pointer[c] = (byte*)_list[c]; } private void Dispose(bool disposing) { if (!_disposedValue) { Marshal.FreeHGlobal(new IntPtr(_pointer)); _disposedValue = true; } } ~ByteStringList() => Dispose(disposing: false); public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } public static implicit operator byte**(ByteStringList obj) => obj._pointer; }