' ******************************************************************************
' ** TIL.VB V1.3.1
' ** Copyright (c) 2001-2011 Tellert Elektronik GmbH
' ******************************************************************************
'
' The minimum required TIL_TMS.DLL version is 1.2.0 (due to the strict result 
' check of TilGetNextIteratorItems for tilDataMeasGroupSignalDataIterator). 
' This limitation can be bypassed by ignoring the corresponding function 
' result:
' #Const SUPPORT_OLDER_TILTMS_VERSIONS = True

Imports System
Imports System.Collections.Generic
Imports System.Globalization
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Runtime.Serialization
Imports System.Text

#If VBC_VER >= 11 Then
Namespace Global.Tellert.Til
#Else
Namespace Tellert.Til
#End If

    ''' <summary>Provides read-only access to TEMES files.</summary>
    Public Class Til
        Implements IDisposable

        ''' <value>Represents the TEMES file name.</value>
        Public Property FileName() As String
            Get
                Return m_FileName
            End Get
            Private Set(ByVal value As String)
                m_FileName = value
            End Set
        End Property
        Private m_FileName As String

        ''' <value>Represents the root variables of a TEMES file.</value>
        Public Property Variables() As VariableDictionary
            Get
                Return m_Variables
            End Get
            Private Set(ByVal value As VariableDictionary)
                m_Variables = value
            End Set
        End Property
        Private m_Variables As VariableDictionary

        ''' <summary>Represents the signal groups of a TEMES file.</summary>
        Public Property Groups() As Group()
            Get
                Return m_Groups
            End Get
            Private Set(ByVal value As Group())
                m_Groups = value
            End Set
        End Property
        Private m_Groups As Group()

        ''' <summary>Represents the view items of a TEMES file.</summary>
        Public Property Views() As View()
            Get
                Return m_Views
            End Get
            Private Set(ByVal value As View())
                m_Views = value
            End Set
        End Property
        Private m_Views As View()

        Public Property Version() As UInt32
            Get
                Return m_Version
            End Get
            Set(value As UInt32)
            End Set
        End Property
        Private m_Version As UInt32

        Private obj As IntPtr

        Protected Overrides Sub Finalize()
            Try
                Dispose(False)
            Finally
                MyBase.Finalize()
            End Try
        End Sub

        Public Overloads Sub Dispose() Implements IDisposable.Dispose
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub

        Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
            If obj <> IntPtr.Zero Then
                TilMethods.DestroyObject(obj)
                obj = IntPtr.Zero
            End If
        End Sub

        ''' <summary>Unloads a possibly loaded TEMES file.</summary>
        Public Sub Clear()
            Dispose(False)
            FileName = Nothing
            Variables = Nothing
            Groups = Nothing
            Views = Nothing
        End Sub

        ''' <summary>
        ''' Loads a TEMES file. 
        ''' TEMES files ("*.tms") require only the additional platform-dependent file "til_tms.dll". 
        ''' Compressed TEMES files ("*.tma") require the additional two platform-dependent files "til_tms.dll" and "zlibwapi.dll".
        ''' </summary>
        Public Function Load(ByVal fileNamePar As String) As Boolean
            Dim root As IntPtr, info As IntPtr, control As IntPtr, file As IntPtr, data As IntPtr, meas As IntPtr, meas0 As IntPtr,
             comm As IntPtr, groupsProp As IntPtr, viewsProp As IntPtr
            Clear()
            If (fileNamePar <> Nothing) Then
                fileNamePar = System.IO.Path.GetFullPath(fileNamePar)
            End If
            obj = TilMethods.CreateObject(TemesTilGuid)
            root = TilMethods.GetRootProperty(obj)
            info = TilMethods.GetProperty(root, Tag.Info)
            m_Version = TilMethods.GetUInt(TilMethods.GetProperty(info, Tag.InfoVersion))
            control = TilMethods.GetProperty(root, Tag.Control)
            file = TilMethods.GetProperty(control, Tag.ControlFilename)
            If Not TilMethods.SetString(file, fileNamePar) Then
                Clear()
                Return False
            End If
            data = TilMethods.GetProperty(root, Tag.Data)
            meas = TilMethods.GetProperty(data, Tag.DataMeas)
            meas0 = TilMethods.GetProperty(meas, 0)
            comm = TilMethods.GetProperty(meas0, Tag.DataMeasComm)
            Variables = New VariableDictionary(TilMethods.GetProperty(comm, Tag.DataMeasCommVariable))
            groupsProp = TilMethods.GetProperty(meas0, Tag.DataMeasGroup)
            Groups = New Group(TilMethods.GetVectorSize(groupsProp) - 1) {}
            If Groups.Length <> 0 Then
                For g As UInteger = 0 To Groups.Length - 1
                    Groups(g) = New Group(TilMethods.GetVectorItem(groupsProp, g))
                Next
            End If
            viewsProp = TilMethods.GetProperty(data, Tag.DataView)
            Views = New View(TilMethods.GetVectorSize(viewsProp) - 1) {}
            If Views.Length <> 0 Then
                For v As UInteger = 0 To Views.Length - 1
                    Views(v) = New View(TilMethods.GetVectorItem(viewsProp, v), Groups)
                Next
            End If
            FileName = fileNamePar

            Return True
        End Function

        ''' <summary>Represents a signal group.</summary>
        Public Class Group
            ''' <summary>Describes the name of a measurement group. Group names may be empty and may not be unambiguous.</summary>
            Public ReadOnly Name As String

            ''' <summary>Represents the measurement comment.</summary>
            Public ReadOnly Comment As String

            ''' <summary>Represents the group variables.</summary>
            Public ReadOnly Variables As VariableDictionary

            ''' <summary>Represents the total number of samples for this group.</summary>
            Public ReadOnly SampleCount As ULong

            ''' <summary>Represents the group sample rate in seconds.</summary>
            Public ReadOnly SampleRate As Double

            ''' <summary>Contains all group date and time information.</summary>
            Public ReadOnly Time As Time

            ''' <summary>Represents the group signals.</summary>
            Public ReadOnly Signals As Signal()

            Public Sub New(ByVal group As IntPtr)
                Dim comm As IntPtr, info As IntPtr, signalsProp As IntPtr
                comm = TilMethods.GetProperty(group, Tag.DataMeasGroupComm)
                Name = TilMethods.GetString(TilMethods.GetProperty(comm, Tag.DataMeasGroupCommName))
                Comment = TilMethods.GetString(TilMethods.GetProperty(comm, Tag.DataMeasGroupCommComment))
                Variables = New VariableDictionary(TilMethods.GetProperty(comm, Tag.DataMeasGroupCommVariable))
                SampleCount = TilMethods.GetULong(TilMethods.GetProperty(group, Tag.DataMeasGroupSamplecount))
                SampleRate = TilMethods.GetDouble(TilMethods.GetProperty(group, Tag.DataMeasGroupSamplerate))
                info = TilMethods.GetProperty(group, Tag.DataMeasGroupInfo)
                Time = New Time(TilMethods.GetProperty(info, Tag.DataMeasGroupInfoTime))
                signalsProp = TilMethods.GetProperty(group, Tag.DataMeasGroupSignal)
                Signals = New Signal(TilMethods.GetVectorSize(signalsProp) - 1) {}
                If Signals.Length <> 0 Then
                    For s As UInteger = 0 To Signals.Length - 1
                        Signals(s) = New Signal(TilMethods.GetVectorItem(signalsProp, s), Me)
                    Next
                End If
            End Sub
        End Class

        ''' <summary>Represents a dictionary of string keys and string/double values.</summary>
        Public Class VariableDictionary
            Inherits SortedDictionary(Of String, Object)
            Public Sub New(ByVal variables As IntPtr)
                Dim count As UInteger = TilMethods.GetVectorSize(variables)
                If count <> 0 Then
                    For i As UInteger = 0 To count - 1
                        Dim variable As IntPtr, value As IntPtr
                        Dim key As String
                        variable = TilMethods.GetVectorItem(variables, i)
                        key = TilMethods.GetString(TilMethods.GetProperty(variable, Tag.DataCommVariableKey))
                        If ContainsKey(key) Then
                            Continue For
                        End If
                        value = TilMethods.GetProperty(variable, Tag.DataCommVariableValue)
                        Select Case TilMethods.[GetType](value)
                            Case PropertyType.AnsiString, PropertyType.WideString
                                Add(key, TilMethods.GetString(value))
                                Exit Select
                            Case PropertyType.Float64, PropertyType.Float80
                                Add(key, TilMethods.GetDouble(value))
                                Exit Select
                        End Select
                    Next
                End If
            End Sub
        End Class

        ''' <summary>Represents the date and time information of a group.</summary>
        Public Structure Time
            ''' <summary>Represents the time point when the device was set up.</summary>
            Public ReadOnly DeviceSetup As Timestamp

            ''' <summary>Represents the time point of the first sample.</summary>
            Public ReadOnly Start As Timestamp

            ''' <summary>Represents the time point when the device was read out.</summary>
            Public ReadOnly DeviceReadOut As Timestamp

            ''' <summary>Represents the mutual exclusive subdivisions of the group samples. The sample offsets are strong monotonically increasing.</summary>
            Public ReadOnly Sections As Section()

            Public Sub New(ByVal time As IntPtr)
                Dim sectionsProp As IntPtr
                DeviceSetup = New Timestamp(TilMethods.GetTime64(TilMethods.GetProperty(time, Tag.DataMeasGroupInfoTimeHwsetup)))
                Start = New Timestamp(TilMethods.GetTime64(TilMethods.GetProperty(time, Tag.DataMeasGroupInfoTimeStart)))
                DeviceReadOut = New Timestamp(TilMethods.GetTime64(TilMethods.GetProperty(time, Tag.DataMeasGroupInfoTimeHwreadout)))
                sectionsProp = TilMethods.GetProperty(time, Tag.DataMeasGroupInfoTimeSection)
                Sections = New Section(TilMethods.GetVectorSize(sectionsProp) - 1) {}
                If Sections.Length <> 0 Then
                    For s As UInteger = 0 To Sections.Length - 1
                        Sections(s) = New Section(TilMethods.GetVectorItem(sectionsProp, s))
                    Next
                End If
            End Sub
        End Structure

        ''' <summary>Represents the mutual exclusive subdivisions of the group samples. The sample offsets are strong monotonically increasing.</summary>
        Public Structure Section
            ''' <summary>Represents the zero-based index of the first section sample within the group samples.</summary>
            Public ReadOnly SampleOffset As ULong

            ''' <summary>Represents the time point of the first section value.</summary>
            Public ReadOnly Start As Timestamp

            Public Sub New(ByVal section As IntPtr)
                SampleOffset = TilMethods.GetULong(TilMethods.GetProperty(section, Tag.DataMeasGroupInfoTimeSectionSampleindex))
                Start = New Timestamp(TilMethods.GetTime64(TilMethods.GetProperty(section, Tag.DataMeasGroupInfoTimeSectionStart)))
            End Sub
        End Structure

        ''' <summary>Represents the group signal.</summary>
        Public Class Signal
            ''' <summary>Represents the nonempty and unambigous signal name.</summary>
            Public ReadOnly Name As String

            ''' <summary>Represents the signal comment. The signal comment is empty at the moment.</summary>
            Public ReadOnly Comment As String

            ''' <summary>Represents the signal variables. The signal variables are empty at the moment.</summary>
            Public ReadOnly Variables As VariableDictionary

            ''' <summary>Represents the signal unit.</summary>
            Public ReadOnly Unit As String

            ''' <summary>Represents all signal attributes.</summary>
            Public ReadOnly Attributes As Attributes

            ''' <summary>Represents the default settings for the signal view.</summary>
            Public ReadOnly ViewDefaults As ViewDefaults

            ''' <summary>Represents the signal markers.</summary>
            Public ReadOnly Markers As Marker()

            ''' <summary>Represents the raw values of a signal. The floating-point values of a signal are obtained by <c>Factor</c> * RawValue + <c>Offset</c>.</summary>
            Public ReadOnly Raw As Raw

            ''' <summary>Represents the floating-point values of a signal. <c>Iterator</c> should not be confused with the native iterator concept of the .NET framework.</summary>
            Public ReadOnly Iterator As Iterator

            ''' <summary>Represents the signal group.</summary>
            Public ReadOnly Group As Group

            Public Sub New(ByVal signal As IntPtr, ByVal parentGroup As Group)
                Dim comm As IntPtr, data As IntPtr, markersProp As IntPtr
                comm = TilMethods.GetProperty(signal, Tag.DataMeasGroupSignalComm)
                Name = TilMethods.GetString(TilMethods.GetProperty(comm, Tag.DataMeasGroupSignalCommName))
                Comment = TilMethods.GetString(TilMethods.GetProperty(comm, Tag.DataMeasGroupSignalCommComment))
                Variables = New VariableDictionary(TilMethods.GetProperty(comm, Tag.DataMeasGroupSignalCommVariable))
                Unit = TilMethods.GetString(TilMethods.GetProperty(signal, Tag.DataMeasGroupSignalUnit))
                data = TilMethods.GetProperty(signal, Tag.DataMeasGroupSignalData)
                Raw = New Raw(TilMethods.GetProperty(data, Tag.DataMeasGroupSignalDataRaw), parentGroup.SampleCount)
                Attributes = New Attributes(TilMethods.GetProperty(data, Tag.DataMeasGroupSignalDataFlags))
                ViewDefaults = New ViewDefaults(TilMethods.GetProperty(signal, Tag.DataMeasGroupSignalView))
                Iterator = New Iterator(TilMethods.GetProperty(data, Tag.DataMeasGroupSignalDataIterator), DataType.LeFloat64, parentGroup.SampleCount)
                markersProp = TilMethods.GetProperty(signal, Tag.DataMeasGroupSignalMarker)
                Markers = New Marker(TilMethods.GetVectorSize(markersProp) - 1) {}
                If Markers.Length <> 0 Then
                    For m As UInteger = 0 To Markers.Length - 1
                        Markers(m) = New Marker(TilMethods.GetVectorItem(markersProp, m))
                    Next
                End If
                Group = parentGroup
            End Sub
        End Class

        ''' <summary>Represents all signal attributes.</summary>
        Public Structure Attributes
            ''' <summary>Represents the "non-interpolatable" property. E.g., this attribute is set for a "register value" or a "segment counter" signal.</summary>
            Public ReadOnly Quantized As Boolean

            Public Sub New(ByVal attributes As IntPtr)
                Quantized = TilMethods.GetUInt(TilMethods.GetProperty(attributes, Tag.DataMeasGroupSignalDataFlagsQuantized)) <> 0
            End Sub
        End Structure

        ''' <summary>Represents the default settings for the signal views.</summary>
        Public Structure ViewDefaults
            ''' <summary>Represents the minimal representable signal value.</summary>
            Public ReadOnly Min As Double

            ''' <summary>Represents the maximal representable signal value.</summary>
            Public ReadOnly Max As Double

            Public Sub New(ByVal view As IntPtr)
                Min = TilMethods.GetDouble(TilMethods.GetProperty(view, Tag.DataMeasGroupSignalViewMin))
                Max = TilMethods.GetDouble(TilMethods.GetProperty(view, Tag.DataMeasGroupSignalViewMax))
            End Sub
        End Structure

        ''' <summary>Represents a marker.</summary>
        Public Structure Marker
            ''' <summary>Represents the marker's identifier.</summary>
            Public ReadOnly Name As String

            ''' <summary>Represents the marker's zero-based sample index or -1 if invalid.</summary>
            Public ReadOnly SampleIndex As Long

            ''' <summary>Represents the marker's visibile attribute. See also the <c>IsVisible</c> property.</summary>
            Public ReadOnly VisibleAttribute As Boolean

            ''' <summary>Represents the marker type. The weighing is similar to "header levels".</summary>
            Public ReadOnly Type As UInteger

            ''' <summary>Represents the marker text.</summary>
            Public ReadOnly Text As String

            ''' <summary>Represents the text angle with 0.01 degree per bit (starting counterclockwise from 3 o'clock position) or -1 if invalid.</summary>
            Public ReadOnly TextAngle As Integer

            ''' <summary>Represents the text distance with 0.01 mm per bit or -1 if invalid.</summary>
            Public ReadOnly TextDistance As Integer

            ''' <summary>Represents the validity of the marker's zero-based sample index.</summary>
            Public ReadOnly Property IsSampleIndexValid() As Boolean
                Get
                    Return SampleIndex >= 0
                End Get
            End Property

            ''' <summary>Represents the marker's visibility.</summary>
            Public ReadOnly Property IsVisible() As Boolean
                Get
                    Return VisibleAttribute AndAlso IsSampleIndexValid
                End Get
            End Property

            ''' <summary>Represents the validity of the text angle.</summary>
            Public ReadOnly Property IsTextAngleValid() As Boolean
                Get
                    Return TextAngle >= 0
                End Get
            End Property

            ''' <summary>Represents the validity of the text distance.</summary>
            Public ReadOnly Property IsTextDistanceValid() As Boolean
                Get
                    Return TextDistance >= 0
                End Get
            End Property

            Public Sub New(ByVal marker As IntPtr)
                Name = TilMethods.GetString(TilMethods.GetProperty(marker, Tag.DataMeasGroupSignalMarkerName))
                SampleIndex = TilMethods.GetLong(TilMethods.GetProperty(marker, Tag.DataMeasGroupSignalMarkerSampleindex), -1)
                VisibleAttribute = TilMethods.GetUInt(TilMethods.GetProperty(marker, Tag.DataMeasGroupSignalMarkerVisible)) <> 0
                Type = TilMethods.GetUInt(TilMethods.GetProperty(marker, Tag.DataMeasGroupSignalMarkerType))
                Text = TilMethods.GetString(TilMethods.GetProperty(marker, Tag.DataMeasGroupSignalMarkerText))
                TextAngle = TilMethods.GetInt(TilMethods.GetProperty(marker, Tag.DataMeasGroupSignalMarkerTextangle), -1)
                TextDistance = TilMethods.GetInt(TilMethods.GetProperty(marker, Tag.DataMeasGroupSignalMarkerTextdistance), -1)
            End Sub
        End Structure

        ''' <summary>Represents the raw values of a signal. The floating-point values of a signal are obtained by <c>Factor</c> * RawValue + <c>Offset</c>.</summary>
        Public Structure Raw
            ''' <summary>Represents the data type of the raw values.</summary>
            Public ReadOnly DataType As DataType

            ''' <summary>Represents the raw value multiplier for the floating-point values of the signal.</summary>
            Public ReadOnly Factor As Double

            ''' <summary>Represents the raw value offset for the floating-point values of the signal.</summary>
            Public ReadOnly Offset As Double

            ''' <summary>Represents the storage location of the signal raw values.</summary>
            Public ReadOnly Storage As Storage

            ''' <summary>Represents the raw values of a signal. <c>Iterator</c> should not be confused with the native iterator concept of the .NET framework.</summary>
            Public ReadOnly Iterator As Iterator

            Public Sub New(ByVal raw As IntPtr, ByVal sampleCount As ULong)
                DataType = CType(TilMethods.GetUInt(TilMethods.GetProperty(raw, Tag.DataMeasGroupSignalDataRawType)), DataType)
                Factor = TilMethods.GetDouble(TilMethods.GetProperty(raw, Tag.DataMeasGroupSignalDataRawFactor), 1)
                Offset = TilMethods.GetDouble(TilMethods.GetProperty(raw, Tag.DataMeasGroupSignalDataRawOffset))
                Storage = New Storage(TilMethods.GetProperty(raw, Tag.DataMeasGroupSignalDataRawFile))
                Iterator = If(DataType <> DataType.SampleNumber, New Iterator(TilMethods.GetProperty(raw, Tag.DataMeasGroupSignalDataRawIterator), DataType, sampleCount), New Iterator(IntPtr.Zero, DataType, sampleCount))
            End Sub

