I know this has been asked before, but I am unsuccessfully trying to convert some C++ structures/unions to Delphi to use the Hikvision SDK.
The C++ structures/unions I’m trying to convert are as follow:
struct{
BYTE byEnable;
BYTE byRes1[3];
DWORD dwTriggerType;
NET_ITC_TRIGGER_PARAM_UNION uTriggerParam;
BYTE byRes[64];
}NET_ITC_SINGLE_TRIGGERCFG,*LPNET_ITC_SINGLE_TRIGGERCFG;
union{
DWORD uLen[1070];
NET_ITC_POST_IOSPEED_PARAM struIOSpeed;
NET_ITC_POST_SINGLEIO_PARAM struSingleIO;
NET_ITC_POST_RS485_PARAM struPostRs485;
NET_ITC_POST_RS485_RADAR_PARAM struPostRadar;
NET_ITC_POST_VTCOIL_PARAM struVtCoil;
NET_ITC_EPOLICE_IOTL_PARAM struIOTL;
NET_ITC_EPOLICE_RS485_PARAM struEpoliceRs485;
NET_ITC_EPOLICE_RS485_PARAM struPERs485;
}NET_ITC_TRIGGER_PARAM_UNION,*LPNET_ITC_TRIGGER_PARAM_UNION;
I have tried the following:
PNetItcSingleTriggerCfg = ^TNetItcSingleTriggerCfg;
TNetItcSingleTriggerCfg = record
byEnable: Byte;
byRes1: array [0..2] of Byte;
dwTriggerType: DWord;
uTriggerParam: TNetItcTriggerParamUnion;
byRes: array [0..63] of Byte;
end;
PNetItcTriggerParamUnion = ^TNetItcTriggerParamUnion;
TNetItcTriggerParamUnion = record
case integer of
0: (uLen: array [0..1069] of DWord);
1: (struIOSpeed: TNetItcPostIOSpeedParam);
2: (struSingleIO: TNetItcPostSingleIOParam);
3: (struPostRs485: TNetItcPostRS485Param);
4: (struPostRadar: TNetItcPostRS485RadarParam);
5: (struVtCoil: TNetItcPostVTCoilParam);
6: (struHvt: TNetItcPostHvtParam);
7: (struIOTL: TNetItcEPoliceIOTLParam);
8: (struEpoliceRs485: TNetItcEPoliceRS485Param);
9: (struPERs485: TNetItcEPoliceRS485Param);
10:(struPostMpr: TNetItcPostMprParam);
11:(struViaVtCoil: TNetDvrViaVtCoilParam);
12:(struPostImt: TNetItcPostImtParam);
13:(struPostPrs: TNetItcPostPrsParam);
14:(struIpcHvt: TNetIpcPostHvtParam);
15:(struHvtV50: TNetIpcPostHvtParamV50);
end;
And I have also tried having it as a nested record (as suggested here http://rvelthuis.de/articles/articles-convert.html#unions )
PNetItcSingleTriggerCfg = ^TNetItcSingleTriggerCfg;
TNetItcSingleTriggerCfg = record
byEnable: Byte;
byRes1: array [0..2] of Byte;
dwTriggerType: DWord;
uTriggerParam: record
case integer of
0: (uLen: array [0..1069] of DWord);
1: (struIOSpeed: TNetItcPostIOSpeedParam);
2: (struSingleIO: TNetItcPostSingleIOParam);
3: (struPostRs485: TNetItcPostRS485Param);
4: (struPostRadar: TNetItcPostRS485RadarParam);
5: (struVtCoil: TNetItcPostVTCoilParam);
6: (struHvt: TNetItcPostHvtParam);
7: (struIOTL: TNetItcSingleIOTLParam);
8: (struEpoliceRs485: TNetItcEPoliceRS485Param);
9: (struPERs485: TNetItcEPoliceRS485Param);
10:(struPostMpr: TNetItcPostMprParam);
11:(struViaVtCoil: TNetDvrViaVtCoilParam);
12:(struPostImt: TNetItcPostImtParam);
13:(struPostPrs: TNetItcPostPrsParam);
14:(struIpcHvt: TNetIpcPostHvtParam);
15:(struHvtV50: TNetIpcPostHvtParamV50);
end;
byRes: array [0..63] of Byte;
end;
I have seen similar questions on here (i.e. How do I translate a C union into Delphi? ), but the union in my example is in the middle of the structure, and as I understand the ‘end’ of the case statement also ends the record.
I think I understand the theory behind a variant record having the same memory allocation for the fields in the case statement, so the fields used would be either/or, but what I can’t work out is how to tell how the DLL is accessing these records, whether it is struName.unionName.fieldName or struName.fieldName and also how the union is defined (i.e. what is the selector of the case statement, and how to know what data type the selector is).
I have three similar structures to translate, and figure if I can crack one, I can crack them all.
With the records as described above, I keep getting the error message ‘Parameter error. Input or output parameter in the SDK API is NULL’ whilst calling a function from the DLL (if you need more information on this, please ask), which makes me think that my records have not been converted correctly.
I’m using the HCNetSDK.dll SDK version 5.0.3.20 and my IDE is XE7 if that helps.
Any help would be appreciated.
Assuming that structure alignment settings match then both of your attempts to convert the union are correct. You can use whichever one you prefer. For what it is worth, I would prefer the first approach where you declare a type to represent the union.
Whatever your actual problem is, it does not appear to lie with the union conversion. A simple way to test this is to check that the size of the types match in the C++ and Delphi versions, and that the offsets to each member match.
For test the size of a type use sizeof
in C++ and SizeOf
in Delphi. For the offsets use the offsetof
macro for C++ and the trick shown in my answer here for Delphi.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With