【发布时间】:2014-01-24 20:16:05
【问题描述】:
如何将此代码从 Delphi 转换为 C#?我需要 struct 来与无人管理的代码进行交互。
TDataTypeParam = packed record
dtType : integer;
case integer of
cInt :(dtInt : integer);
cFloat :(dtFloat : real);
cLongInt :(dtLongInt : Int64);
cDateTime:(dtDateTime : TDateTime);
cShortStr:(dtShortString : ShortString);
end;
TDataParam = packed record
NumberParam : integer;
Param : array [1..MaxParam] of TDataTypeParam;
end;
TEvData = packed record
dm : TDateTime;
CodeEV : integer;
IDCAM : integer;
Reserv1 : integer;
Data : TDataParam;
end;
TArrSrvData = packed record
NumberPack : integer;
Address : Cardinal;
tpCL : integer;
tpEv : integer;
Reserv : integer;
Packs : array [1..MaxPacks] of TEvData;
end;
这段代码是抛出 System.TypeLoadException:
//TDataTypeParam = packed record
//dtType : integer;//data type
// case integer of
// cInt :(dtInt : integer);
// cFloat :(dtFloat : real);
// cLongInt :(dtLongInt : Int64);
// cDateTime:(dtDateTime : TDateTime);
// cShortStr:(dtShortString : ShortString);
//end;
[StructLayout(LayoutKind.Explicit)]
[Serializable]
internal struct DataTypeParam
{
[FieldOffset(0)]
public DataType dtType;
[FieldOffset(4)]
public int dtInt;
[FieldOffset(4)]
public double dtFloat;
[FieldOffset(4)]
public long dtLongInt;
[FieldOffset(4)]
public double dtDateTime;
[FieldOffset(4)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] dtShortString;
};
//TDataParam = packed record
// NumberParam : integer;
// Param : array [1..MaxParam] of TDataTypeParam;
// end;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
[Serializable]
internal struct DataParam
{
public int NumberParam;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = Consts.MaxParam)]
public DataTypeParam[] Param;
};
// TEvData = packed record
// dm : TDateTime;
// CodeEV : integer;
// IDCAM : integer;
// Reserv1 : integer;
// Data : TDataParam;
// end;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
[Serializable]
internal struct EvData
{
public DateTime dm;
public int CodeEV;
public int IDCAM;
public int Reserv1;
public DataParam Data;
}
// TArrSrvData = packed record
// NumberPack : integer;
// Address : Cardinal;
// tpCL : integer;
// tpEv : integer;
// Reserv : integer;
// Packs : array [1..MaxPacks] of TEvData;
// end;
// PArrSrvData = ^TArrSrvData;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
[Serializable]
internal struct ArrSrvData
{
public int NumberPack;
public uint Address;
public int tpCL;
public int tpEv;
public int Reserv;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = Consts.MaxPacks)]
public EvData[] Param;
}
这个问题出在 cShortStr:(dtShortString : ShortString); 转换...
这是实际代码:
void mySink_NewEvent(ref object Comm)
{
byte[] arr = Comm as byte[];
if(arr == null) return;
var data = (ArrSrvData)MarshalSerializer.RawDeserialize(arr, typeof(ArrSrvData));
}
以及 RawDeserialize 代码:
public static object RawDeserialize(byte[] rawData, Type type)
{
if (rawData == null)
throw new ArgumentNullException(MethodBase.GetCurrentMethod().GetParameters()[0].Name);
int rawsize = Marshal.SizeOf(type);
if (rawsize > rawData.Length)
return null;
object retobj;
GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
try
{
IntPtr buffer = handle.AddrOfPinnedObject();
retobj = Marshal.PtrToStructure(buffer, type);
}
finally
{
handle.Free();
}
return retobj;
}
【问题讨论】:
-
"This code is throw System.TypeLoadException"Buy 你没有显示任何实际的代码,只有结构定义。显示异常发生的位置。 -
@Jonathon Reinhart,Marshal.PtrToStructure 方法中抛出异常。
-
@Ken Variant 记录与联合相同。但是使用
FieldOffset可以解决这个问题。 AFIR,real长期以来一直是double的别名(我怀疑是Delphi 2)。还有SizeOf(ShortString)=256。
标签: c# delphi pinvoke marshalling