Delphi Enums to Variant as varInteger instead of varUInt32

别来无恙 提交于 2020-01-15 09:21:30

问题


Delphi enumeration values are natively defined as unsigned integers - 1, 2 or 4 bytes, depending on the setting of MINENUMSIZE.

I have a case where we are using Variants to transfer data of different data types between applications. All other data types work nicely, but now we realised that the expectation from other applications is that the enumerated values should be signed integers instead of unsigned (and some are really validating this).

Is there a way to configure the automatic variant conversion that the enumeration values would be converted to varInteger, instead of varUInt32?

The background: we are writing library code for OPC UA. OPC UA defines a type called Variant, which has history in Windows Variant, but is now defined in a different way. In practice, OPC UA defines that enumeration values are transferred as Int32 over the wire.

OPC UA also defines a data type called DataValue, which consists of the Value (as Variant), StatusCode (UInt32) and some Timestamp fields.

Now, we are using Delphi Variants for mapping the OPC UA Variant, since it works nicely in general. Now the only major pitfall is that when you write an enumeration value to the Variant it is converted to UInt32, whereas OPC UA expects Int32.

The library takes in Variants (in DataValues) and as an application developer, you can just assign your enumeration values to the DataValue and everything looks good. However, the value has been converted to an UInt32 and when the library code sees this Variant it cannot know anymore that it corresponds actually to an enumeration type of variable.

Should we be able to control the automatic conversion (or actually the native data type of enumerations), we could simply get rid of this problem with that.

If that is not possible, we will really have to invent conversion code, wherever we can, but which can never be 100% certain, after all.


回答1:


You can't distinguish between assignment of enumerated type to variant, and assignment of integer type to variant. Consider the following code:

uses
  System.SysUtils;

type
  TFoo = (foo, bar);

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

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

The compiler generates the following:

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

So even if you hook the library routine that handles such an assignment (System.Variants._VarFromInt), you will inevitably pick up assignments of Byte values as well as enumerated type values.

The above code assumes single byte enumerated type size, but nothing much changes for 2 or 4 byte enumerated types. Instead of the assignment looking like a byte assignment it looks like a Word or LongWord assignment, respectively.



来源:https://stackoverflow.com/questions/52946989/delphi-enums-to-variant-as-varinteger-instead-of-varuint32

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!