OPC Studio User's Guide and Reference
DataType Class
Members  Example 



OpcLabs.BaseLib Assembly > OpcLabs.BaseLib.DataTypeModel Namespace : DataType Class
An abstract data type.
Syntax
'Declaration
 
<CLSCompliantAttribute(True)>
<ComDefaultInterfaceAttribute(OpcLabs.BaseLib.DataTypeModel.ComTypes._DataType)>
<ComVisibleAttribute(True)>
<GuidAttribute("D196D5B2-AC5D-41DB-9886-D41CD12A4A32")>
<DebuggerDisplayAttribute("{DebuggerDisplay,nq}")>
<TypeConverterAttribute(System.ComponentModel.ExpandableObjectConverter)>
<ValueControlAttribute("OpcLabs.BaseLib.Forms.Common.ObjectSerializationControl, OpcLabs.BaseLibForms, Version=5.80.82.1, Culture=neutral, PublicKeyToken=6faddca41dacb409", 
   DefaultReadWrite=False, 
   Export=True, 
   PageId=10001)>
<SerializableAttribute()>
Public MustInherit Class DataType 
   Inherits TypeMemberInfo
   Implements OpcLabs.BaseLib.ComTypes._Info, OpcLabs.BaseLib.ComTypes._Object2, OpcLabs.BaseLib.DataTypeModel.ComTypes._DataType, OpcLabs.BaseLib.DataTypeModel.ComTypes._TypeMemberInfo, System.ICloneable, System.IFormattable, System.Runtime.Serialization.ISerializable, System.Xml.Serialization.IXmlSerializable 
'Usage
 
Dim instance As DataType
[CLSCompliant(true)]
[ComDefaultInterface(OpcLabs.BaseLib.DataTypeModel.ComTypes._DataType)]
[ComVisible(true)]
[Guid("D196D5B2-AC5D-41DB-9886-D41CD12A4A32")]
[DebuggerDisplay("{DebuggerDisplay,nq}")]
[TypeConverter(System.ComponentModel.ExpandableObjectConverter)]
[ValueControl("OpcLabs.BaseLib.Forms.Common.ObjectSerializationControl, OpcLabs.BaseLibForms, Version=5.80.82.1, Culture=neutral, PublicKeyToken=6faddca41dacb409", 
   DefaultReadWrite=false, 
   Export=true, 
   PageId=10001)]
[Serializable()]
public abstract class DataType : TypeMemberInfo, OpcLabs.BaseLib.ComTypes._Info, OpcLabs.BaseLib.ComTypes._Object2, OpcLabs.BaseLib.DataTypeModel.ComTypes._DataType, OpcLabs.BaseLib.DataTypeModel.ComTypes._TypeMemberInfo, System.ICloneable, System.IFormattable, System.Runtime.Serialization.ISerializable, System.Xml.Serialization.IXmlSerializable  
[CLSCompliant(true)]
[ComDefaultInterface(OpcLabs.BaseLib.DataTypeModel.ComTypes._DataType)]
[ComVisible(true)]
[Guid("D196D5B2-AC5D-41DB-9886-D41CD12A4A32")]
[DebuggerDisplay("{DebuggerDisplay,nq}")]
[TypeConverter(System.ComponentModel.ExpandableObjectConverter)]
[ValueControl("OpcLabs.BaseLib.Forms.Common.ObjectSerializationControl, OpcLabs.BaseLibForms, Version=5.80.82.1, Culture=neutral, PublicKeyToken=6faddca41dacb409", 
   DefaultReadWrite=false, 
   Export=true, 
   PageId=10001)]
[Serializable()]
public ref class DataType abstract : public TypeMemberInfo, OpcLabs.BaseLib.ComTypes._Info, OpcLabs.BaseLib.ComTypes._Object2, OpcLabs.BaseLib.DataTypeModel.ComTypes._DataType, OpcLabs.BaseLib.DataTypeModel.ComTypes._TypeMemberInfo, System.ICloneable, System.IFormattable, System.Runtime.Serialization.ISerializable, System.Xml.Serialization.IXmlSerializable  
Remarks

Classes derived from DataType form following class hierarchy:

.

Example

.NET

COM

.NET

COM

