Delphi 将 Variant 枚举为 varInteger 而不是 varUInt32

Delphi Enums to Variant as varInteger instead of varUInt32

Delphi 枚举值本身定义为无符号整数 - 1、2 或 4 字节,具体取决于 MINENUMSIZE 的设置。

我有一个案例,我们使用变体在应用程序之间传输不同数据类型的数据。所有其他数据类型都可以很好地工作,但现在我们意识到其他应用程序的期望是枚举值应该是有符号整数而不是无符号整数(有些确实在验证这一点)。

有没有办法配置自动变量转换,将枚举值转换为 varInteger,而不是 varUInt32?

背景:我们正在为OPC UA编写库代码。 OPC UA 定义了一个名为 Variant 的类型,它在 Windows Variant 中有历史,但现在以不同的方式定义。实际上,OPC UA 定义枚举值作为 Int32 通过网络传输。

OPC UA 还定义了一种称为 DataValue 的数据类型,它由 Value(作为 Variant)、StatusCode (UInt32) 和一些 Timestamp 字段组成。

现在,我们使用 Delphi 变体来映射 OPC UA 变体,因为它通常工作得很好。现在唯一的主要缺陷是,当您将枚举值写入 Variant 时,它会转换为 UInt32,而 OPC UA 需要 Int32。

该库接受 Variants(在 DataValues 中),作为应用程序开发人员,您只需将枚举值分配给 DataValue,一切看起来都不错。但是,该值已转换为 UInt32,当库代码看到此 Variant 时,它无法再知道它实际上对应于枚举类型的变量。

如果我们能够控制自动转换(或者实际上是枚举的本机数据类型),我们可以简单地解决这个问题。

如果那不可能,我们真的必须尽可能地发明转换代码,但毕竟永远不能 100% 确定。

您无法区分将枚举类型赋值给变体和将整数类型赋值给变体。考虑以下代码:

uses
  System.SysUtils;

type
  TFoo = (foo, bar);

var
  V: Variant;
  enum: TFoo;
  b: Byte;

begin
  V := enum;
  V := b;
end.

编译器生成以下内容:

Project52946989.dpr.14: V := enum;
00422562 B8389F4200       mov eax,[=15=]429f38
00422567 33D2             xor edx,edx
00422569 8A15489F4200     mov dl,[[=15=]429f48]
0042256F B101             mov cl,
00422571 E8BED1FFFF       call @VarFromInt
Project52946989.dpr.15: V := b;
00422576 B8389F4200       mov eax,[=15=]429f38
0042257B 33D2             xor edx,edx
0042257D 8A15499F4200     mov dl,[[=15=]429f49]
00422583 B101             mov cl,
00422585 E8AAD1FFFF       call @VarFromInt

因此,即使您挂钩处理此类赋值 (System.Variants._VarFromInt) 的库例程,您也将不可避免地获取 Byte 值的赋值以及枚举类型值。

以上代码假定单字节枚举类型大小,但对于 2 或 4 字节枚举类型没有太大变化。赋值看起来不像字节赋值,而是分别看起来像 WordLongWord 赋值。