如何将Delphi的记录类型高效转换为C语言的对应结构体?

2026-04-28 00:492阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1271个文字,预计阅读时间需要6分钟。

如何将Delphi的记录类型高效转换为C语言的对应结构体?

将现代代码从Delphi转换为C#,主要步骤如下:

1. 项目结构:C#项目通常使用.NET框架,因此项目结构会有所不同。Delphi项目可能包含多个单元文件,而C#项目可能使用类和命名空间。

2. 语法差异: - 变量声明:Delphi中通常使用`var`关键字声明变量,而C#中直接使用变量名。 - 数据类型:Delphi和C#的数据类型有很多相似之处,但也有一些差异,例如C#中没有`Variant`类型。

3. 控制结构: - 循环:Delphi中的`for`循环和C#中的类似,但需要注意循环变量的初始化和条件。 - 条件语句:Delphi的`if`、`then`、`else`和C#的对应结构基本相同。

4. 函数和过程: - Delphi中的函数和过程在C#中分别对应方法和委托。 - 函数返回值在C#中需要指定返回类型。

5. 异常处理: - Delphi使用`try...except`结构,C#也使用类似的`try...catch`。

6. 数据库访问: - Delphi通常使用ADO或FireDAC进行数据库访问,而C#可以使用ADO.NET、Entity Framework等。

如何将Delphi的记录类型高效转换为C语言的对应结构体?

7. 界面设计: - Delphi的界面设计通常在IDE中进行,而C#的界面设计可以使用Windows Forms或WPF。

8. 代码转换工具: - 一些第三方工具可以帮助将Delphi代码转换为C#,但可能需要手动调整。

举例:Delphi代码:delphiprocedure TForm1.Button1Click(Sender: TObject);var i: Integer;begin for i :=1 to 10 do ShowMessage(IntToStr(i));end;C#代码:csharppublic partial class MainForm : Form{ public MainForm() { InitializeComponent(); }

private void Button1_Click(object sender, EventArgs e) { for (int i=1; i <=10; i++) { MessageBox.Show(i.ToString()); } }}

如何将此代码从Delphi转换为C#?我需要struct与unmaneged代码进行交互.

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; } 你有几个问题.

首先,C#DateTime不映射到Delphi TDateTime.您需要在C#代码中使用double,并编写从C#日期/时间到Delphi日期/时间的映射.

第二个问题,更严重的是,确实是字符串.在Delphi中,ShortString是256字节宽.第一个字节包含字符串长度,其余255个是有效负载.

您不能在C#联合中使用非引用类型覆盖引用类型.这是你的问题.除了作为引用类型的字符串之外,所有重叠变量都是值类型. Hans Passant在这里讨论了这个问题:C# Platform-invoke, c-style union with reference and value types.请注意,他明确地提到了您遇到的异常.

在MSDN,您可以找到相同的信息:

In managed code, value types and reference types are not permitted to overlap.

对此问题的正常响应是停止混合引用和值类型.最好只使用blittable值类型.但我没有看到一个明显的方法来做到这一点.您可以使用固定的字节数组,但这会强制您使用不安全的处理固定数组并不是很有趣.可以在此处找到该方法的示例:Marshaling structure with reference-type and value-type members inside a union.

因此,我建议您手动编组记录的变体部分.使用UnmanagedType.ByValArray将其声明为byte [].

[StructLayout(LayoutKind.Sequential)] [Serializable] internal struct DataTypeParam { public DataType dtType; [MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] public byte[] dtUnion; };

然后你需要编写助手来从/向字节数组读/写单个字段.有了这些助手,你的结构可能看起来像这样:

[StructLayout(LayoutKind.Sequential)] [Serializable] internal struct DataTypeParam { public int dtType; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] private byte[] dtUnion; public int cInt { get { return BitConverter.ToInt32(dtUnion, 0); } set { dtUnion = BitConverter.GetBytes(value); } } public double cFloat { get { return BitConverter.ToDouble(dtUnion, 0); } set { dtUnion = BitConverter.GetBytes(value); } } };