// Shows how to process a data type, displaying some of its properties, recursively.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

using System;
using System.Linq;
using OpcLabs.BaseLib.DataTypeModel;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.ComplexData;
using OpcLabs.EasyOpc.UA.OperationModel;

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" (currently not supported)
            // 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: 3);
        }
        

        // 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;

                case DataTypeKind.Union:
                    Console.WriteLine("The data type is union.");
                    var unionDataType = (UnionDataType)dataType;
                    Console.WriteLine("It has {0} data fields.", unionDataType.DataFields.Count);
                    Console.WriteLine("The names of the data fields are: {0}.",
                        String.Join(", ", unionDataType.DataFields.Select(field => field.Name)));
                    break;
            }
        }
    }
}
# Shows how to process a data type, displaying some of its properties, recursively.
#
# Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
# OPC client and subscriber examples in Python on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-Python .
# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc

# Import .NET namespaces.
from System import *
from OpcLabs.BaseLib.DataTypeModel import *
from OpcLabs.EasyOpc.UA import *
from OpcLabs.EasyOpc.UA.OperationModel import *


def processDataType(dataType, maximumDepth):
    if maximumDepth == 0:
        print('* Reached maximum depth *')
        return

    print()
    print('dataType.Name: ', dataType.Name, sep='')

    if dataType.Kind == DataTypeKind.Enumeration:
        print('The data type is an enumeration.')
        enumerationDataType = dataType
        print('It has ', enumerationDataType.EnumerationMembers.Count, ' enumeration members.', sep='')
        print('The names of the enumeration members are: ', end='')
        for i, member in enumerate(enumerationDataType.EnumerationMembers):
            if i != 0:
                print(', ', end='')
            print(member.Name, end='')
        print('.')
        # Here you can process the members, or inspect SizeInBits etc.

    elif dataType.Kind == DataTypeKind.Opaque:
        print('The data type is opaque.')
        opaqueDataType = dataType
        print('Its size is ', opaqueDataType.SizeInBits, ' bits.', sep='')
        # 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...

    elif dataType.Kind == DataTypeKind.Primitive:
        print('The data type is primitive.')
        primitiveDataType = dataType
        print('Its .NET value type is "', primitiveDataType.ValueType, '".', sep='')
        # There isn't much more you can learn about the primitive data type.

    elif dataType.Kind == DataTypeKind.Sequence:
        print('The data type is a sequence.')
        sequenceDataType = dataType
        print('Its length is ', sequenceDataType.Length, ' (-1 means that the length can vary).', sep='')

        print('A dump of the element data type follows.')
        processDataType(sequenceDataType.ElementDataType, maximumDepth - 1)

    elif dataType.Kind == DataTypeKind.Structured:
        print('The data type is structured.')
        structuredDataType = dataType
        print('It has ', structuredDataType.DataFields.Count, ' data fields.', sep='')
        print('The names of the data fields are: ', end='')
        for i, field in enumerate(structuredDataType.DataFields):
            if i != 0:
                print(', ', end='')
            print(field.Name, end='')
        print('.')

        print('A dump of each of the data fields follows.')
        for dataField in structuredDataType.DataFields:
            print()
            print('dataField.Name: ', dataField.Name, sep='')
            # 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)

    elif dataType.Kind == DataTypeKind.Union:
        print('The data type is union.')
        unionDataType = dataType
        print('It has ', unionDataType.DataFields.Count, ' data fields.', sep='')
        print('The names of the data fields are: ', end='')
        for i, field in enumerate(unionDataType.DataFields):
            if i != 0:
                print(', ', end='')
            print(field.Name, end='')
        print('.')


# Define which server and node we will work with.
endpointDescriptor = UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:51210/UA/SampleServer')
# or 'http://opcua.demo-this.com:51211/UA/SampleServer' (currently not supported)
# or 'https://opcua.demo-this.com:51212/UA/SampleServer/'

# [ObjectsFolder]/Data.Static.Scalar.StructureValue
nodeDescriptor = UANodeDescriptor('nsu=http://test.org/UA/Data/ ;i=10239')

# Instantiate the client object.
client = EasyUAClient()