#If DEBUG Then
            ''' <summary>Converts all raw signal values to floating-point values</summary>
            Public Function ConvertTo(ByRef values As Double()) As Boolean
                values = New Double(Iterator.ItemCount - 1) {}
                Iterator.Rewind()
                If Not ConvertNextItemsTo(values, 0) Then
                    values = Nothing
                    Return False
                End If
                Return True
            End Function

            ''' <summary>Converts (a subset of) raw values to floating-point values.
            ''' <example>Example to query 2500 values in blocks of 1000 values:<code>
            ''' double[] valuesFromRaw = double[1000];
            ''' Iterator.Rewind();
            ''' ConvertNextItemsTo(valuesFromRaw, 0);
            ''' ConvertNextItemsTo(valuesFromRaw, 1000);
            ''' ConvertNextItemsTo(valuesFromRaw, 2000);
            ''' </code></example></summary>
            ''' <param name="values">Is the target array which also determines the maximal number of iterated values.</param>
            ''' <param name="sampleIndex">Is the zero-based start sample number.</param>
            Public Function ConvertNextItemsTo(ByRef values As Double(), ByVal sampleIndex As ULong) As Boolean
                If values Is Nothing Then
                    Return False
                End If

                If values.Length = 0 Then
                    Return True
                End If

                If DataType = DataType.SampleNumber Then
                    For k As Integer = 0 To values.Length - 1
                        values(k) = Factor * sampleIndex + Offset
                        sampleIndex += 1
                    Next
                    Return True
                Else
                    Select Case DataType
                        Case DataType.LeInt8, DataType.RsvdBeInt8
                            Dim rawValues As SByte() = New SByte(values.Length - 1) {}
                            If Not Iterator.CopyNextItemsTo(rawValues) Then
                                Return False
                            End If
                            For k As Integer = 0 To values.Length - 1
                                values(k) = Factor * rawValues(k) + Offset
                            Next
                            Return True
                        Case DataType.LeUInt8, DataType.RsvdBeUInt8
                            Dim rawValues As Byte() = New Byte(values.Length - 1) {}
                            If Not Iterator.CopyNextItemsTo(rawValues) Then
                                Return False
                            End If
                            For k As Integer = 0 To values.Length - 1
                                values(k) = Factor * rawValues(k) + Offset
                            Next
                            Return True
                        Case DataType.LeInt16
                            Dim rawValues As Short() = New Short(values.Length - 1) {}
                            If Not Iterator.CopyNextItemsTo(rawValues) Then
                                Return False
                            End If
                            For k As Integer = 0 To values.Length - 1
                                values(k) = Factor * rawValues(k) + Offset
                            Next
                            Return True
                        Case DataType.LeUInt16
                            Dim rawValues As UShort() = New UShort(values.Length - 1) {}
                            If Not Iterator.CopyNextItemsTo(rawValues) Then
                                Return False
                            End If
                            For k As Integer = 0 To values.Length - 1
                                values(k) = Factor * rawValues(k) + Offset
                            Next
                            Return True
                        Case DataType.LeInt32
                            Dim rawValues As Integer() = New Integer(values.Length - 1) {}
                            If Not Iterator.CopyNextItemsTo(rawValues) Then
                                Return False
                            End If
                            For k As Integer = 0 To values.Length - 1
                                values(k) = Factor * rawValues(k) + Offset
                            Next
                            Return True
                        Case DataType.LeUInt32
                            Dim rawValues As UInteger() = New UInteger(values.Length - 1) {}
                            If Not Iterator.CopyNextItemsTo(rawValues) Then
                                Return False
                            End If
                            For k As Integer = 0 To values.Length - 1
                                values(k) = Factor * rawValues(k) + Offset
                            Next
                            Return True
                        Case DataType.LeInt64
                            Dim rawValues As Long() = New Long(values.Length - 1) {}
                            If Not Iterator.CopyNextItemsTo(rawValues) Then
                                Return False
                            End If
                            For k As Integer = 0 To values.Length - 1
                                values(k) = Factor * rawValues(k) + Offset
                            Next
                            Return True
                        Case DataType.LeUInt64
                            Dim rawValues As ULong() = New ULong(values.Length - 1) {}
                            If Not Iterator.CopyNextItemsTo(rawValues) Then
                                Return False
                            End If
                            For k As Integer = 0 To values.Length - 1
                                values(k) = Factor * rawValues(k) + Offset
                            Next
                            Return True
                        Case DataType.LeFloat32
                            Dim rawValues As Single() = New Single(values.Length - 1) {}
                            If Not Iterator.CopyNextItemsTo(rawValues) Then
                                Return False
                            End If
                            For k As Integer = 0 To values.Length - 1
                                values(k) = Factor * rawValues(k) + Offset
                            Next
                            Return True
                        Case DataType.LeFloat64
                            Dim rawValues As Double() = New Double(values.Length - 1) {}
                            If Not Iterator.CopyNextItemsTo(rawValues) Then
                                Return False
                            End If
                            For k As Integer = 0 To values.Length - 1
                                values(k) = Factor * rawValues(k) + Offset
                            Next
                            Return True
                    End Select
                End If
                Return False
            End Function
#End If
        End Structure

        ''' <summary>Represents the storage location of the signal raw values.</summary>
        Public Structure Storage
            ''' <summary>Represents the file name of the signal raw values.</summary>
            Public ReadOnly FileName As String

            ''' <summary>Represents the file offset of the first signal raw value.</summary>
            Public ReadOnly Offset As ULong

            ''' <summary>Represents the data size of one signal raw value in bytes.</summary>
            Public ReadOnly DataSize As UInteger

            ''' <summary>Represents the number of bytes which separates two adjacent raw values.</summary>
            Public ReadOnly Gap As UInteger

            Public Sub New(ByVal file As IntPtr)
                FileName = TilMethods.GetString(TilMethods.GetProperty(file, Tag.DataMeasGroupSignalDataRawFileName))
                Offset = TilMethods.GetULong(TilMethods.GetProperty(file, Tag.DataMeasGroupSignalDataRawFileOffset))
                DataSize = TilMethods.GetUInt(TilMethods.GetProperty(file, Tag.DataMeasGroupSignalDataRawFileDatasize))
                Gap = TilMethods.GetUInt(TilMethods.GetProperty(file, Tag.DataMeasGroupSignalDataRawFileGap))
            End Sub
        End Structure

        ''' <summary>Provides access to the signal values. <c>Iterator</c> should not be confused with the native iterator concept of the .NET framework.</summary>
        Public Structure Iterator
            ''' <summary>Represents the data type of the iterator's values.</summary>
            Public ReadOnly DataType As DataType

            ''' <summary>Represents the size of one iterator value in bytes.</summary>
            Public ReadOnly ItemSize As UInteger

            ''' <summary>Represents the total number of iterator values.</summary>
            Public ReadOnly ItemCount As ULong

            Public ReadOnly Property IsAvailable() As Boolean
                Get
                    Return iterator <> IntPtr.Zero
                End Get
            End Property

            Private iterator As IntPtr

            Public Sub New(ByVal iteratorProp As IntPtr, ByVal dataTypeProp As DataType, ByVal itemCountProp As ULong)
                DataType = dataTypeProp
                ItemCount = itemCountProp
                ItemSize = TilMethods.GetIteratorItemSize(iteratorProp)
                iterator = iteratorProp
            End Sub

            ''' <summary>Resets the internal iterator's position counter.</summary>
            Public Function Rewind() As Boolean
                Return TilMethods.RewindIterator(iterator)
            End Function

            ''' <summary>Copies all values of an iterator.</summary>
            Public Function CopyTo(Of T)(ByRef values As T()) As Boolean
                If Not IsAvailable Then
                    values = Nothing
                    Return False
                End If
                values = New T(ItemCount - 1) {}
                Rewind()
                If Not CopyNextItemsTo(Of T)(values) Then
                    values = Nothing
                    Return False
                End If
                Return True
            End Function

            ''' <summary>Copies (a subset of) iterator values.
            ''' <example>Example to query 2500 values in blocks of 1000 values:<code>
            ''' double[] values = double[1000];
            ''' Rewind();
            ''' CopyNextItemsTo(values);
            ''' CopyNextItemsTo(values);
            ''' CopyNextItemsTo(values);
            ''' </code></example></summary>
            ''' <param name="values">Is the target array which also determines the maximal number of iterated values.</param>
            Public Function CopyNextItemsTo(Of T)(ByRef values As T()) As Boolean
                Return TilMethods.GetNextIteratorItems(Of T)(iterator, values)
            End Function
        End Structure

        Public Structure View
            ''' <summary>Represents the name of the view. The name of the first view (= default view) is empty.</summary>
            Public ReadOnly Name As String

            ''' <summary>Represents the view items.</summary>
            Public ReadOnly Items As ViewItem()

            Public Sub New(ByVal view As IntPtr, ByVal groups As Group())
                Dim comm As IntPtr, itemsProp As IntPtr
                comm = TilMethods.GetProperty(view, Tag.DataViewComm)
                Name = TilMethods.GetString(TilMethods.GetProperty(comm, Tag.DataViewCommName))
                itemsProp = TilMethods.GetProperty(view, Tag.DataViewItem)
                Items = New ViewItem(TilMethods.GetVectorSize(itemsProp) - 1) {}
                If Items.Length <> 0 Then
                    For i As UInteger = 0 To Items.Length - 1
                        Items(i) = New ViewItem(TilMethods.GetVectorItem(itemsProp, i), groups)
                    Next
                End If
            End Sub
        End Structure

        Public Structure ViewItem
            ''' <summary>Represents the view item's signal.</summary>
            Public ReadOnly Info As SignalInfo

            ''' <summary>Represents the name of the displayed signal name.</summary>
            Public ReadOnly Name As String

            ''' <summary>Represents the name of the displayed physical unit.</summary>
            Public ReadOnly Unit As String

            ''' <summary>Represents the additional signal multiplier.
            ''' The item value is obtained by ItemValue(t) = Factor * SignalValue(t - RefOffset) + Offset</summary>
            Public ReadOnly Factor As Double

            ''' <summary>Represents the additional signal offset.
            ''' The item value is obtained by ItemValue(t) = Factor * SignalValue(t - RefOffset) + Offset</summary>
            Public ReadOnly Offset As Double

            ''' <summary>Represents the reference multiplier. This property is always 1 at the moment.</summary>
            Public ReadOnly RefFactor As Double

            ''' <summary>Represents the signal delay in units of the reference signal.
            ''' The item value is obtained by ItemValue(t) = Factor * SignalValue(t - RefOffset) + Offset</summary>
            Public ReadOnly RefOffset As Double
            Public ReadOnly SlotVisibleAttribute As Boolean
            Public ReadOnly CurveVisibleAttribute As Boolean
            Public ReadOnly Digits As Integer
            Public ReadOnly CurveColor As UInteger
            Public ReadOnly CurveThickness As UInteger
            Public ReadOnly CurveLinePattern As UInteger
            Public ReadOnly Begin As Double
            Public ReadOnly [End] As Double
            Public ReadOnly AxisPosition As Integer
            Public ReadOnly XAxisPosition As Integer
            Public ReadOnly AxisMin As Double
            Public ReadOnly AxisMax As Double
            Public ReadOnly AxisName As String
            Public ReadOnly AxisTitle As String
            Public ReadOnly AxisDefaultMin As Double
            Public ReadOnly AxisDefaultMax As Double

            Public ReadOnly Property IsSlotVisible As Boolean
                Get
                    Return SlotVisibleAttribute
                End Get
            End Property

            Public ReadOnly Property IsCurveVisible As Boolean
                Get
                    Return CurveVisibleAttribute
                End Get
            End Property

            Public Sub New(ByVal item As IntPtr, ByVal groups As Group())
                Me.New()
                Dim comm As IntPtr
                Info = New SignalInfo(TilMethods.GetProperty(item, Tag.DataViewItemSignalinfo), groups)
                comm = TilMethods.GetProperty(item, Tag.DataViewItemComm)
                Name = TilMethods.GetString(TilMethods.GetProperty(comm, Tag.DataViewItemCommName))
                Unit = TilMethods.GetString(TilMethods.GetProperty(item, Tag.DataViewItemUnit))
                Factor = TilMethods.GetDouble(TilMethods.GetProperty(item, Tag.DataViewItemFactor), 1)
                Offset = TilMethods.GetDouble(TilMethods.GetProperty(item, Tag.DataViewItemOffset))
                RefFactor = TilMethods.GetDouble(TilMethods.GetProperty(item, Tag.DataViewItemReffactor), 1)
                RefOffset = TilMethods.GetDouble(TilMethods.GetProperty(item, Tag.DataViewItemRefoffset))
                SlotVisibleAttribute = TilMethods.GetUInt(TilMethods.GetProperty(item, Tag.DataViewItemSlotVisible)) <> 0
                Digits = TilMethods.GetInt(TilMethods.GetProperty(item, Tag.DataViewItemDigits))
                CurveVisibleAttribute = TilMethods.GetUInt(TilMethods.GetProperty(item, Tag.DataViewItemCurveVisible)) <> 0
                CurveColor = TilMethods.GetUInt(TilMethods.GetProperty(item, Tag.DataViewItemColor))
                CurveThickness = TilMethods.GetUInt(TilMethods.GetProperty(item, Tag.DataViewItemThickness))
                CurveLinePattern = TilMethods.GetUInt(TilMethods.GetProperty(item, Tag.DataViewItemPattern))
                Begin = TilMethods.GetDouble(TilMethods.GetProperty(item, Tag.DataViewItemBegin))
                [End] = TilMethods.GetDouble(TilMethods.GetProperty(item, Tag.DataViewItemEnd))
                AxisPosition = TilMethods.GetInt(TilMethods.GetProperty(item, Tag.DataViewItemAxisPos))
                XAxisPosition = TilMethods.GetInt(TilMethods.GetProperty(item, Tag.DataViewItemXAxisPos))
                AxisMin = TilMethods.GetDouble(TilMethods.GetProperty(item, Tag.DataViewItemAxisMin))
                AxisMax = TilMethods.GetDouble(TilMethods.GetProperty(item, Tag.DataViewItemAxisMax))
                AxisName = TilMethods.GetString(TilMethods.GetProperty(item, Tag.DataViewItemAxisName))
                AxisTitle = TilMethods.GetString(TilMethods.GetProperty(item, Tag.DataViewItemAxisTitle))
                AxisDefaultMin = TilMethods.GetDouble(TilMethods.GetProperty(item, Tag.DataViewItemAxisDefMin))
                AxisDefaultMax = TilMethods.GetDouble(TilMethods.GetProperty(item, Tag.DataViewItemAxisDefMax))
            End Sub
        End Structure

        Public Structure SignalInfo
            ''' <summary>Represents the zero-based measurement index. This property is always zero at the moment.</summary>
            Public ReadOnly MeasIndex As UInteger

            ''' <summary>Represents the zero-based group index within the respective measurement.</summary>
            Public ReadOnly GroupIndex As UInteger

            ''' <summary>Represents the zero-based signal index within the respective group.</summary>
            Public ReadOnly SignalIndex As UInteger

            ''' <summary>Represents the signal.</summary>
            Public ReadOnly Signal As Signal

            ''' <summary>Represents the reference signal.</summary>
            Public ReadOnly RefSignal As Signal

            Public ReadOnly Property IsRefSignal() As Boolean
                Get
                    Return SignalIndex = 0
                End Get
            End Property

            Public Sub New(ByVal info As IntPtr, ByVal groups As Group())
                MeasIndex = TilMethods.GetUInt(TilMethods.GetProperty(info, Tag.DataViewItemSignalinfoMeasindex))
                GroupIndex = TilMethods.GetUInt(TilMethods.GetProperty(info, Tag.DataViewItemSignalinfoGroupindex))
                SignalIndex = TilMethods.GetUInt(TilMethods.GetProperty(info, Tag.DataViewItemSignalinfoSignalindex))
                If MeasIndex = 0 AndAlso groups.Length > GroupIndex Then
                    If groups(GroupIndex).Signals.Length > 0 Then
                        RefSignal = groups(GroupIndex).Signals(0)
                    End If
                    If groups(GroupIndex).Signals.Length > SignalIndex Then
                        Signal = groups(GroupIndex).Signals(SignalIndex)
                    End If
                End If
            End Sub
        End Structure

        Public Structure Timestamp
            Public ReadOnly Year As Integer
            Public ReadOnly Month As Integer
            Public ReadOnly Day As Integer
            Public ReadOnly Hour As Integer
            Public ReadOnly Minute As Integer
            Public ReadOnly Second As Integer
            Public ReadOnly Microsecond As Integer

            ''' <summary>Represents the number of days since December 30, 1899.</summary>
            Public ReadOnly Time64 As Double

            Public ReadOnly Property IsAvailable() As Boolean
                Get
                    Return Year <> 0
                End Get
            End Property

            Public Sub New(ByVal timestamp As Double)
#If DEBUG Then
                ' CLR consistency check
                Dim roundingCheck As New DateTime(29999)
                If roundingCheck.Millisecond <> 2 Then
                    Throw New Exception("Unexpected tick rounding in DateTime!")
                End If
#End If
                Time64 = timestamp

                If timestamp = 0 OrElse timestamp < -693593 OrElse timestamp > 2958465 Then
                    Year = 0
                    Month = 0
                    Day = 0
                    Hour = 0
                    Minute = 0
                    Second = 0
                    Microsecond = 0
                    Exit Sub
                End If

                Dim ticks As Long = timestamp * 864000000000L
                ticks += 599264352000000005L
                Dim dt As New DateTime(ticks)
                Year = dt.Year
                Month = dt.Month
                Day = dt.Day
                Hour = dt.Hour
                Minute = dt.Minute
                Second = dt.Second
                Microsecond = (ticks Mod 10000000) / 20
                Microsecond *= 2
            End Sub

            Public Overrides Function ToString() As String
                Return If(IsAvailable, String.Format(CultureInfo.InvariantCulture, "{0:D4}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}{6}{7:D6}", Year, Month, Day, Hour,
                 Minute, Second, CultureInfo.CurrentCulture.NumberFormat.PercentDecimalSeparator, Microsecond), String.Empty)
            End Function
        End Structure

#If DEBUG Then
        <Serializable()>
        Public Class Exception
            Inherits System.Exception
            Public Sub New()
            End Sub
            Public Sub New(ByVal Message As String)
                MyBase.New(Message)
            End Sub
            Protected Sub New(ByVal Info As SerializationInfo, ByVal Context As StreamingContext)
                MyBase.New(Info, Context)
            End Sub
        End Class
#End If

        ''' <summary>Represents signal data types with following prefixes:
        ''' Le = little endian (Intel), Be = big endian (Motorola), Rsvd = reserved for.</summary>
        Public Enum DataType
            Unknown
            SampleNumber
            LeUInt8
            LeInt8
            LeUInt16
            LeInt16
            LeUInt32
            LeInt32
            LeUInt64
            LeInt64
            LeFloat32 = 32
            LeFloat64
            RsvdLeFloat80
            RsvdBeUInt8 = 16
            RsvdBeInt8
            RsvdBeUInt16
            RsvdBeInt16
            RsvdBeUInt32
            RsvdBeInt32
            RsvdBeUInt64
            RsvdBeInt64
            RsvdBeFloat32 = 48
            RsvdBeFloat64
            RsvdBeFloat80
            RsvdChar8 = 64
            RsvdChar16
            RsvdTime64 = 80
        End Enum

        Private Const TemesTilGuid As String = "{35F0EC67-B7ED-4627-9EF6-563016B176B5}"

        Private Enum PropertyType
            Void
            Bool
            Int8
            Int16
            Int32
            Int64
            UInt8 = 8
            UInt16
            UInt32
            UInt64
            Float32 = 32
            Float64
            Float80
            Time64 = 40
            Data = 64
            AnsiString
            WideString
            Collection = 128
            Vector
            Iterator
        End Enum

        Private Enum Tag
            Local = 1
            LocalLangid = 1
            LocalResolvedlangid = 2
            LocalSupportedlangids = 3
            Info = 2
            InfoSupportedtypes = 1
            InfoSupportedtypesGuid = 1
            InfoSupportedtypesDescription = 2
            InfoSupportedtypesExtension = 3
            InfoSupportedtypesArgguids = 4
            InfoSupportedtypesFeatures = 5
            InfoSupportedtypesFeaturesGuid = 1
            InfoSupportedtypesFeaturesData = 2
            InfoVersion = 2
            Control = 3
            ControlTypeindex = 1
            ControlArgs = 2
            ControlArgsGuid = 1
            ControlArgsData = 2
            ControlFilename = 3
            Data = 4
            DataComm = 1
            DataCommName = 1
            DataCommComment = 2
            DataCommVariable = 3
            DataCommVariableKey = 1
            DataCommVariableValue = 2
            DataMeas = 3
            DataMeasComm = 1
            DataMeasCommName = 1
            DataMeasCommComment = 2
            DataMeasCommVariable = 3
            DataMeasCommVariableKey = 1
            DataMeasCommVariableValue = 2
            DataMeasGroup = 2
            DataMeasGroupComm = 1
            DataMeasGroupCommName = 1
            DataMeasGroupCommComment = 2
            DataMeasGroupCommVariable = 3
            DataMeasGroupCommVariableKey = 1
            DataMeasGroupCommVariableValue = 2
            DataMeasGroupSamplecount = 2
            DataMeasGroupSamplerate = 3
            DataMeasGroupInfo = 4
            DataMeasGroupInfoTime = 1
            DataMeasGroupInfoTimeHwsetup = 1
            DataMeasGroupInfoTimeStart = 2
            DataMeasGroupInfoTimeHwreadout = 3
            ' start of legacy support for V1.1.1 downwards
            DataMeasGroupInfoTimeStamp = 4
            DataMeasGroupInfoTimeStampSampleindex = 1
            DataMeasGroupInfoTimeStampTime = 2
            ' end of legacy support for V1.1.1 downwards 
            DataMeasGroupInfoTimeSection = 4
            DataMeasGroupInfoTimeSectionSampleindex = 1
            DataMeasGroupInfoTimeSectionStart = 2
            DataMeasGroupSignal = 5
            DataMeasGroupSignalComm = 1
            DataMeasGroupSignalCommName = 1
            DataMeasGroupSignalCommComment = 2
            DataMeasGroupSignalCommVariable = 3
            DataMeasGroupSignalCommVariableKey = 1
            DataMeasGroupSignalCommVariableValue = 2
            DataMeasGroupSignalInternalname = 2
            DataMeasGroupSignalUnit = 3
            DataMeasGroupSignalData = 4
            DataMeasGroupSignalDataRaw = 1
            DataMeasGroupSignalDataRawType = 1
            DataMeasGroupSignalDataRawFactor = 2
            DataMeasGroupSignalDataRawOffset = 3
            DataMeasGroupSignalDataRawFile = 4
            DataMeasGroupSignalDataRawFileName = 1
            DataMeasGroupSignalDataRawFileOffset = 2
            DataMeasGroupSignalDataRawFileDatasize = 3
            DataMeasGroupSignalDataRawFileGap = 4
            DataMeasGroupSignalDataRawIterator = 5
            DataMeasGroupSignalDataInvalidvalue = 2
            DataMeasGroupSignalDataIterator = 3
            DataMeasGroupSignalDataFlags = 4
            DataMeasGroupSignalDataFlagsQuantized = 1
            DataMeasGroupSignalDataFlagsWraparoundcounter = 2
            DataMeasGroupSignalRefsignal = 5
            DataMeasGroupSignalRefsignalFactor = 1
            DataMeasGroupSignalRefsignalOffset = 2
            DataMeasGroupSignalView = 6
            DataMeasGroupSignalViewMin = 1
            DataMeasGroupSignalViewMax = 2
            DataMeasGroupSignalMarker = 7
            DataMeasGroupSignalMarkerName = 1
            DataMeasGroupSignalMarkerSampleindex = 2
            DataMeasGroupSignalMarkerVisible = 3
            DataMeasGroupSignalMarkerType = 4
            DataMeasGroupSignalMarkerText = 5
            DataMeasGroupSignalMarkerTextangle = 6
            DataMeasGroupSignalMarkerTextdistance = 7
            DataView = 4
            DataViewComm = 1
            DataViewCommName = 1
            DataViewItem = 2
            DataViewItemComm = 1
            DataViewItemCommName = 1
            DataViewItemSignalinfo = 2
            DataViewItemSignalinfoMeasindex = 1
            DataViewItemSignalinfoGroupindex = 2
            DataViewItemSignalinfoSignalindex = 3
            DataViewItemUnit = 3
            DataViewItemFactor = 4
            DataViewItemOffset = 5
            DataViewItemReffactor = 6
            DataViewItemRefoffset = 7
            DataViewItemVisible = 8
            DataViewItemSlotVisible = 8
            DataViewItemDigits = 9
            DataViewItemCurveVisible = 10
            DataViewItemColor = 11
            DataViewItemThickness = 12
            DataViewItemPattern = 13
            DataViewItemBegin = 14
            DataViewItemEnd = 15
            DataViewItemAxisPos = 16
            DataViewItemXAxisPos = 17
            DataViewItemAxisMin = 18
            DataViewItemAxisMax = 19
            DataViewItemAxisName = 20
            DataViewItemAxisTitle = 21
            DataViewItemAxisDefMin = 22
            DataViewItemAxisDefMax = 23
        End Enum

        ' ----------------------------------------------------------------------
        ' "til_tms.dll" parameters are allowed to be NULL (to indicate non-
        ' existing parameters). However, NULL parameters are catched to maintain
        ' a nice looking debug log when the debug version of "til_tms.dll" is 
        ' used.
        '
        ' It Is possible to replace the system wide "til_tms.dll" by 
        ' copying the "til_tms.dll" in the executable subfolder "\x86" or 
        ' "\x64" respectively.
        '
        ' Platform | Correct "til_tms.dll"/"zlipwapi.dll" version
        ' ---------+------------------------------------------------------------
        ' Any CPU  | 32-bit or x64 (depending on the running OS)
        ' x86      | 32-bit
        ' x64      | x64

        Private NotInheritable Class TilMethods

            Private Shared missingParameter As IntPtr = IntPtr.Zero
            Private Shared ReadOnly queryStringLength As New IntPtr(-1)

            Private Sub New()
            End Sub

            Friend Shared Function CreateObject(ByVal guid As String) As IntPtr
                If guid Is Nothing Then
                    Return IntPtr.Zero
                End If
                Return NativeMethods.TilCreateObject(guid)
            End Function

            Friend Shared Sub DestroyObject(ByVal obj As IntPtr)
                If obj = IntPtr.Zero Then
                    Exit Sub
                End If
                NativeMethods.TilDestroyObject(obj)
            End Sub

            Friend Shared Function GetRootProperty(ByVal obj As IntPtr) As IntPtr
                If obj = IntPtr.Zero Then
                    Return IntPtr.Zero
                End If
                Return NativeMethods.TilGetRootProperty(obj)
            End Function

            Friend Shared Function GetProperty(ByVal prop As IntPtr, ByVal tag As Tag) As IntPtr
                If prop = IntPtr.Zero Then
                    Return IntPtr.Zero
                End If
                Return NativeMethods.TilGetProperty(prop, CInt(tag))
            End Function

            Friend Overloads Shared Function [GetType](ByVal prop As IntPtr) As PropertyType
                If prop = IntPtr.Zero Then
                    Return PropertyType.Void
                End If
                Return CType(NativeMethods.TilGetType(prop), PropertyType)
            End Function

            Friend Shared Function GetULong(ByVal prop As IntPtr, ByVal defaultValue As ULong) As ULong
                Dim value As ULong
                If prop = IntPtr.Zero Then
                    Return defaultValue
                End If
                If NativeMethods.TilGetUInt64(prop, value) = 0 Then
                    Return defaultValue
                End If
                Return value
            End Function

            Friend Shared Function GetULong(ByVal prop As IntPtr) As ULong
                Return GetULong(prop, 0)
            End Function

            Friend Shared Function GetUInt(ByVal prop As IntPtr, ByVal defaultValue As UInteger) As UInteger
                Return CUInt(GetULong(prop, CULng(defaultValue)))
            End Function

            Friend Shared Function GetUInt(ByVal prop As IntPtr) As UInteger
                Return GetUInt(prop, 0)
            End Function

            Friend Shared Function GetLong(ByVal prop As IntPtr, ByVal defaultValue As Long) As Long
                Dim value As Long
                If prop = IntPtr.Zero Then
                    Return defaultValue
                End If
                If NativeMethods.TilGetInt64(prop, value) = 0 Then
                    Return defaultValue
                End If
                Return value
            End Function

            Friend Shared Function GetLong(ByVal prop As IntPtr) As Long
                Return GetLong(prop, 0)
            End Function

            Friend Shared Function GetInt(ByVal prop As IntPtr, ByVal defaultValue As Integer) As Integer
                Return CInt(GetLong(prop, CLng(defaultValue)))
            End Function

            Friend Shared Function GetInt(ByVal prop As IntPtr) As Integer
                Return GetInt(prop, 0)
            End Function

            Friend Shared Function GetDouble(ByVal prop As IntPtr, ByVal defaultValue As Double) As Double
                Dim value As Double
                If prop = IntPtr.Zero Then
                    Return defaultValue
                End If
                If NativeMethods.TilGetFloat64(prop, value) = 0 Then
                    Return defaultValue
                End If
                Return value
            End Function

            Friend Shared Function GetDouble(ByVal prop As IntPtr) As Double
                Return GetDouble(prop, 0)
            End Function

            Friend Shared Function GetTime64(ByVal prop As IntPtr) As Double
                Dim value As Double
                If prop = IntPtr.Zero Then
                    Return 0
                End If
                If NativeMethods.TilGetTime64(prop, value) = 0 Then
                    Return 0
                End If
                Return value
            End Function

            Friend Shared Function GetVectorSize(ByVal prop As IntPtr) As UInteger
                Return If(prop <> IntPtr.Zero, CUInt(NativeMethods.TilGetVectorSize(prop)), CUInt(0))
            End Function

            Friend Shared Function GetVectorItem(ByVal prop As IntPtr, ByVal index As UInteger) As IntPtr
                Return NativeMethods.TilGetVectorItem(prop, CType(index, IntPtr))
            End Function

            Friend Shared Function GetString(ByVal prop As IntPtr, ByVal defaultValue As String) As String
                If prop = IntPtr.Zero Then
                    Return defaultValue
                End If
                Dim length As IntPtr = queryStringLength
                If NativeMethods.TilGetString(prop, Nothing, queryStringLength, length) = 0 Then
                    ' ignore function result 
                End If
                If length = queryStringLength Then
                    Return defaultValue
                End If
                Dim value As New StringBuilder(CInt(length))
                If NativeMethods.TilGetString(prop, value, length, missingParameter) = 0 Then
                    Return defaultValue
                End If
                Return value.ToString()
            End Function

            Friend Shared Function GetString(ByVal prop As IntPtr) As String
                Return GetString(prop, String.Empty)
            End Function

            Friend Shared Function SetString(ByVal prop As IntPtr, ByVal value As String) As Boolean
                If prop = IntPtr.Zero OrElse value Is Nothing Then
                    Return False
                End If
                Return NativeMethods.TilSetString(prop, value) <> 0
            End Function

            Friend Shared Function GetIteratorItemSize(ByVal iterator As IntPtr) As UInteger
                If iterator = IntPtr.Zero Then
                    Return 0
                End If
                Return CUInt(NativeMethods.TilGetIteratorItemSize(iterator))
            End Function

            Friend Shared Function RewindIterator(ByVal iterator As IntPtr) As Boolean
                If iterator = IntPtr.Zero Then
                    Return False
                End If
                Return NativeMethods.TilRewindIterator(iterator) <> 0
            End Function

            Friend Shared Function GetNextIteratorItems(Of T)(ByVal iterator As IntPtr, ByRef values As T()) As Boolean
                If iterator = IntPtr.Zero OrElse values Is Nothing Then
                    Return False
                End If
                If GetIteratorItemSize(iterator) <> Marshal.SizeOf(GetType(T)) Then
                    Return False
                End If
                If GetType(T) Is GetType(Double) Then
#If Not SUPPORT_OLDER_TILTMS_VERSIONS Then
                    Return NativeMethods.TilGetNextIteratorItems(iterator, DirectCast(DirectCast(values, Object), Double()), CType(values.Length, IntPtr)) <> 0
#Else
						NativeMethods.TilGetNextIteratorItems(iterator, DirectCast(DirectCast(values, Object), Double()), CType(values.Length, IntPtr))
						Return True
#End If
                ElseIf GetType(T) Is GetType(UShort) Then
                    Return NativeMethods.TilGetNextIteratorItems(iterator, DirectCast(DirectCast(values, Object), UShort()), CType(values.Length, IntPtr)) <> 0
                ElseIf GetType(T) Is GetType(UInteger) Then
                    Return NativeMethods.TilGetNextIteratorItems(iterator, DirectCast(DirectCast(values, Object), UInteger()), CType(values.Length, IntPtr)) <> 0
                ElseIf GetType(T) Is GetType(Integer) Then
                    Return NativeMethods.TilGetNextIteratorItems(iterator, DirectCast(DirectCast(values, Object), Integer()), CType(values.Length, IntPtr)) <> 0
                ElseIf GetType(T) Is GetType(ULong) Then
                    Return NativeMethods.TilGetNextIteratorItems(iterator, DirectCast(DirectCast(values, Object), ULong()), CType(values.Length, IntPtr)) <> 0
                ElseIf GetType(T) Is GetType(Byte) Then
                    Return NativeMethods.TilGetNextIteratorItems(iterator, DirectCast(DirectCast(values, Object), Byte()), CType(values.Length, IntPtr)) <> 0
                ElseIf GetType(T) Is GetType(Long) Then
                    Return NativeMethods.TilGetNextIteratorItems(iterator, DirectCast(DirectCast(values, Object), Long()), CType(values.Length, IntPtr)) <> 0
                ElseIf GetType(T) Is GetType(Short) Then
                    Return NativeMethods.TilGetNextIteratorItems(iterator, DirectCast(DirectCast(values, Object), Short()), CType(values.Length, IntPtr)) <> 0
                ElseIf GetType(T) Is GetType(SByte) Then
                    Return NativeMethods.TilGetNextIteratorItems(iterator, DirectCast(DirectCast(values, Object), SByte()), CType(values.Length, IntPtr)) <> 0
                ElseIf GetType(T) Is GetType(Single) Then
                    Return NativeMethods.TilGetNextIteratorItems(iterator, DirectCast(DirectCast(values, Object), Single()), CType(values.Length, IntPtr)) <> 0
                End If
                Return False
            End Function
        End Class

        Private NotInheritable Class NativeMethods

            Shared Sub New()
                Dim path As String = New Uri(GetType(NativeMethods).Assembly.CodeBase).LocalPath
                Dim folder As String = System.IO.Path.GetDirectoryName(path)
                Dim subFolder As String = If((IntPtr.Size = 8), "\x64\", "\x86\")
                LoadLibrary(folder & subFolder & "til_tms.dll")
            End Sub

            <DllImport("kernel32.dll")>
            Private Shared Function LoadLibrary(ByVal libFileName As String) As IntPtr
            End Function

            <DllImport("til_tms.dll", CharSet:=CharSet.Unicode)>
            Friend Shared Function TilCreateObject(ByVal guid As String) As IntPtr
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Sub TilDestroyObject(ByVal obj As IntPtr)
            End Sub

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetRootProperty(ByVal obj As IntPtr) As IntPtr
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetProperty(ByVal prop As IntPtr, ByVal tag As Integer) As IntPtr
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetType(ByVal prop As IntPtr) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetUInt64(ByVal prop As IntPtr, ByRef value As ULong) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetInt64(ByVal prop As IntPtr, ByRef value As Long) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetFloat64(ByVal prop As IntPtr, ByRef value As Double) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetTime64(ByVal prop As IntPtr, ByRef value As Double) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetVectorSize(ByVal prop As IntPtr) As IntPtr
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetVectorItem(ByVal prop As IntPtr, ByVal index As IntPtr) As IntPtr
            End Function

            <DllImport("til_tms.dll", CharSet:=CharSet.Unicode)>
            Friend Shared Function TilGetString(ByVal prop As IntPtr, ByVal value As StringBuilder, ByVal maxLength As IntPtr, ByRef valueLength As IntPtr) As Integer
            End Function

            <DllImport("til_tms.dll", CharSet:=CharSet.Unicode)>
            Friend Shared Function TilSetString(ByVal prop As IntPtr, ByVal value As String) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilRewindIterator(ByVal iterator As IntPtr) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetIteratorItemSize(ByVal iterator As IntPtr) As IntPtr
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetNextIteratorItems(ByVal iterator As IntPtr, <Out()> ByVal values As Byte(), ByVal count As IntPtr) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetNextIteratorItems(ByVal iterator As IntPtr, <Out()> ByVal values As SByte(), ByVal count As IntPtr) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetNextIteratorItems(ByVal iterator As IntPtr, <Out()> ByVal values As UShort(), ByVal count As IntPtr) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetNextIteratorItems(ByVal iterator As IntPtr, <Out()> ByVal values As Short(), ByVal count As IntPtr) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetNextIteratorItems(ByVal iterator As IntPtr, <Out()> ByVal values As UInteger(), ByVal count As IntPtr) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetNextIteratorItems(ByVal iterator As IntPtr, <Out()> ByVal values As Integer(), ByVal count As IntPtr) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetNextIteratorItems(ByVal iterator As IntPtr, <Out()> ByVal values As ULong(), ByVal count As IntPtr) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetNextIteratorItems(ByVal iterator As IntPtr, <Out()> ByVal values As Long(), ByVal count As IntPtr) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetNextIteratorItems(ByVal iterator As IntPtr, <Out()> ByVal values As Single(), ByVal count As IntPtr) As Integer
            End Function

            <DllImport("til_tms.dll")>
            Friend Shared Function TilGetNextIteratorItems(ByVal iterator As IntPtr, <Out()> ByVal values As Double(), ByVal count As IntPtr) As Integer
            End Function
        End Class
    End Class
End Namespace
