Tagged structures in Visual Basic are in close analogy with their counterparts in C. The principal caveates include
An in C, the first step is to register the structure. You do this at initialization time by declaring a structure tag name and filling in the sizes and locations of the individual elements. Then when a client sends or asks for a structure and it sends the structure tag along with the request, the server knows all about the structure and how to handle it.
In Visual Basic this might look like
' make sure tine.bas is included in the project ! Option Explicit Private Const NUM_DEVICES = 10 Private Const NUM_VALUES = 1024 * 8 Private Type SineInfo amplitude As Single frequency As Single noise As Single phase As Single numberCalls As Long Description(63) As Byte End Type Dim sineInfoTable(NUM_DEVICES - 1) As SineInfo 'other variables omitted ... Private Sub Form_Load() ' other initialization omitted .... Call RegisterStructs ' other initialization omitted .... End Sub Sub RegisterStructs() Dim offset As Long ' this must follow the order of the structure explicitly! ' note: in VB the alignment is always 4-bytes (do not leave alignment gaps!) ' offset is then always the accumulated size in bytes (Len) of the structure fields AddFieldToStruct "SineInfo", offset, 1, CF_FLOAT, "amplitude" offset = offset + Len(sineInfoTable(0).amplitude) AddFieldToStruct "SineInfo", offset, 1, CF_FLOAT, "frequency" offset = offset + Len(sineInfoTable(0).frequency) AddFieldToStruct "SineInfo", offset, 1, CF_FLOAT, "noise" offset = offset + Len(sineInfoTable(0).noise) AddFieldToStruct "SineInfo", offset, 1, CF_FLOAT, "phase" offset = offset + Len(sineInfoTable(0).phase) AddFieldToStruct "SineInfo", offset, 1, CF_LONG, "numberCalls" offset = offset + Len(sineInfoTable(0).numberCalls) AddFieldToStruct "SineInfo", offset, 64, CF_TEXT, "Description" ' terminate the registration : SealTaggedStruct "SineInfo", Len(sineInfoTable(0)), NUM_DEVICES End Sub
A Visual Basic server then might make use of something like the following within its equiment module dispatch event handler:
Private Sub Srv1_EqpFcn(ByVal DevName As String, ByVal devProperty As String, ByVal outArrayLen As Long, ByVal inArrayLen As Long, ByVal devAccess As Integer)
Dim devnr As Integer, i As Integer, cc As Integer
Dim sinf As SineInfo
devnr = Srv1.EqpGetModuleNumber(DevName)
If (devnr < 0 Or devnr >= NUM_DEVICES) Then
Srv1.EqpSetCompletion illegal_equipment_number, ""
Exit Sub
End If
Select Case devProperty
Case "Sine":
If (devAccess And CA_WRITE) = CA_WRITE Then
Srv1.EqpSetCompletion illegal_read_write, ""
Exit Sub
End If
Srv1.EqpSendData sinbuf(0, devnr)
sineInfoTable(devnr).numberCalls = sineInfoTable(devnr).numberCalls + 1
' other properties omitted ...
Case "SineInfo":
If (inArrayLen > 0) Then
If (devAccess And CA_WRITE) <> CA_WRITE Then
Srv1.EqpSetCompletion illegal_read_write, ""
Exit Sub
End If
' allow an atomic set of all relevant values this way ...
cc = 0
Srv1.EqpRecvData sinf.amplitude
If (sinf.amplitude < 1 Or sinf.amplitude > 1000) Then cc = out_of_range
If (sinf.frequency < 1 Or sinf.frequency > 100) Then cc = out_of_range
If (sinf.phase < 1 Or sinf.phase > 512) Then cc = out_of_range
If (sinf.noise < 1 Or sinf.noise > 100) Then cc = out_of_range
If cc <> 0 Then
Srv1.EqpSetCompletion cc, ""
Exit Sub
End If
sineInfoTable(devnr) = sinf
End If
If (outArrayLen > 0) Then
Srv1.EqpSendData sineInfoTable(0).amplitude
End If
Case Else:
Srv1.EqpSetCompletion illegal_property, ""
Exit Sub
End Select
Srv1.EqpSetCompletion 0, ""
End Sub
A Visual Basic client application would access a user-defined structure using code something like the following:
' Example using an ACOP control to get an array of structures ... Dim sininf(9) As SineInfo sub GetSineInfo() Dim rc As Integer ACOP1.DeviceContext = "TEST" ACOP1.DeviceGroup = "SineServer" ACOP1.DeviceName = "SineGen0" ACOP1.AccessRate = 1000 ' ACOP1.AccessMode = "READ" ACOP1.DeviceProperty = "SineInfo" rc = ACOP1.Execute(sininf(0).amplitude, 10, "STRUCT/SineInfo") End Sub
1.5.8