# Read a node. We know that this node returns complex data, so we can type cast to UAGenericObject.
try:
    print('Reading...')
    genericObject = IEasyUAClientExtension.ReadValue(client, endpointDescriptor, nodeDescriptor)
except UAException as uaException:
    print('*** Failure: ' + uaException.GetBaseException().Message)
    exit()
print('Reading successful.')
# 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, 3)

print()
print('Finished.')
' Shows how to process a data type, displaying some of its properties, recursively.
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

Imports System
Imports System.Linq
Imports OpcLabs.BaseLib.DataTypeModel
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.ComplexData
Imports OpcLabs.EasyOpc.UA.OperationModel

Namespace 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" (currently not supported)
            ' 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

                Case DataTypeKind.Union
                    Console.WriteLine("The data type is union.")
                    Dim unionDataType = CType(dataType, UnionDataType)
                    Console.WriteLine("It has {0} data fields.", unionDataType.DataFields.Count)
                    Console.WriteLine("The names of the data fields are: {0}.",
                                      String.Join(", ", unionDataType.DataFields.Select(Function(field) field.Name)))

            End Select

        End Sub
    End Class
End Namespace
// Shows how to process a data type, displaying some of its properties, recursively.
//
// Find all latest examples here : https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

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';
    //'https://opcua.demo-this.com:51212/UA/SampleServer/';
    '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 obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

using System;
using Microsoft.Extensions.DependencyInjection;
using OpcLabs.BaseLib.DataTypeModel;
using OpcLabs.BaseLib.OperationModel.Generic;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.AddressSpace;
using OpcLabs.EasyOpc.UA.AddressSpace.Standard;
using OpcLabs.EasyOpc.UA.InformationModel;
using OpcLabs.EasyOpc.UA.Plugins.ComplexData;

namespace UADocExamples.ComplexData._IEasyUAClientComplexData
{
    class ResolveDataType
    {
        public static void Main1()
        {
            // Define which server we will work with.
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            // Instantiate the client object.
            var client = new EasyUAClient();

            // Obtain the data type ID.
            //
            // In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
            // attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface.
            // The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract
            // data type, and the actual values are then sub-types of this base data type. This abstract data type does not
            // have any encodings associated with it and it is therefore not possible to extract its description from the
            // server. We therefore use a hard-coded data type ID for one of the sub-types in this example.
            //
            // The code to obtain the data type ID for given node would normally look like this:
            //    UANodeId dataTypeId = client.ReadDataType(
            //        endpointDescriptor,
            //        "nsu=http://test.org/UA/Data/ ;i=10239");    // [ObjectsFolder]/Data.Static.Scalar.StructureValue
            //
            UANodeId dataTypeId = "nsu=http://test.org/UA/Data/ ;i=9440";    // ScalarValueDataType

            // Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
            // operations.
            IEasyUAClientComplexData complexData = client.GetService<IEasyUAClientComplexData>();
            
            // Resolve the data type ID to the data type object, containing description of the data type.
            ValueResult<DataType> dataTypeResult = complexData.ResolveDataType(
                new UAModelNodeDescriptor(endpointDescriptor, dataTypeId), 
                UABrowseNames.DefaultBinary);
            // Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            if (!dataTypeResult.Succeeded)
            {
                Console.WriteLine("*** Failure: {0}", dataTypeResult.ErrorMessageBrief);
                return;
            }

            // The actual data type is in the Value property.
            // Display basic information about what we have obtained.
            Console.WriteLine(dataTypeResult.Value);

            // If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
            // specifier. In the debugger, you can view the same by displaying the private DebugView property.
            Console.WriteLine();
            Console.WriteLine("{0:V}", dataTypeResult.Value);

            // For processing the internals of the data type, refer to examples for GenericData class.


            // Example output (truncated):
            //
            //ScalarValueDataType = structured
            //
            //ScalarValueDataType = structured
            //  [BooleanValue] Boolean = primitive(System.Boolean)
            //  [ByteStringValue] ByteString = primitive(System.Byte[])
            //  [ByteValue] Byte = primitive(System.Byte)
            //  [DateTimeValue] DateTime = primitive(System.DateTime)
            //  [DoubleValue] Double = primitive(System.Double)
            //  [EnumerationValue] Int32 = primitive(System.Int32)
            //  [ExpandedNodeIdValue] ExpandedNodeId = structured
            //    [ByteString] optional ByteStringNodeId = structured
            //      [Identifier] ByteString = primitive(System.Byte[])
            //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            //    [FourByte] optional FourByteNodeId = structured
            //      [Identifier] UInt16 = primitive(System.UInt16)
            //      [NamespaceIndex] Byte = primitive(System.Byte)
            //    [Guid] optional GuidNodeId = structured
            //      [Identifier] Guid = primitive(System.Guid)
            //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            //    [NamespaceURI] optional CharArray = primitive(System.String)
            //    [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
            //    [NodeIdType] switch NodeIdType = enumeration(6)
            //      TwoByte = 0
            //      FourByte = 1
            //      Numeric = 2
            //      String = 3
            //      Guid = 4
            //      ByteString = 5
            //    [Numeric] optional NumericNodeId = structured
            //      [Identifier] UInt32 = primitive(System.UInt32)
            //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            //    [ServerIndex] optional UInt32 = primitive(System.UInt32)
            //    [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
            //    [String] optional StringNodeId = structured
            //      [Identifier] CharArray = primitive(System.String)
            //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            //    [TwoByte] optional TwoByteNodeId = structured
            //      [Identifier] Byte = primitive(System.Byte)
            //  [FloatValue] Float = primitive(System.Single)
            //  [GuidValue] Guid = primitive(System.Guid)
            //  [Int16Value] Int16 = primitive(System.Int16)
            //  [Int32Value] Int32 = primitive(System.Int32)
            //  [Int64Value] Int64 = primitive(System.Int64)
            //  [Integer] Variant = structured
            //    [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
            //    [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
            //    [ArrayLength] length optional Int32 = primitive(System.Int32)
            //    [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
            //    [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
            //    [Byte] optional sequence[*] of Byte = primitive(System.Byte)
        }
    }
}
# Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.
#
# Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
# OPC client and subscriber examples in Python on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-Python .
# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc

