Read VARIANT while marshaling stream from x32 to x64|Classic OPC: DA, A&E, HDA, XML-DA, etc.|Forum|OPC Foundation

Avatar
Search
Forum Scope


Match



Forum Options



Minimum search word length is 3 characters - maximum search word length is 84 characters
Lost password?
sp_Feed sp_PrintTopic sp_TopicIcon
Read VARIANT while marshaling stream from x32 to x64
Avatar
TelWin SCADA
New Member
Members
Forum Posts: 2
Member Since:
04/28/2016
sp_UserOfflineSmall Offline
1
05/24/2018 - 02:23
sp_Permalink sp_Print

I'm making possible to read data between x32 and x64 (in both ways) between opc da server and client.

I run in to problem with reading VARIANT from stream, the stream is send by callback:

STDMETHODIMP_(void) OnDataChange(FORMATETC *pFmt, STGMEDIUM *pStg);

The data in pStg consists of a group header followed by one or more item headers followed by the data:

OPCGROUPHEADER

OPCITEMHEADER[hdr.dwItemCount]

VARIANTS[hdr.dwItemCount]

Problem exist when VARIANT is type of BSTR, in that case VARIANT union is followed by a DWORD - byte count of BSTR and BSTR bytes, so when I move by the sizeof(VARIANT) to read BSTR I have diffrent sizeof depend of compilation (x32 or x64), so what is the best way to unified marshaling the data to be undependent from bit version?

Exist a some kind of standard to write/read the stream?, for example we always write VARIANT as x32 bit version, and read it in the same way.

Avatar
Zbynek Zahradnik
Member
Members
Forum Posts: 62
Member Since:
02/24/2014
sp_UserOfflineSmall Offline
2
05/24/2018 - 22:54
sp_Permalink sp_Print

You should not be moving by sizeof(VARIANT). Instead, you should "seek" to a specific position. Precisely for this purpose, there are dwValueOffset fields in the OPCITEMHEADER1 and OPCITEMHEADER2 structures that precede the actual VARIANTs in the stream.

 

Best regards

Zbynek Zahradnik

Avatar
TelWin SCADA
New Member
Members
Forum Posts: 2
Member Since:
04/28/2016
sp_UserOfflineSmall Offline
3
05/28/2018 - 01:52
sp_Permalink sp_Print

But how to read  BSTR, when is after the VARIANT then? And I can only seek to each VARIANT, not to string.

Avatar
Zbynek Zahradnik
Member
Members
Forum Posts: 62
Member Since:
02/24/2014
sp_UserOfflineSmall Offline
4
05/31/2018 - 23:07
sp_Permalink sp_Print sp_EditHistory

The OPC DA 1.0 spec was written in 1997 and only assumed 32-bit world. Interoperability with 64-bit world is not a problem for method calls or data directly on COM interfaces, because OPC proxies/stubs take care of proper marshalling/unmarshalling while maintaining the same "wire format" between them.

But you are right, it is kind of problem with the "special" IAdviseSink/IDataObject, because the OPC spec defines a streamed format for the data, and refers to "VARIANT" being placed on the stream, without realizing that its binary layout may differ. Given the origins of the spec, I think the developers should always assume that when OPC DA 1.0 spec talk about some structure in this format, in means the 32-bit layout of it. This applies to VARIANT, and also to SAFEARRAY; not so much to BSTR itself, because how BSTR should be represented in the stream is described verbatim in the spec:

For a BSTR the union is followed without padding by an image of the BSTR. The BSTR image will include the terminating NUL (WIDE char). Note that BSTRs contain WIDE chars which are 2 bytes each. The BSTR starts with a DWORD byte count followed by 'count' bytes of data followed by 2 bytes of 0. Thus the total space required for the BSTR is the number of bytes specified in count + 6 (4 for the DWORD count and 2 for the trailing NUL).

I think the answer to your question is therefore as follows: If anybody is to write OPC DA 1.0-compatible server or client, he should interpret the references to VARIANT and SAFEARRAY on the OPC data stream in the spec as having the layout they have in 32 bit Windows. With some effort, it is perfectly possible to remake the 32-bit layout in 64-bit code. In fact, I looked shortly at the definition of VARIANT. It totals to 16 bytes in 32-bits and to 24 bytes on 64-bit, but the difference is only due to last member of the union which is "BRECORD", not used in OPC at all. So, if you are writing a 64-bit server, it should be safe to simply put the first 16 bytes of your 24-byte VARIANT onto the stream. If you are writing 64-bit client, it should be safe to clear your 24-byte VARIANT and then copy 16 bytes to it from the stream, and move your position by 16 bytes.

OPC DA 2.0 and OPC DA 3.0 do not use the IDataObject and are therefore free of this issue altogether.

Best regards

Forum Timezone: America/Phoenix
Most Users Ever Online: 510
Currently Online:
Guest(s) 32
Currently Browsing this Page:
1 Guest(s)
Top Posters:
Forum Stats:
Groups: 2
Forums: 10
Topics: 1351
Posts: 4579