#c# #marshalling #unmanaged #unix-timestamp
#c# #сортировка #неуправляемый #unix-временная метка
Вопрос:
возможно ли определить пользовательский неуправляемый тип для класса атрибутов MarshalAs? В частности, я хочу преобразовать long int unix time в тип DateTime. Что-то вроде этого:
[MarshalAs(UnmanagedType.LongTimeUnix)]
public DateTime Time;
Куда мне нужно поместить пользовательский тип перечисления LongTimeUnix и куда поместить код преобразования времени:
public static DateTime ConvertUnix2DateTime(long timeStamp)
{
DateTime DT = new DateTime(1970, 1, 1, 0, 0, 0, 0);
DT = DT.AddSeconds(timeStamp);
return DT;
}
При передаче данных с
(SomeStruct)Marshal.PtrToStructure(
IntPtr,
typeof(SomeStruct));
Я хочу, чтобы долгое время unix автоматически преобразовывался с помощью приведенного выше кода sinppet.
Должен ли я наследовать от класса MarshalAs и записывать преобразование в этот класс?
Спасибо, Юрген
Обновление Вот пользовательский маршаллер:
class MarshalTest : ICustomMarshaler
{
public void CleanUpManagedData(object ManagedObj)
{
throw new NotImplementedException();
}
public void CleanUpNativeData(IntPtr pNativeData)
{
throw new NotImplementedException();
}
public int GetNativeDataSize()
{
return 8;
}
public IntPtr MarshalManagedToNative(object ManagedObj)
{
throw new NotImplementedException();
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
long UnixTime = 0;
try
{
UnixTime = Marshal.ReadInt64(pNativeData);
}
catch (Exception e)
{
QFXLogger.Error(e, "MarshalNativeToManaged");
}
DateTime DT = new DateTime(1970, 1, 1, 0, 0, 0, 0);
DT = DT.AddSeconds(UnixTime);
return DT;
}
}
Вот определение класса:
unsafe public struct MT5ServerAttributes
{
/// <summary>
/// Last known server time.
/// </summary>
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MarshalTest))]
public DateTime CurrentTime;
//[MarshalAs(UnmanagedType.U8)]
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MarshalTest))]
public DateTime TradeTime;
}
И, наконец, код для маршалирования данных из неуправляемой памяти:
try
{
MT5ServerAttributes MT5SrvAttributes = (MT5ServerAttributes)Marshal.PtrToStructure(mMT5Proxy.MT5InformationProxy.ServerData,
typeof(MT5ServerAttributes));
}
catch (Exception e)
{
QFXLogger.Error(e, "ConsumeCommand inner");
}
При выполнении этого выдается следующее исключение (которое не является прямым исключением из PtrToStructure!)
Невозможно маршалировать поле ‘currentTime’ типа ‘QFX_DLL.MT5ServerAttributes’: недопустимая комбинация управляемого / неуправляемого типа (класс DateTime должен быть сопряжен со структурой).
Есть идеи?
Ответ №1:
Вы не можете добавить свой собственный в перечисление, но вы можете использовать UnmanagedType.CustomMarshaler
. Чтобы указать, что вы хотите маршалировать его, используя пользовательский тип.
В MSDN есть целый раздел, посвященный этому.
В конечном итоге вы должны сделать что-то в этом роде:
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyCustomMarshaler))]
public DateTime Time;
Затем реализуйте MyCustomMarshaler как ICustomMarshaler
.
Комментарии:
1. Действительно ли это работает? Я пытаюсь сделать то же самое, и это не удается, потому что вы не можете использовать
CustomMarshaler
для члена класса. Насколько я могу судитьCustomMarshaler
, работает только для параметров функции (и это боль).2. Нет, для меня тоже нет радости @J.N .. Я подозреваю из его комментария, что @Juergen пометил это как ответ, прежде чем на самом деле попробовать. Если вы пропустите шаг вызова
Marshal.SizeOf
и перейдете непосредственно кMarshal.PtrToStructure
вызову, вы получите сообщение об ошибке «Пользовательские маршалеры не могут использоваться для полей структур». Это в значительной степени говорит о том, что это невозможно сделать.