# Import .NET namespaces.
from Microsoft.Extensions.DependencyInjection import *
from System import *
from OpcLabs.EasyOpc.UA import *
from OpcLabs.EasyOpc.UA.AddressSpace import *
from OpcLabs.EasyOpc.UA.AddressSpace.Standard import *
#from OpcLabs.EasyOpc.UA.Extensions import *
from OpcLabs.EasyOpc.UA.InformationModel import *
from OpcLabs.EasyOpc.UA.Plugins.ComplexData import *


endpointDescriptor = UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:51210/UA/SampleServer')
# or 'http://opcua.demo-this.com:51211/UA/SampleServer' (currently not supported)
# or 'https://opcua.demo-this.com:51212/UA/SampleServer/'

# Instantiate the client object.
client = EasyUAClient()

# Obtain the data type ID.
#
# In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
# attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface.
# The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract
# data type, and the actual values are then sub-types of this base data type. This abstract data type does not
# have any encodings associated with it and it is therefore not possible to extract its description from the
# server. We therefore use a hard-coded data type ID for one of the sub-types in this example.
#
# The code to obtain the data type ID for given node would normally look like this:
#    dataTypeId = IEasyUAClientExtension2.ReadDataType(client,
#        endpointDescriptor,
#        UANodeDescriptor('nsu=http://test.org/UA/Data/ ;i=10239'))    # [ObjectsFolder]/Data.Static.Scalar.StructureValue
dataTypeId = UANodeId('nsu=http://test.org/UA/Data/ ;i=9440')   # ScalarValueDataType

# Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data
# operations.
complexData = ServiceProviderServiceExtensions.GetService[IEasyUAClientComplexData](client)
if complexData is None:
    print('The client complex data service is not available.')
    exit()

# Resolve the data type ID to the data type object, containing description of the data type.
dataTypeResult = IEasyUAClientComplexDataExtension.ResolveDataType(complexData,
    UAModelNodeDescriptor(endpointDescriptor, UANodeDescriptor(dataTypeId)),
    UABrowseNames.DefaultBinary)
# Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
if not dataTypeResult.Succeeded:
    print('*** Failure: ', dataTypeResult.ErrorMessageBrief)
    exit()