我会让你写下剩下的帮手.

本文共计1271个文字,预计阅读时间需要6分钟。

如何将Delphi的记录类型高效转换为C语言的对应结构体?

将现代代码从Delphi转换为C#,主要步骤如下:

1. 项目结构:C#项目通常使用.NET框架,因此项目结构会有所不同。Delphi项目可能包含多个单元文件,而C#项目可能使用类和命名空间。

2. 语法差异: - 变量声明:Delphi中通常使用`var`关键字声明变量,而C#中直接使用变量名。 - 数据类型:Delphi和C#的数据类型有很多相似之处,但也有一些差异,例如C#中没有`Variant`类型。

3. 控制结构: - 循环:Delphi中的`for`循环和C#中的类似,但需要注意循环变量的初始化和条件。 - 条件语句:Delphi的`if`、`then`、`else`和C#的对应结构基本相同。

4. 函数和过程: - Delphi中的函数和过程在C#中分别对应方法和委托。 - 函数返回值在C#中需要指定返回类型。

5. 异常处理: - Delphi使用`try...except`结构,C#也使用类似的`try...catch`。

6. 数据库访问: - Delphi通常使用ADO或FireDAC进行数据库访问,而C#可以使用ADO.NET、Entity Framework等。

如何将Delphi的记录类型高效转换为C语言的对应结构体?

7. 界面设计: - Delphi的界面设计通常在IDE中进行,而C#的界面设计可以使用Windows Forms或WPF。

8. 代码转换工具: - 一些第三方工具可以帮助将Delphi代码转换为C#,但可能需要手动调整。

举例:Delphi代码:delphiprocedure TForm1.Button1Click(Sender: TObject);var i: Integer;begin for i :=1 to 10 do ShowMessage(IntToStr(i));end;C#代码:csharppublic partial class MainForm : Form{ public MainForm() { InitializeComponent(); }

private void Button1_Click(object sender, EventArgs e) { for (int i=1; i <=10; i++) { MessageBox.Show(i.ToString()); } }}

如何将此代码从Delphi转换为C#?我需要struct与unmaneged代码进行交互.

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; } 你有几个问题.

首先,C#DateTime不映射到Delphi TDateTime.您需要在C#代码中使用double,并编写从C#日期/时间到Delphi日期/时间的映射.

第二个问题,更严重的是,确实是字符串.在Delphi中,ShortString是256字节宽.第一个字节包含字符串长度,其余255个是有效负载.

您不能在C#联合中使用非引用类型覆盖引用类型.这是你的问题.除了作为引用类型的字符串之外,所有重叠变量都是值类型. Hans Passant在这里讨论了这个问题:C# Platform-invoke, c-style union with reference and value types.请注意,他明确地提到了您遇到的异常.

在MSDN,您可以找到相同的信息:

In managed code, value types and reference types are not permitted to overlap.

对此问题的正常响应是停止混合引用和值类型.最好只使用blittable值类型.但我没有看到一个明显的方法来做到这一点.您可以使用固定的字节数组,但这会强制您使用不安全的处理固定数组并不是很有趣.可以在此处找到该方法的示例:Marshaling structure with reference-type and value-type members inside a union.

因此,我建议您手动编组记录的变体部分.使用UnmanagedType.ByValArray将其声明为byte [].

[StructLayout(LayoutKind.Sequential)] [Serializable] internal struct DataTypeParam { public DataType dtType; [MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] public byte[] dtUnion; };

然后你需要编写助手来从/向字节数组读/写单个字段.有了这些助手,你的结构可能看起来像这样:

[StructLayout(LayoutKind.Sequential)] [Serializable] internal struct DataTypeParam { public int dtType; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] private byte[] dtUnion; public int cInt { get { return BitConverter.ToInt32(dtUnion, 0); } set { dtUnion = BitConverter.GetBytes(value); } } public double cFloat { get { return BitConverter.ToDouble(dtUnion, 0); } set { dtUnion = BitConverter.GetBytes(value); } } };

我会让你写下剩下的帮手.