// Shows how to process a data type, displaying some of its properties, recursively.
using System;
using System.Linq;
using OpcLabs.BaseLib.DataTypeModel;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.OperationModel;
using OpcLabs.EasyOpc.UA.Plugins.ComplexData;
namespace UADocExamples.ComplexData._DataType
{
class Kind
{
public static void Main1()
{
// Define which server and node we will work with.
UAEndpointDescriptor endpointDescriptor =
"opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
// or "http://opcua.demo-this.com:51211/UA/SampleServer" (not in .NET Standard)
// or "https://opcua.demo-this.com:51212/UA/SampleServer/"
UANodeDescriptor nodeDescriptor =
"nsu=http://test.org/UA/Data/;i=10239"; // [ObjectsFolder]/Data.Static.Scalar.StructureValue
// Instantiate the client object.
var client = new EasyUAClient();
// Read a node. We know that this node returns complex data, so we can type cast to UAGenericObject.
UAGenericObject genericObject;
try
{
genericObject = (UAGenericObject)client.ReadValue(endpointDescriptor, nodeDescriptor);
}
catch (UAException uaException)
{
Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
return;
}
// The data type is in the GenericData.DataType property of the UAGenericObject.
DataType dataType = genericObject.GenericData.DataType;
// Process the data type. We will inspect some of its properties, and dump them.
ProcessDataType(dataType, maximumDepth: 2);
}
// Process the data type. It can be recursive in itself, so if you do not know the data type you are dealing with,
// it is recommended to make safeguards against infinite looping or recursion - here, the maximumDepth.
public static void ProcessDataType(DataType dataType, int maximumDepth)
{
if (maximumDepth == 0)
return;
Console.WriteLine();
Console.WriteLine("dataType.Name: {0}", dataType.Name);
switch (dataType.Kind)
{
case DataTypeKind.Enumeration:
Console.WriteLine("The data type is an enumeration.");
var enumerationDataType = (EnumerationDataType) dataType;
Console.WriteLine("It has {0} enumeration members.", enumerationDataType.EnumerationMembers.Count);
Console.WriteLine("The names of the enumeration members are: {0}.",
String.Join(", ", enumerationDataType.EnumerationMembers.Select(member => member.Name)));
// Here you can process the members, or inspect SizeInBits etc.
break;
case DataTypeKind.Opaque:
Console.WriteLine("The data type is opaque.");
var opaqueDataType = (OpaqueDataType) dataType;
Console.WriteLine("Its size is {0} bits.", opaqueDataType.SizeInBits);
// There isn't much more you can learn about an opaque data type (well, it may have Description and
// other common members). It is, after all, opaque...
break;
case DataTypeKind.Primitive:
Console.WriteLine("The data type is primitive.");
var primitiveDataType = (PrimitiveDataType) dataType;
Console.WriteLine("Its .NET value type is \"{0}\".", primitiveDataType.ValueType);
// There isn't much more you can learn about the primitive data type.
break;
case DataTypeKind.Sequence:
Console.WriteLine("The data type is a sequence.");
var sequenceDataType = (SequenceDataType) dataType;
Console.WriteLine("Its length is {0} (-1 means that the length can vary).", sequenceDataType.Length);
Console.WriteLine("A dump of the element data type follows.");
ProcessDataType(sequenceDataType.ElementDataType, maximumDepth - 1);
break;
case DataTypeKind.Structured:
Console.WriteLine("The data type is structured.");
var structuredDataType = (StructuredDataType) dataType;
Console.WriteLine("It has {0} data fields.", structuredDataType.DataFields.Count);
Console.WriteLine("The names of the data fields are: {0}.",
String.Join(", ", structuredDataType.DataFields.Select(field => field.Name)));
Console.WriteLine("A dump of each of the data fields follows.");
foreach (DataField dataField in structuredDataType.DataFields)
{
Console.WriteLine();
Console.WriteLine("dataField.Name: {0}", dataField.Name);
// Note that every data field also has properties like IsLength, IsOptional, IsSwitch which might
// be of interest but we are not dumping them here.
ProcessDataType(dataField.DataType, maximumDepth - 1);
}
break;
}
}
}
}
// Shows how to process a data type, displaying some of its properties, recursively.
class procedure Kind.Main;
var
Client: _EasyUAClient;
DataType: OpcLabs_BaseLib_TLB._DataType;
EndpointDescriptor: string;
GenericObject: _UAGenericObject;
NodeDescriptor: string;
begin
// Define which server and node we will work with.
EndpointDescriptor := 'http://opcua.demo-this.com:51211/UA/SampleServer';
//or 'https://opcua.demo-this.com:51212/UA/SampleServer/';
//or 'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';
NodeDescriptor := 'nsu=http://test.org/UA/Data/;i=10239'; // [ObjectsFolder]/Data.Static.Scalar.StructureValue
// Instantiate the client object
Client := CoEasyUAClient.Create;
// Read a node. We know that this node returns complex data, so we can type cast to UAGenericObject.
try
GenericObject := IUnknown(Client.ReadValue(EndpointDescriptor, NodeDescriptor)) as _UAGenericObject;
except
on E: EOleException do
begin
WriteLn(Format('*** Failure: %s', [E.GetBaseException.Message]));
Exit;
end;
end;
// The data type is in the GenericData.DataType property of the UAGenericObject.
DataType := genericObject.GenericData.DataType;
// Process the data type. We will inspect some of its properties, and dump them.
ProcessDataType(DataType, 2);
end;
// Process the data type. It can be recursive in itself, so if you do not know the data type you are dealing with,
// it is recommended to make safeguards against infinite looping or recursion - here, the maximumDepth.
class procedure Kind.ProcessDataType(DataType: OpcLabs_BaseLib_TLB._DataType; MaximumDepth: Cardinal);
var
Count: Cardinal;
DataField: _DataField;
Element: OleVariant;
ElementEnumerator: IEnumVARIANT;
EnumerationMember: _EnumerationMember;
EnumerationDataType: _EnumerationDataType;
FieldNames: string;
First: boolean;
MemberNames: string;
OpaqueDataType: _OpaqueDataType;
PrimitiveDataType: _PrimitiveDataType;
SequenceDataType: _SequenceDataType;
StructuredDataType: _StructuredDataType;
TypeName: WideString;
begin
if MaximumDepth = 0 then
Exit;
WriteLn;
WriteLn('dataType.Name: ', DataType.Name);
case DataType.Kind of
DataTypeKind_Enumeration:
begin
WriteLn('The data type is an enumeration.');
EnumerationDataType := DataType as _EnumerationDataType;
WriteLn(Format('It has %s enumeration members.', [EnumerationDataType.EnumerationMembers.Count]));
ElementEnumerator := EnumerationDataType.EnumerationMembers.GetEnumerator;
MemberNames := '';
First := True;
while (ElementEnumerator.Next(1, Element, Count) = S_OK) do
begin
EnumerationMember := IUnknown(Element) as _EnumerationMember;
if First then
First := False
else
MemberNames := MemberNames + ', ';
MemberNames := MemberNames + EnumerationMember.Name;
end;
WriteLn(Format('The names of the enumeration members are: %s.', [MemberNames]));
// Here you can process the members, or inspect SizeInBits etc.
end;
DataTypeKind_Opaque:
begin
WriteLn('The data type is opaque.');
OpaqueDataType := DataType as _OpaqueDataType;
WriteLn(Format('Its size is %s bits.', [OpaqueDataType.SizeInBits]));
// There isn't much more you can learn about an opaque data type (well, it may have Description and
// other common members). It is, after all, opaque...
end;
DataTypeKind_Primitive:
begin
WriteLn('The data type is primitive.');
PrimitiveDataType := DataType as _PrimitiveDataType;
PrimitiveDataType.ValueType.Get_ToString(TypeName);
WriteLn(Format('Its .NET value type is "%s".', [TypeName]));
// There isn't much more you can learn about the primitive data type.
end;
DataTypeKind_Sequence:
begin
WriteLn('The data type is a sequence.');
SequenceDataType := DataType as _SequenceDataType;
WriteLn(Format('Its length is %s (-1 means that the length can vary).', [SequenceDataType.Length.ToString]));
WriteLn('A dump of the element data type follows.');
ProcessDataType(SequenceDataType.ElementDataType, MaximumDepth - 1);
end;
DataTypeKind_Structured:
begin
WriteLn('The data type is structured.');
StructuredDataType := DataType as _StructuredDataType;
WriteLn(Format('It has %s data fields.', [StructuredDataType.DataFields.Count.ToString]));
ElementEnumerator := StructuredDataType.DataFields.GetEnumerator;
FieldNames := '';
First := True;
while (ElementEnumerator.Next(1, Element, Count) = S_OK) do
begin
if First then
First := False
else
FieldNames := FieldNames + ', ';
FieldNames := FieldNames + Element.Name;
end;
WriteLn(Format('The names of the data fields are: %s.', [FieldNames]));
WriteLn('A dump of each of the data fields follows.');
ElementEnumerator := StructuredDataType.DataFields.GetEnumerator;
while (ElementEnumerator.Next(1, Element, Count) = S_OK) do
begin
DataField := IUnknown(Element) as _DataField;
WriteLn;
WriteLn(Format('dataField.Name: %s', [DataField.Name]));
// Note that every data field also has properties like IsLength, IsOptional, IsSwitch which might
// be of interest but we are not dumping them here.
ProcessDataType(DataField.DataType, MaximumDepth - 1);
end;
end;
end;
end;
' Shows how to process a data type, displaying some of its properties, recursively.
Imports System
Imports System.Linq
Imports OpcLabs.BaseLib.DataTypeModel
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.OperationModel
Imports OpcLabs.EasyOpc.UA.Plugins.ComplexData
Namespace UADocExamples.ComplexData._DataType
Friend Class Kind
Public Shared Sub Main1()
' Define which server we will work with.
Dim endpointDescriptor As UAEndpointDescriptor =
"opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
' or "http://opcua.demo-this.com:51211/UA/SampleServer" (not in .NET Standard)
' or "https://opcua.demo-this.com:51212/UA/SampleServer/"
' Define which node we will work with.
Dim nodeDescriptor As UANodeDescriptor = _
"nsu=http://test.org/UA/Data/;i=10239" ' [ObjectsFolder]/Data.Static.Scalar.StructureValue
' Instantiate the client object.
Dim client = New EasyUAClient
' Read a node. We know that this node returns complex data, so we can type cast to UAGenericObject.
Dim genericObject As UAGenericObject
Try
genericObject = CType(client.ReadValue(endpointDescriptor, nodeDescriptor), UAGenericObject)
Catch uaException As UAException
Console.WriteLine("*** Failure: {0}", uaException.GetBaseException.Message)
Exit Sub
End Try
' The data type is in the GenericData.DataType property of the UAGenericObject.
Dim dataType As DataType = genericObject.GenericData.DataType
' Process the data type. We will inspect some of its properties, and dump them.
ProcessDataType(dataType, maximumDepth:=2)
End Sub
' Process the data type. It can be recursive in itself, so if you do not know the data type you are dealing with,
' it is recommended to make safeguards against infinite looping or recursion - here, the maximumDepth.
Public Shared Sub ProcessDataType(dataType As DataType, ByVal maximumDepth As Integer)
If (maximumDepth = 0) Then
Return
End If
Console.WriteLine()
Console.WriteLine("dataType.Name: {0}", dataType.Name)
Select Case (dataType.Kind)
Case DataTypeKind.Enumeration
Console.WriteLine("The data type is an enumeration.")
Dim enumerationDataType = CType(dataType, EnumerationDataType)
Console.WriteLine("It has {0} enumeration members.", enumerationDataType.EnumerationMembers.Count)
Console.WriteLine("The names of the enumeration members are: {0}.", _
String.Join(", ", enumerationDataType.EnumerationMembers.Select(Function(member) member.Name)))
' Here you can process the members, or inspect SizeInBits etc.
Case DataTypeKind.Opaque
Console.WriteLine("The data type is opaque.")
Dim opaqueDataType = CType(dataType, OpaqueDataType)
Console.WriteLine("Its size is {0} bits.", opaqueDataType.SizeInBits)
' There isn't much more you can learn about an opaque data type (well, it may have Description and
' other common members). It is, after all, opaque...
Case DataTypeKind.Primitive
Console.WriteLine("The data type is primitive.")
Dim primitiveDataType = CType(dataType, PrimitiveDataType)
Console.WriteLine("Its .NET value type is ""{0}"".", primitiveDataType.ValueType)
' There isn't much more you can learn about the primitive data type.
Case DataTypeKind.Sequence
Console.WriteLine("The data type is a sequence.")
Dim sequenceDataType = CType(dataType, SequenceDataType)
Console.WriteLine("Its length is {0} (-1 means that the length can vary).", sequenceDataType.Length)
Console.WriteLine("A dump of the element data type follows.")
ProcessDataType(sequenceDataType.ElementDataType, (maximumDepth - 1))
Case DataTypeKind.Structured
Console.WriteLine("The data type is structured.")
Dim structuredDataType = CType(dataType, StructuredDataType)
Console.WriteLine("It has {0} data fields.", structuredDataType.DataFields.Count)
Console.WriteLine("The names of the data fields are: {0}.", _
String.Join(", ", structuredDataType.DataFields.Select(Function(field) field.Name)))
Console.WriteLine("A dump of each of the data fields follows.")
For Each dataField As DataField In structuredDataType.DataFields
Console.WriteLine()
Console.WriteLine("dataField.Name: {0}", dataField.Name)
' Note that every data field also has properties like IsLength, IsOptional, IsSwitch which might
' be of interest but we are not dumping them here.
ProcessDataType(dataField.DataType, (maximumDepth - 1))
Next
End Select
End Sub
End Class
End Namespace