# The actual data type is in the Value property.
# Display basic information about what we have obtained.
print(dataTypeResult.Value)

# If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
# specifier. In the debugger, you can view the same by displaying the private DebugView property.
print()
print(String.Format('{0:V}', dataTypeResult.Value))

# For processing the internals of the data type, refer to examples for GenericData class.

print()
print('Finished.')
' Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

Imports System
Imports Microsoft.Extensions.DependencyInjection
Imports OpcLabs.BaseLib.DataTypeModel
Imports OpcLabs.BaseLib.OperationModel.Generic
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.AddressSpace
Imports OpcLabs.EasyOpc.UA.AddressSpace.Standard
Imports OpcLabs.EasyOpc.UA.InformationModel
Imports OpcLabs.EasyOpc.UA.Plugins.ComplexData

Namespace ComplexData._IEasyUAClientComplexData

    Friend Class ResolveDataType

        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" (currently not supported)
            ' or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            ' Instantiate the client object.
            Dim client = New EasyUAClient

            ' Obtain the data type ID.
            '
            ' In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
            ' attribute, or easier, by calling the extension method ReadDataType on the IEasyUAClient interface. The sample
            ' server, however, shows a more advanced approach in which the data type ID refers to an abstract data type,
            ' and the actual values are then sub-types of this base data type. This abstract data type does not have any
            ' encodings associated with it and it is therefore not possible to extract its description from the server.
            ' We therefore use a hard-coded data type ID for one of the sub-types in this example.
            '
            ' The code to obtain the data type ID for given node would normally look like this:
            '    UANodeId dataTypeId = client.ReadDataType(
            '        endpointDescriptor,
            '        "nsu=http://test.org/UA/Data/ ;i=10239");    // [ObjectsFolder]/Data.Static.Scalar.StructureValue
            '
            Dim dataTypeId As UANodeId = "nsu=http://test.org/UA/Data/ ;i=9440"  ' ScalarValueDataType

            ' Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
            ' operations.
            Dim complexData As IEasyUAClientComplexData = client.GetService(Of IEasyUAClientComplexData)

            ' Resolve the data type ID to the data type object, containing description of the data type.
            Dim dataTypeResult As ValueResult(Of DataType) = complexData.ResolveDataType( _
                New UAModelNodeDescriptor(endpointDescriptor, dataTypeId), _
                UABrowseNames.DefaultBinary)
            ' Check if the operation succeeded. Use the ThrowIfFailed method instead if you want exception be thrown.
            If Not dataTypeResult.Succeeded Then
                Console.WriteLine("*** Failure: {0}", dataTypeResult.ErrorMessageBrief)
                Exit Sub
            End If

            ' The actual data type is in the Value property.
            ' Display basic information about what we have obtained.
            Console.WriteLine(dataTypeResult.Value)

            ' If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
            ' specifier. In the debugger, you can view the same by displaying the private DebugView property.
            Console.WriteLine()
            Console.WriteLine("{0:V}", dataTypeResult.Value)

            ' For processing the internals of the data type, refer to examples for GenericData class.


            ' Example output (truncated):
            '
            'ScalarValueDataType = structured
            '
            'ScalarValueDataType = structured
            '  [BooleanValue] Boolean = primitive(System.Boolean)
            '  [ByteStringValue] ByteString = primitive(System.Byte[])
            '  [ByteValue] Byte = primitive(System.Byte)
            '  [DateTimeValue] DateTime = primitive(System.DateTime)
            '  [DoubleValue] Double = primitive(System.Double)
            '  [EnumerationValue] Int32 = primitive(System.Int32)
            '  [ExpandedNodeIdValue] ExpandedNodeId = structured
            '    [ByteString] optional ByteStringNodeId = structured
            '      [Identifier] ByteString = primitive(System.Byte[])
            '      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            '    [FourByte] optional FourByteNodeId = structured
            '      [Identifier] UInt16 = primitive(System.UInt16)
            '      [NamespaceIndex] Byte = primitive(System.Byte)
            '    [Guid] optional GuidNodeId = structured
            '      [Identifier] Guid = primitive(System.Guid)
            '      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            '    [NamespaceURI] optional CharArray = primitive(System.String)
            '    [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
            '    [NodeIdType] switch NodeIdType = enumeration(6)
            '      TwoByte = 0
            '      FourByte = 1
            '      Numeric = 2
            '      String = 3
            '      Guid = 4
            '      ByteString = 5
            '    [Numeric] optional NumericNodeId = structured
            '      [Identifier] UInt32 = primitive(System.UInt32)
            '      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            '    [ServerIndex] optional UInt32 = primitive(System.UInt32)
            '    [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
            '    [String] optional StringNodeId = structured
            '      [Identifier] CharArray = primitive(System.String)
            '      [NamespaceIndex] UInt16 = primitive(System.UInt16)
            '    [TwoByte] optional TwoByteNodeId = structured
            '      [Identifier] Byte = primitive(System.Byte)
            '  [FloatValue] Float = primitive(System.Single)
            '  [GuidValue] Guid = primitive(System.Guid)
            '  [Int16Value] Int16 = primitive(System.Int16)
            '  [Int32Value] Int32 = primitive(System.Int32)
            '  [Int64Value] Int64 = primitive(System.Int64)
            '  [Integer] Variant = structured
            '    [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
            '    [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
            '    [ArrayLength] length optional Int32 = primitive(System.Int32)
            '    [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
            '    [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
            '    [Byte] optional sequence[*] of Byte = primitive(System.Byte)
        End Sub
    End Class
