Судя по документации, не совсем ясно что должен вообще реализовывать интерфейс ICustomMarshaler
.
Хотелось бы описать маршалер для преобразования массива си строк в управляемый массив строк и обратно.
Есть ли какие-либо примеры или подсказки как это сделать правильно?
Дополнительные классы преобразования описал, вот только неясность осталась с данным интерфейсом.
public class CString : IDisposable
{
private bool _isDisposed;
public CString(string str)
{
byte[] tmpArr = Encoding.UTF8.GetBytes(str);
Handle = Marshal.AllocHGlobal(tmpArr.Length + 1);
Marshal.Copy(tmpArr, 0, Handle, tmpArr.Length);
Marshal.WriteByte(Handle, tmpArr.Length, (byte) '\0');
GC.KeepAlive(this);
}
public CString(IntPtr unmanagedStrPtr)
{
Handle = unmanagedStrPtr;
}
public IntPtr Handle { get; }
public char this[int idx] => (char) Marshal.ReadByte(Handle, idx);
public void Dispose()
{
if (_isDisposed) return;
Marshal.FreeHGlobal(Handle);
_isDisposed = true;
}
public static implicit operator CString(string str)
{
return new CString(str);
}
public static implicit operator CString(IntPtr strPtr)
{
return new CString(strPtr);
}
public static implicit operator string(CString str)
{
int size = 0;
while (Marshal.ReadByte(str.Handle, size) != '\0') size++;
byte[] arrBytes = new byte[size];
Marshal.Copy(str.Handle, arrBytes, 0, size);
return Encoding.UTF8.GetString(arrBytes);
}
~CString()
{
Dispose();
GC.SuppressFinalize(this);
}
}
public class CStringArray : IDisposable
{
public IntPtr Handle { get; }
private CString[] _arrStrings;
private IntPtr[] _arrPtr;
private bool _isDisposed;
public int Length => _arrPtr.Length;
public CStringArray(string[] arrayStrings)
{
_arrStrings = new CString[arrayStrings.Length];
_arrPtr = new IntPtr[arrayStrings.Length];
for (int i = 0; i < arrayStrings.Length; i++)
{
_arrStrings[i] = arrayStrings[i];
}
Handle = Marshal.AllocHGlobal(IntPtr.Size * arrayStrings.Length);
for (int i = 0; i < _arrPtr.Length; i++)
{
_arrPtr[i] = _arrStrings[i].Handle;
}
Marshal.Copy(_arrPtr, 0, Handle, _arrPtr.Length);
GC.KeepAlive(this);
}
public CStringArray(IntPtr unmanagedPtr, int length)
{
_arrPtr = new IntPtr[length];
_arrStrings = new CString[length];
for (int i = 0; i < length; i++)
{
_arrPtr[i] = Marshal.ReadIntPtr(unmanagedPtr, IntPtr.Size * i);
_arrStrings[i] = new CString(_arrPtr[i]);
}
}
public CString this[int idx] => _arrStrings[idx];
public static implicit operator string[](CStringArray array)
{
string[] arr = new string[array.Length];
for (int i = 0; i < array.Length; i++)
{
arr[i] = array[i];
}
return arr;
}
public static implicit operator CStringArray(string[] strings)
{
return new CStringArray(strings);
}
public void Dispose()
{
if (_isDisposed)
{
return;
}
for (int i = 0; i < _arrStrings.Length; i++)
{
_arrStrings[i].Dispose();
}
_arrStrings = null;
_arrPtr = null;
_isDisposed = true;
}
~CStringArray()
{
Dispose();
GC.SuppressFinalize(this);
}
}
На данный момент описал его так:
public class CStringMarshaler : ICustomMarshaler
{
static CStringMarshaler StaticInstance;
public void CleanUpManagedData(object ManagedObj)
{
if (ManagedObj is CString data)
{
data.Dispose();
}
else
{
throw new BadArgumentException("ManagedObj is not CString");
}
}
public void CleanUpNativeData(IntPtr pNativeData)
{
Marshal.FreeHGlobal(pNativeData);
}
public int GetNativeDataSize()
{
return -1;
}
public IntPtr MarshalManagedToNative(object ManagedObj)
{
return new CString((string)ManagedObj).Handle;
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return new CString(pNativeData);
}
public static ICustomMarshaler GetInstance(string cookie)
{
if (StaticInstance == null)
{
return StaticInstance = new CStringMarshaler();
}
return StaticInstance;
}
}
Это работает, но не уверен в правильности реализации.
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Виртуальный выделенный сервер (VDS) становится отличным выбором
Почему при перетаскивании объекта, он перетаскивается не конкретно с курсором, а слегка обтекая его (попытался отобразить на скриншотах...
Как повернуть объект по направлению к другому через transformRotate только по оси у?
Есть некоторый сервис, который дёргает два репозитория (первый - к сущности Order, второй - к сущности OrderPosition) и возвращает уже собранный заказ...
Задача: повредить файл, для обеспечения невозможности его чтения(И удачного восстановления если его удалить программным способом, на той...