End Namespace
// Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.
//
// Find all latest examples here : https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

class procedure ResolveDataType.Main;
var
  Client: _EasyUAClient;
  ComplexData: _EasyUAClientComplexData;
  DataType: _DataType;
  DataTypeId: string;
  DataTypeResult: _ValueResult;
  EncodingName: _UAQualifiedName;
  EndpointDescriptor: string;
  ModelNodeDescriptor: _UAModelNodeDescriptor;
begin
  // Define which server and node we will work with.
  EndpointDescriptor := 
    //'http://opcua.demo-this.com:51211/UA/SampleServer';
    //'https://opcua.demo-this.com:51212/UA/SampleServer/';
    'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';

  // Instantiate the client object
  Client := CoEasyUAClient.Create;

  // Obtain the data type ID.
  //
  // In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
  // attribute.
  // The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract data type, and
  // the actual values are then sub-types of this base data type. This abstract data type does not have any encodings
  // associated with it and it is therefore not possible to extract its description from the server. We therefore use
  // a hard-coded data type ID for one of the sub-types in this example.
  DataTypeId := 'nsu=http://test.org/UA/Data/ ;i=9440';    // ScalarValueDataType

  // Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data
  // operations.
  ComplexData := IInterface(Client.GetServiceByName('OpcLabs.EasyOpc.UA.Plugins.ComplexData.IEasyUAClientComplexData, OpcLabs.EasyOpcUA')) as _EasyUAClientComplexData;

  // Resolve the data type ID to the data type object, containing description of the data type.
  ModelNodeDescriptor := CoUAModelNodeDescriptor.Create;
  ModelNodeDescriptor.EndpointDescriptor.UrlString := EndpointDescriptor;
  ModelNodeDescriptor.NodeDescriptor.NodeId.ExpandedText := DataTypeId;
  EncodingName := CoUAQualifiedName.Create;
  EncodingName.StandardName := 'DefaultBinary';
  DataTypeResult := ComplexData.ResolveDataType(ModelNodeDescriptor, EncodingName);
  if not DataTypeResult.Succeeded then
  begin
    WriteLn(Format('*** Failure: %s', [DataTypeResult.ErrorMessageBrief]));
    Exit;
  end;

  // The actual data type is in the Value property.
  DataType := IUnknown(DataTypeResult.Value) as _DataType;

  // Display basic information about what we have obtained.
  WriteLn(DataType.ToString);

  // If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
  // specifier.
  Writeln;
  Writeln(DataType.ToString_2['V', nil]);

  // For processing the internals of the data type, refer to examples for GenericData class.


  // Example output (truncated):
  //
  //ScalarValueDataType = structured
  //
  //ScalarValueDataType = structured
  //  [BooleanValue] Boolean = primitive(System.Boolean)
  //  [ByteStringValue] ByteString = primitive(System.Byte[])
  //  [ByteValue] Byte = primitive(System.Byte)
  //  [DateTimeValue] DateTime = primitive(System.DateTime)
  //  [DoubleValue] Double = primitive(System.Double)
  //  [EnumerationValue] Int32 = primitive(System.Int32)
  //  [ExpandedNodeIdValue] ExpandedNodeId = structured
  //    [ByteString] optional ByteStringNodeId = structured
  //      [Identifier] ByteString = primitive(System.Byte[])
  //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
  //    [FourByte] optional FourByteNodeId = structured
  //      [Identifier] UInt16 = primitive(System.UInt16)
  //      [NamespaceIndex] Byte = primitive(System.Byte)
  //    [Guid] optional GuidNodeId = structured
  //      [Identifier] Guid = primitive(System.Guid)
  //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
  //    [NamespaceURI] optional CharArray = primitive(System.String)
  //    [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
  //    [NodeIdType] switch NodeIdType = enumeration(6)
  //      TwoByte = 0
  //      FourByte = 1
  //      Numeric = 2
  //      String = 3
  //      Guid = 4
  //      ByteString = 5
  //    [Numeric] optional NumericNodeId = structured
  //      [Identifier] UInt32 = primitive(System.UInt32)
  //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
  //    [ServerIndex] optional UInt32 = primitive(System.UInt32)
  //    [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
  //    [String] optional StringNodeId = structured
  //      [Identifier] CharArray = primitive(System.String)
  //      [NamespaceIndex] UInt16 = primitive(System.UInt16)
  //    [TwoByte] optional TwoByteNodeId = structured
  //      [Identifier] Byte = primitive(System.Byte)
  //  [FloatValue] Float = primitive(System.Single)
  //  [GuidValue] Guid = primitive(System.Guid)
  //  [Int16Value] Int16 = primitive(System.Int16)
  //  [Int32Value] Int32 = primitive(System.Int32)
  //  [Int64Value] Int64 = primitive(System.Int64)
  //  [Integer] Variant = structured
  //    [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
  //    [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
  //    [ArrayLength] length optional Int32 = primitive(System.Int32)
  //    [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
  //    [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
  //    [Byte] optional sequence[*] of Byte = primitive(System.Byte)

end;
Rem Shows how to obtain object describing the data type of complex data node with OPC UA Complex Data plug-in.
Rem
Rem Find all latest examples here : https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .

Option Explicit

' Define which server we will work with.
Dim endpointDescriptor: endpointDescriptor = _
    "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
    '"http://opcua.demo-this.com:51211/UA/SampleServer"  
    '"https://opcua.demo-this.com:51212/UA/SampleServer/"

' Instantiate the client object.
Dim Client: Set Client = CreateObject("OpcLabs.EasyOpc.UA.EasyUAClient")

' Obtain the data type ID.
'
' In many cases, you would be able to obtain the data type ID of a particular node by reading its DataType
' attribute. 
' The sample server, however, shows a more advanced approach in which the data type ID refers to an abstract data type, and 
' the actual values are then sub-types of this base data type. This abstract data type does not have any encodings 
' associated with it and it is therefore not possible to extract its description from the server. We therefore use 
' a hard-coded data type ID for one of the sub-types in this example.
Dim dataTypeId: dataTypeId = "nsu=http://test.org/UA/Data/ ;i=9440"    ' ScalarValueDataType

' Get the IEasyUAClientComplexData service from the client. This is needed for advanced complex data 
' operations.
Dim ComplexData: Set ComplexData = _
    Client.GetServiceByName("OpcLabs.EasyOpc.UA.Plugins.ComplexData.IEasyUAClientComplexData, OpcLabs.EasyOpcUA")

' Resolve the data type ID to the data type object, containing description of the data type.
Dim ModelNodeDescriptor: Set ModelNodeDescriptor = CreateObject("OpcLabs.EasyOpc.UA.InformationModel.UAModelNodeDescriptor")
ModelNodeDescriptor.EndpointDescriptor.UrlString = endpointDescriptor
ModelNodeDescriptor.NodeDescriptor.NodeId.ExpandedText = dataTypeId
Dim EncodingName: Set EncodingName = CreateObject("OpcLabs.EasyOpc.UA.AddressSpace.UAQualifiedName")
EncodingName.StandardName = "DefaultBinary"
Dim DataTypeResult: Set DataTypeResult = ComplexData.ResolveDataType(ModelNodeDescriptor, EncodingName)
If Not DataTypeResult.Succeeded Then
    WScript.Echo "*** Failure: "  & DataTypeResult.Exception.GetBaseException().Message
    WScript.Quit
End If

' The actual data type is in the Value property.
Dim DataType: Set DataType = DataTypeResult.Value

' Display basic information about what we have obtained.
WScript.Echo DataType

' If we want to see the whole hierarchy of the received data type, we can format it with the "V" (verbose)
' specifier. 
WScript.Echo
WScript.Echo DataType.ToString_2("V", Nothing)

' For processing the internals of the data type, refer to examples for GenericData class.


' Example output (truncated):
'
'ScalarValueDataType = structured
'
'ScalarValueDataType = structured
'  [BooleanValue] Boolean = primitive(System.Boolean)
'  [ByteStringValue] ByteString = primitive(System.Byte[])
'  [ByteValue] Byte = primitive(System.Byte)
'  [DateTimeValue] DateTime = primitive(System.DateTime)
'  [DoubleValue] Double = primitive(System.Double)
'  [EnumerationValue] Int32 = primitive(System.Int32)
'  [ExpandedNodeIdValue] ExpandedNodeId = structured
'    [ByteString] optional ByteStringNodeId = structured
'      [Identifier] ByteString = primitive(System.Byte[])
'      [NamespaceIndex] UInt16 = primitive(System.UInt16)
'    [FourByte] optional FourByteNodeId = structured
'      [Identifier] UInt16 = primitive(System.UInt16)
'      [NamespaceIndex] Byte = primitive(System.Byte)
'    [Guid] optional GuidNodeId = structured
'      [Identifier] Guid = primitive(System.Guid)
'      [NamespaceIndex] UInt16 = primitive(System.UInt16)
'    [NamespaceURI] optional CharArray = primitive(System.String)
'    [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
'    [NodeIdType] switch NodeIdType = enumeration(6)
'      TwoByte = 0
'      FourByte = 1
'      Numeric = 2
'      String = 3
'      Guid = 4
'      ByteString = 5
'    [Numeric] optional NumericNodeId = structured
'      [Identifier] UInt32 = primitive(System.UInt32)
'      [NamespaceIndex] UInt16 = primitive(System.UInt16)
'    [ServerIndex] optional UInt32 = primitive(System.UInt32)
'    [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
'    [String] optional StringNodeId = structured
'      [Identifier] CharArray = primitive(System.String)
'      [NamespaceIndex] UInt16 = primitive(System.UInt16)
'    [TwoByte] optional TwoByteNodeId = structured
'      [Identifier] Byte = primitive(System.Byte)
'  [FloatValue] Float = primitive(System.Single)
'  [GuidValue] Guid = primitive(System.Guid)
'  [Int16Value] Int16 = primitive(System.Int16)
'  [Int32Value] Int32 = primitive(System.Int32)
'  [Int64Value] Int64 = primitive(System.Int64)
'  [Integer] Variant = structured
'    [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
'    [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
'    [ArrayLength] length optional Int32 = primitive(System.Int32)
'    [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
'    [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
'    [Byte] optional sequence[*] of Byte = primitive(System.Byte)
Inheritance Hierarchy

System.Object
   OpcLabs.BaseLib.Object2
      OpcLabs.BaseLib.Info
         OpcLabs.BaseLib.DataTypeModel.TypeMemberInfo
            OpcLabs.BaseLib.DataTypeModel.DataType
               OpcLabs.BaseLib.DataTypeModel.CompositeDataType
               OpcLabs.BaseLib.DataTypeModel.EnumerationDataType
               OpcLabs.BaseLib.DataTypeModel.OpaqueDataType
               OpcLabs.BaseLib.DataTypeModel.PrimitiveDataType
               OpcLabs.BaseLib.DataTypeModel.SequenceDataType

Requirements

Target Platforms: .NET Framework: Windows 10 (selected versions), Windows 11 (selected versions), Windows Server 2016, Windows Server 2022; .NET: Linux, macOS, Microsoft Windows

See Also