Imports CndexLinkDotNet
Imports Microsoft.Win32
Imports CMSControl.App.Runtime
Imports CMSControl.Config.Settings

Imports T_memType = System.Collections.Generic.Dictionary(Of System.Int32, System.Collections.Generic.Dictionary(Of System.Int32, System.Object))
Imports T_memDim = System.Collections.Generic.Dictionary(Of System.Int32, System.Object)

Namespace CNC

    Partial Public Class OSAI
        Inherits CNC

        'Variabili per server Cndex (Osai)
        Protected _szRemoteName As String
        Protected _UserSession As Short
        Protected _ErrClass As Integer
        Protected _ErrNum As Integer
        Friend Cndex As CndexLinkDotNet.Cndex
        Private nReturn As Short

        Protected Const ERRORE = 0

        Public Enum MemTypeWord
            I_CODE = 0
            O_CODE = 1

            MW_CODE = 20
            GW_CODE = 21
            SW_CODE = 22

            PW_CODE = 62
            UW_CODE = 63
        End Enum
        Public Enum MemTypeDouble
            MD_CODE = 40
            GD_CODE = 41
            SD_CODE = 42
            PD_CODE = 43
            UD_CODE = 44
            L_CODE = 145
        End Enum

        Public Enum MemTypeText
            LS_CODE = 18
            AA_CODE = 28
            A_CODE = 45
            SC_CODE = 50
            SYMO_A_CODE = 102
        End Enum

        Private nLicenzaTmp As Integer
        Public Overrides Property Licenza() As Integer
            Get
                Return nLicenzaTmp
            End Get
            Set(ByVal value As Integer)
                nLicenzaTmp = value
            End Set
        End Property

        Private bLicenzaScadutaTmp As Boolean
        Public Overrides Property LicenzaScaduta() As Boolean
            Get
                Return bLicenzaScadutaTmp
            End Get
            Set(ByVal value As Boolean)
                bLicenzaScadutaTmp = value
            End Set
        End Property

        Public Sub New(ByRef szRemoteName As String)
            Me.New()

            Try
                Cndex = New CndexLinkDotNet.Cndex
            Catch ex As Exception
                MsgBox(ex.Message)
            End Try

            _szRemoteName = szRemoteName
        End Sub

        Public Sub New()
            MyBase.New()
            _Type = NcType.OSAI

            'Definisco l'area della Cnc Window
            SetCncWindowSize()

            'Inizializzo le variabili
            Me._Descrizione = "NC OSAI" & vbNewLine
            Me._Descrizione = Me._Descrizione & "RemoteName: " & _szRemoteName
        End Sub

        Public Overrides Sub Connect(Optional ByRef szStatus As String = "")
            Dim nReturn As Short
            Dim pPhase As Short
            Dim szReturn As String = ""
            Dim sValue(0) As Short
            Dim TimeStart As Date

            'apro una sessione col CN
            Log.WI("TRY OpenSession CNC.OSAI", "RemoteName=" & _szRemoteName, CLog.Lev.Secondary)
            nReturn = Cndex.OpenSession_C(_szRemoteName, _UserSession, _ErrClass, _ErrNum)
            If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("OpenSession_C({0},{1}) Connect CNC.OSAI", _szRemoteName, _UserSession), szReturn) Then
                Throw New CmsNcException(szReturn)
            Else
                Log.WI("OK  OpenSession CNC.OSAI", , CLog.Lev.Secondary)
                'leggo in che fase di boot mi trovo
                nReturn = Cndex.BootPhaseEnquiry_C(_UserSession, pPhase, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("BootPhaseEnquiry_C({0},{1}) Connect CNC.OSAI", _UserSession, pPhase), szReturn) Then
                    _bConnected = False
                    Throw New CmsNcException(szReturn)
                Else
                    'verifico che il sistema si trovi in una fase operativa "stabile"
                    Log.WI("OK  BootPhaseEnquiry CNC.OSAI", "Phase=" & pPhase, CLog.Lev.Secondary)
                    If pPhase = 4 Then 'SYSTEM_UP_PHASE

                        'leggo matricola e verifico che sia diversa da zero
                        TimeStart = Now
                        Do
                            Select Case Settings.MemoryMapping
                                Case MemoryMapping.ElsManager, _
                                     MemoryMapping.Default
                                    'Matricola
                                    nReturn = O_RW_Short(False, MemTypeWord.MW_CODE, 3187, sValue)

                                Case MemoryMapping.ToolManager, _
                                     MemoryMapping.ToolTable
                                    'Matricola
                                    nReturn = O_RW_Short(False, MemTypeWord.MW_CODE, 3403, sValue)
                            End Select

                            If sValue(0) > 0 Then
                                Threading.Thread.Sleep(500)
                                Exit Do
                            End If

                            If (Now - TimeStart).Seconds > 30 Then
                                Select Case MsgBox("Matricola non inizializzata in 30 secondi: Verificare CMSKMG o PLC", MsgBoxStyle.Exclamation + MsgBoxStyle.RetryCancel)
                                    Case MsgBoxResult.Retry : TimeStart = Now
                                    Case MsgBoxResult.Cancel : Exit Do
                                End Select
                            End If
                            Log.WI("OK  Connect CNC.OSAI but SERIAL NUMBER NOT YET INITIALIZED", , CLog.Lev.Secondary)
                            Application.DoEvents()
                            Threading.Thread.Sleep(500) 'aspetto 500ms prima di ritentare
                            Application.DoEvents()
                        Loop

                        _bConnected = True
                        Log.WI("OK  Connect CNC.OSAI", "Connected=" & _bConnected, CLog.Lev.Secondary)
                    Else
                        _bConnected = False
                        Log.WI("OK  Connect CNC.OSAI but PHASE NOT OK", "Phase=" & pPhase & " Connected=" & _bConnected, CLog.Lev.Secondary)
                        Throw New CmsNcException("ERR BootPhase NOT OK CNC.OSAI")
                    End If
                End If
            End If

        End Sub

        Public Overrides Sub Disconnect(Optional ByRef szStatus As String = "")
            Dim nReturn As Short
            Dim bRet As Boolean
            Dim szReturn As String = ""

            'chiudo la sessione
            nReturn = Cndex.CloseSession_C(_UserSession, _ErrClass, _ErrNum)
            If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("CloseSession_C({0}) Disconnect CNC.OSAI", _UserSession), szReturn) Then
                _bConnected = False '?
                bRet = False
                Throw New CmsNcException(szReturn)
            Else
                _bConnected = False
                bRet = True
            End If

        End Sub

        Public Overrides Function SetCncWindowSize() As Boolean
            Dim CncWindowSizeNew As Size

            Select Case Config.Settings.Settings.OpPanel_ScreenSize 'Screen.PrimaryScreen.Bounds.Size
                Case New Size(800, 600)  '10"
                    CncWindowSizeNew = New System.Drawing.Size(640, 480)
                Case New Size(1024, 768)  '15"
                    CncWindowSizeNew = New System.Drawing.Size(773, 600) '(800, 600) 'per visualizzare senza barra almeno 3 teste
                Case New Size(2048, 768)  '15" doppio monitor
                    CncWindowSizeNew = New System.Drawing.Size(800, 600)
                Case New Size(1280, 800)  '15,6" widescreen
                    CncWindowSizeNew = New System.Drawing.Size(800, 544)
                Case New Size(1280, 1024) '17"
                    CncWindowSizeNew = New System.Drawing.Size(990, 750) '(1024, 768) 'per visualizzare senza barra almeno 3 teste
                Case New Size(1920, 1080) 'FullHD
                    CncWindowSizeNew = New System.Drawing.Size(1370, 770)
                Case Else
                    CncWindowSizeNew = New System.Drawing.Size(800, 600)
            End Select
            If _CncWindowSize <> CncWindowSizeNew Then
                _CncWindowSize = CncWindowSizeNew
                Return True
            Else
                Return False
            End If
        End Function

        Public Overrides Sub RunCnc()
            Dim szProgramFilesDir, szPath As String
            Dim key As RegistryKey
            Dim myProcess As System.Diagnostics.Process

            If Not FindCncWindow() Then
                key = Registry.LocalMachine.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion")
                szProgramFilesDir = key.GetValue("ProgramFilesDir")
                szPath = szProgramFilesDir & "\OSAI\WinNBI\ProVideo.exe"

                myProcess = System.Diagnostics.Process.Start(szPath)
            End If
        End Sub

        Public Overrides Sub CloseCnc()
            If FindCncWindow() Then
                _CncWindowProcess.Kill()
            End If
        End Sub

        Public Overrides Function FindCncWindow() As Boolean
            _CncWindowProcess = FindProcess("ProVideo")
            Return _CncWindowProcess IsNot Nothing
        End Function

        Public Overrides Function CncIsIconic() As Boolean
            If _CncWindowProcess IsNot Nothing Then
                Return ProcessIsIconic(_CncWindowProcess.MainWindowHandle)
            End If
        End Function

        Public Overrides Function CncIsZoomed() As Boolean
            If _CncWindowProcess IsNot Nothing Then
                Return ProcessIsZoomed(_CncWindowProcess.MainWindowHandle)
            End If
        End Function

        Public Overrides Sub MinimizeCnc()
            MinimizeWindow("ProVideo")
        End Sub

        Public Overrides Sub NormalizeCnc()
            Try
                MakeExternalWindowBorderless(FindProcess("ProVideo").MainWindowHandle)
            Catch ex As Exception
            End Try
            ShowNormalWindow("ProVideo")
            MoveWindow("ProVideo", _CncWindowPosition)
        End Sub

        Public Overrides Sub SetCncFocus()
            SetWindowFocus("ProVideo")
        End Sub

        Public Overrides Sub MoveCnc()
            MoveWindow("ProVideo", CncWindowPosition, "OSAI ProcessController")
            ResizeWindow("ProVideo", Me.CncWindowSize, "OSAI ProcessController")
        End Sub

        Public Overrides Function GetCncWindowId() As Long
            _CncWindowProcess = FindProcess("ProVideo")
            If _CncWindowProcess IsNot Nothing Then
                Return _CncWindowProcess.Id
            Else
                Return -1
            End If
        End Function

        ''' <summary>
        ''' Legge le memorie di configurazione dal cn
        ''' </summary>
        Public Overrides Sub GetStaticData()
            Dim sValue(0) As Short

            If Not bStaticDataReaded Then
                'Try
                Select Case Settings.MemoryMapping
                    Case MemoryMapping.ElsManager, _
                         MemoryMapping.Default
                        'Matricola
                        nReturn = Cndex.ReadVarWord_C(_UserSession, Cndex.MW_CODE, 0, 3187, 1, sValue, _ErrClass, _ErrNum)
                        If nReturn = ERRORE Then
                            Log.WW("ERR GetStaticData CNC.OSAI", "Return=" & nReturn & " ErrClass=" & _ErrClass & " ErrNum=0x" & Hex(_ErrNum))
                        Else
                            Me._Matricola = sValue(0)
                        End If
                        'Teste
                        nReturn = Cndex.ReadVarWord_C(_UserSession, Cndex.MW_CODE, 0, 3161, 1, sValue, _ErrClass, _ErrNum)
                        If nReturn = ERRORE Then
                            Log.WW("ERR GetStaticData CNC.OSAI", "Return=" & nReturn & " ErrClass=" & _ErrClass & " ErrNum=0x" & Hex(_ErrNum))
                        Else
                            Me._Teste = sValue(0)
                        End If
                        'Magazzini
                        nReturn = Cndex.ReadVarWord_C(_UserSession, Cndex.MW_CODE, 0, 3163, 1, sValue, _ErrClass, _ErrNum)
                        If nReturn = ERRORE Then
                            Log.WW("ERR GetStaticData CNC.OSAI", "Return=" & nReturn & " ErrClass=" & _ErrClass & " ErrNum=0x" & Hex(_ErrNum))
                        Else
                            Me._Magazzini = sValue(0)
                        End If
                        'Manine per Magazzino
                        ReDim Me._ManineMagazzino(Me._Magazzini - 1)
                        For i = 1 To Me._Magazzini
                            If i <= 8 Then
                                nReturn = Cndex.ReadVarWord_C(_UserSession, Cndex.MW_CODE, 0, 3164 + (i - 1), 1, sValue, _ErrClass, _ErrNum)
                                If nReturn = ERRORE Then
                                    Log.WW("ERR GetStaticData CNC.OSAI", "Return=" & nReturn & " ErrClass=" & _ErrClass & " ErrNum=0x" & Hex(_ErrNum))
                                Else
                                    Me._ManineMagazzino(i - 1) = sValue(0)
                                End If
                            Else '8-20
                                nReturn = Cndex.ReadVarWord_C(_UserSession, Cndex.MW_CODE, 0, 3188 + (i - 1), 1, sValue, _ErrClass, _ErrNum)
                                If nReturn = ERRORE Then
                                    Log.WW("ERR GetStaticData CNC.OSAI", "Return=" & nReturn & " ErrClass=" & _ErrClass & " ErrNum=0x" & Hex(_ErrNum))
                                Else
                                    Me._ManineMagazzino(i - 1) = sValue(0)
                                End If

                            End If
                        Next i

                    Case MemoryMapping.ToolManager, _
                         MemoryMapping.ToolTable
                        'Matricola
                        nReturn = Cndex.ReadVarWord_C(_UserSession, Cndex.MW_CODE, 0, 3403, 1, sValue, _ErrClass, _ErrNum)
                        If nReturn = ERRORE Then
                            Log.WW("ERR GetStaticData CNC.OSAI", "Return=" & nReturn & " ErrClass=" & _ErrClass & " ErrNum=0x" & Hex(_ErrNum))
                        Else
                            Me._Matricola = sValue(0)
                        End If
                        'Teste
                        nReturn = Cndex.ReadVarWord_C(_UserSession, Cndex.MW_CODE, 0, 3405, 1, sValue, _ErrClass, _ErrNum)
                        If nReturn = ERRORE Then
                            Log.WW("ERR GetStaticData CNC.OSAI", "Return=" & nReturn & " ErrClass=" & _ErrClass & " ErrNum=0x" & Hex(_ErrNum))
                        Else
                            Me._Teste = sValue(0)
                        End If
                        'Magazzini
                        nReturn = Cndex.ReadVarWord_C(_UserSession, Cndex.MW_CODE, 0, 3407, 1, sValue, _ErrClass, _ErrNum)
                        If nReturn = ERRORE Then
                            Log.WW("ERR GetStaticData CNC.OSAI", "Return=" & nReturn & " ErrClass=" & _ErrClass & " ErrNum=0x" & Hex(_ErrNum))
                        Else
                            Me._Magazzini = sValue(0)
                        End If
                        'Manine per Magazzino
                        Dim bPari As Boolean
                        Dim nTmp As Integer
                        ReDim Me._ManineMagazzino(Me._Magazzini - 1)
                        If Me._Magazzini Mod 2 = 0 Then 'pari
                            bPari = True
                            nTmp = Me._Magazzini / 2
                        Else 'dispari
                            nTmp = Int(Me._Magazzini / 2) + 1
                        End If
                        For i = 1 To nTmp
                            nReturn = Cndex.ReadVarWord_C(_UserSession, Cndex.MW_CODE, 0, 5520 + (i - 1), 1, sValue, _ErrClass, _ErrNum)
                            Me._ManineMagazzino(i * 2 - 2) = ShortToByte(sValue(0), LOW_ORDER)
                            If Not (Not bPari And i = nTmp) Then Me._ManineMagazzino(i * 2 - 1) = ShortToByte(sValue(0), HIGH_ORDER)
                        Next i
                End Select

                Me._MaxUtensiliGestibili = 300 'TODO IMPLEMENTARE
                Me._MaxIdUtensile = 300 'TODO IMPLEMENTARE

                'ZoomSpeed
                Select Case Settings.MemoryMapping
                    Case MemoryMapping.ElsManager
                        O_RW_Short(R, MemTypeWord.MW_CODE, 3921, sValue)
                    Case MemoryMapping.ToolManager
                        O_RW_Short(R, MemTypeWord.MW_CODE, 5670, sValue)
                    Case MemoryMapping.ToolTable
                        O_RW_Short(R, MemTypeWord.MW_CODE, 3425, sValue)
                End Select
                If sValue(0) > 0 And sValue(0) <= 100 Then
                    Me._ZoomSpeed = sValue(0)
                Else
                    Me._ZoomSpeed = 1
                End If

                bStaticDataReaded = True

                'Catch ex As CmsNcException
                '    Me.CncException(ex.Message)
                'End Try

            End If
        End Sub


        ''' <summary>
        ''' Verifica se è installata la WINNBI e se è una versione compatibile con .NET
        ''' </summary>
        ''' <param name="DotNet">Versione compatibile con framework .NET</param>
        Shared Function GetWinnbi(Optional ByRef DotNet As Boolean = False) As Boolean

            Dim DotNetMinVersion As New System.Version("3.1.1")
            Dim readValue() As String
            Dim Ver As System.Version
            Dim key As RegistryKey

            'leggo le versioni installate
            key = Registry.LocalMachine.OpenSubKey("SOFTWARE\OSAI\WinNBI")
            readValue = key.GetSubKeyNames
            'verifico che ci sia al massimo una versione installata
            If readValue.Count > 1 Then
                MessageBox.Show("Risultano installate più versioni di WinNBI." & vbNewLine & _
                                "Verificare le chiavi in HKEY_LOCAL_MACHINE\SOFTWARE\OSAI\WinNBI", _
                                "Error on GetWinnbi", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End If

            'La precisione di Osai nel rilasciare le versioni !!!
            If readValue(0) = "3.03" Then readValue(0) = "3.0.3"
            If readValue(0) = "3.04" Then readValue(0) = "3.0.4"
            If readValue(0) = "3.05" Then readValue(0) = "3.0.5"

            For Each szVersion As String In readValue
                Ver = New System.Version(szVersion)
                'Log.WI("GetWinnbi  VersionInstalled=" & szVersion, , CLog.Lev.Principal)

                'se versione compatibile con framework .NET
                If Ver >= DotNetMinVersion Then
                    DotNet = True
                End If

                'se entro almeno una volta ho trovato almeno una versione installata
                GetWinnbi = True
            Next

        End Function


        ''' <summary>
        ''' Legge o scrive Boolean da MEMORIE PLC
        ''' </summary>
        ''' <param name="bWrite">Se True SCRIVE, se False LEGGE</param>
        ''' <param name="MemType">Tipo di memoria Osai</param>
        ''' <param name="MemIndex">Indice di memoria</param>
        ''' <param name="MemBit">Bit della memoria</param>
        ''' <param name="Value">Valore da scrivere su scrittura e letto su lettura</param>
        ''' <returns>True se andata a buon fine</returns>
        Public Overridable Overloads Function O_RW_Boolean(ByVal bWrite As Boolean, ByVal MemType As MemTypeWord, ByVal MemIndex As Integer, ByVal MemBit As Integer, ByRef Value As Boolean) As Boolean
            Dim szReturn As String = ""
            Dim nValue(0) As Short

            'leggo la memoria
            nReturn = Cndex.ReadVarWord_C(_UserSession, MemType, 0, MemIndex, nValue.Length, nValue, _ErrClass, _ErrNum)
            If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("ReadVarWord_C({0},{1},{2}) O_RW_Boolean CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                Throw New CmsNcException(szReturn)
                Return False
            Else
                If bWrite Then ' *** Write
                    If Value Then 'True
                        nValue(0) = nValue(0) Or UnsignedToShort(2 ^ MemBit)
                    Else 'False
                        nValue(0) = nValue(0) And Not UnsignedToShort(2 ^ MemBit)
                    End If
                    nReturn = Cndex.WriteVarWord_C(_UserSession, MemType, 0, MemIndex, nValue.Length, nValue, _ErrClass, _ErrNum)
                    If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("WriteVarWord_C({0},{1},{2}) O_RW_Boolean CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                        Throw New CmsNcException(szReturn)
                        Return False
                    End If

                Else ' ************* Read
                    If (nValue(0) And (2 ^ MemBit)) = (2 ^ MemBit) Then 'True
                        Value = True
                    Else 'False
                        Value = False
                    End If
                End If
            End If

            Return True
        End Function

        ''' <summary>
        ''' Legge o scrive Byte da MEMORIE PLC
        ''' </summary>
        ''' <param name="bWrite">Se True SCRIVE, se False LEGGE</param>
        ''' <param name="MemType">Tipo di memoria Osai</param>
        ''' <param name="MemIndex">Indice di memoria</param>
        ''' <param name="MemOrderStart">Ordine di partenza LOW_ORDER = 0 HIGH_ORDER = 1</param>
        ''' <param name="Value">Matrice di valori da scrivere su scrittura o letti su lettura</param>
        ''' <returns>True se andata a buon fine</returns>
        Public Overridable Overloads Function O_RW_Byte(ByVal bWrite As Boolean, ByVal MemType As MemTypeWord, ByVal MemIndex As Integer, ByVal MemOrderStart As Integer, ByRef Value() As Byte) As Boolean
            Dim szReturn As String = ""
            Dim bStartHigh As Boolean = MemOrderStart
            Dim bEndDispari As Boolean = (Value.Length + MemOrderStart) Mod 2
            Dim cStart, cEnd As Byte
            Dim ValueTmp(((Value.Length + MemOrderStart) \ 2) + ((Value.Length + MemOrderStart) Mod 2) - 1) As Short


            If bWrite Then ' *** Write
                'se comincio con hi leggo la prima memo
                If bStartHigh Then
                    Dim ValStartTmp(0) As Short
                    nReturn = Cndex.ReadVarWord_C(_UserSession, MemType, 0, MemIndex, ValStartTmp.Length, ValStartTmp, _ErrClass, _ErrNum)
                    If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("ReadVarWord_C({0},{1},{2}) O_RW_Byte CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                        Throw New CmsNcException(szReturn)
                        Return False
                    Else
                        cStart = ShortToByte(ValStartTmp(0), LOW_ORDER)
                    End If
                End If

                'se finisco dispari, leggo l'ultima memo
                If bEndDispari Then
                    Dim ValEndTmp(0) As Short
                    nReturn = Cndex.ReadVarWord_C(_UserSession, MemType, 0, MemIndex + ValueTmp.Length - 1, ValEndTmp.Length, ValEndTmp, _ErrClass, _ErrNum)
                    If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("ReadVarWord_C({0},{1},{2}) O_RW_Byte CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                        Throw New CmsNcException(szReturn)
                        Return False
                    Else
                        cEnd = ShortToByte(ValEndTmp(0), HIGH_ORDER)
                    End If
                End If

                For i = 0 To ValueTmp.Length - 1
                    Dim cLow, cHigh As Byte
                    'Low
                    If i = 0 AndAlso bStartHigh Then
                        cLow = cStart
                    Else
                        cLow = Value(i * 2 - MemOrderStart)
                    End If
                    'High
                    If i = (ValueTmp.Length - 1) AndAlso bEndDispari Then
                        cHigh = cEnd
                    Else
                        cHigh = Value(i * 2 + 1 - MemOrderStart)
                    End If

                    ValueTmp(i) = ByteToShort(cLow, cHigh)
                Next

                nReturn = Cndex.WriteVarWord_C(_UserSession, MemType, 0, MemIndex, Value.Length, ValueTmp, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("WriteVarWord_C({0},{1},{2}) O_RW_DWord CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException(szReturn)
                    Return False
                End If

            Else ' ************* Read
                nReturn = Cndex.ReadVarWord_C(_UserSession, MemType, 0, MemIndex, ValueTmp.Length, ValueTmp, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("ReadVarWord_C({0},{1},{2}) O_RW_Byte CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException(szReturn)
                    Return False
                Else
                    For i = 0 To Value.Length - 1
                        Value(i) = ShortToByte(ValueTmp((i + MemOrderStart) \ 2), (i + MemOrderStart) Mod 2)
                    Next
                End If
            End If

            Return True
        End Function


        ''' <summary>
        ''' Legge o scrive Word da MEMORIE PLC
        ''' </summary>
        ''' <param name="bWrite">Se True SCRIVE, se False LEGGE</param>
        ''' <param name="MemType">Tipo di memoria Osai</param>
        ''' <param name="MemIndex">Indice di memoria</param>
        ''' <param name="Value">Matrice di valori da scrivere su scrittura o letti su lettura</param>
        ''' <returns>True se andata a buon fine</returns>
        Public Overridable Overloads Function O_RW_Word(ByVal bWrite As Boolean, ByVal MemType As MemTypeWord, ByVal MemIndex As Integer, ByRef Value() As UShort) As Boolean
            Dim szReturn As String = ""
            Dim nValue(Value.Length - 1) As Short

            If bWrite Then ' *** Write
                For i = 0 To Value.Length - 1
                    nValue(i) = UnsignedToShort(Value(i))
                Next
                nReturn = Cndex.WriteVarWord_C(_UserSession, MemType, 0, MemIndex, Value.Length, nValue, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("WriteVarWord_C({0},{1},{2}) O_RW_Word CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException(szReturn)
                    Return False
                End If

            Else ' ************* Read
                nReturn = Cndex.ReadVarWord_C(_UserSession, MemType, 0, MemIndex, Value.Length, nValue, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("ReadVarWord_C({0},{1},{2}) O_RW_Word CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException(szReturn)
                    Return False
                End If
                For i = 0 To Value.Length - 1
                    Value(i) = ShortToUnsigned(nValue(i))
                Next
            End If

            Return True
        End Function



        ''' <summary>
        ''' Legge o scrive Short da MEMORIE PLC
        ''' </summary>
        ''' <param name="bWrite">Se True SCRIVE, se False LEGGE</param>
        ''' <param name="MemType">Tipo di memoria Osai</param>
        ''' <param name="MemIndex">Indice di memoria</param>
        ''' <param name="Value">Matrice di valori da scrivere su scrittura o letti su lettura</param>
        ''' <returns>True se andata a buon fine</returns>
        Public Overridable Overloads Function O_RW_Short(ByVal bWrite As Boolean, ByVal MemType As MemTypeWord, ByVal MemIndex As Integer, ByRef Value() As Short) As Boolean
            Dim szReturn As String = ""

            If bWrite Then ' *** Write
                nReturn = Cndex.WriteVarWord_C(_UserSession, MemType, 0, MemIndex, Value.Length, Value, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("WriteVarWord_C({0},{1},{2}) O_RW_Word CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException(szReturn)
                    Return False
                End If

            Else ' ************* Read
                nReturn = Cndex.ReadVarWord_C(_UserSession, MemType, 0, MemIndex, Value.Length, Value, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("ReadVarWord_C({0},{1},{2}) O_RW_Word CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException(szReturn)
                    Return False
                End If
            End If

            Return True
        End Function


        ''' <summary>
        ''' Legge o scrive DWord da MEMORIE PLC
        ''' </summary>
        ''' <param name="bWrite">Se True SCRIVE, se False LEGGE</param>
        ''' <param name="MemType">Tipo di memoria Osai</param>
        ''' <param name="MemIndex">Indice di memoria</param>
        ''' <param name="Value">Matrice di valori da scrivere su scrittura o letti su lettura</param>
        ''' <returns>True se andata a buon fine</returns>
        Public Overridable Overloads Function O_RW_DWord(ByVal bWrite As Boolean, ByVal MemType As MemTypeWord, ByVal MemIndex As Integer, ByRef Value() As UInteger) As Boolean
            Dim szReturn As String = ""
            Dim ValueTmp(Value.Length * 2 - 1) As Short

            If bWrite Then ' *** Write
                For i = 0 To Value.Length - 1
                    ValueTmp(i * 2) = DWordToShort(Value(i), LOW_ORDER)
                    ValueTmp(i * 2 + 1) = DWordToShort(Value(i), HIGH_ORDER)
                Next
                nReturn = Cndex.WriteVarWord_C(_UserSession, MemType, 0, MemIndex, ValueTmp.Length, ValueTmp, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("WriteVarWord_C({0},{1},{2}) O_RW_DWord CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException(szReturn)
                    Return False
                End If

            Else ' ************* Read
                nReturn = Cndex.ReadVarWord_C(_UserSession, MemType, 0, MemIndex, ValueTmp.Length, ValueTmp, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("ReadVarWord_C({0},{1},{2}) O_RW_DWord CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException(szReturn)
                    Return False
                Else
                    For i = 0 To Value.Length - 1
                        Value(i) = ShortsToDWord(ValueTmp(i * 2), ValueTmp(i * 2 + 1))
                    Next
                End If
            End If

            Return True
        End Function



        ''' <summary>
        ''' Legge o scrive DWord da MEMORIE PLC
        ''' </summary>
        ''' <param name="bWrite">Se True SCRIVE, se False LEGGE</param>
        ''' <param name="MemType">Tipo di memoria Osai</param>
        ''' <param name="MemIndex">Indice di memoria</param>
        ''' <param name="Value">Matrice di valori da scrivere su scrittura o letti su lettura</param>
        ''' <returns>True se andata a buon fine</returns>
        Public Overridable Overloads Function O_RW_Integer(ByVal bWrite As Boolean, ByVal MemType As MemTypeWord, ByVal MemIndex As Integer, ByRef Value() As Integer) As Boolean
            Dim szReturn As String = ""
            Dim ValueTmp(Value.Length * 2 - 1) As Short

            If bWrite Then ' *** Write
                For i = 0 To Value.Length - 1
                    ValueTmp(i * 2) = IntegerToShort(Value(i), LOW_ORDER)
                    ValueTmp(i * 2 + 1) = IntegerToShort(Value(i), HIGH_ORDER)
                Next
                nReturn = Cndex.WriteVarWord_C(_UserSession, MemType, 0, MemIndex, ValueTmp.Length, ValueTmp, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("WriteVarWord_C({0},{1},{2}) O_RW_DWord CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException(szReturn)
                    Return False
                End If

            Else ' ************* Read
                nReturn = Cndex.ReadVarWord_C(_UserSession, MemType, 0, MemIndex, ValueTmp.Length, ValueTmp, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("ReadVarWord_C({0},{1},{2}) O_RW_DWord CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException(szReturn)
                    Return False
                Else
                    For i = 0 To Value.Length - 1
                        Value(i) = ShortsToInteger(ValueTmp(i * 2), ValueTmp(i * 2 + 1))
                    Next
                End If
            End If

            Return True
        End Function



        ''' <summary>
        ''' Legge o scrive Double da MEMORIE PLC
        ''' </summary>
        ''' <param name="bWrite">Se True SCRIVE, se False LEGGE</param>
        ''' <param name="MemType">Tipo di memoria Osai</param>
        ''' <param name="MemIndex">Indice di memoria</param>
        ''' <param name="Value">Matrice di valori da scrivere su scrittura o letti su lettura</param>
        ''' <returns>True se andata a buon fine</returns>
        Public Overridable Overloads Function O_RW_Double(ByVal bWrite As Boolean, ByVal MemType As MemTypeDouble, ByVal MemIndex As Integer, ByRef Value() As Double) As Boolean
            Dim szReturn As String = ""

            If bWrite Then ' *** Write
                nReturn = Cndex.WriteVarDouble_C(_UserSession, MemType, 0, MemIndex, Value.Length, Value, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("WriteVarDouble_C({0},{1},{2}) O_RW_Double CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException("ERR WriteVarDouble_C O_RW_Double CNC.OSAI")
                    Return False
                End If

            Else ' ************* Read
                nReturn = Cndex.ReadVarDouble_C(_UserSession, MemType, 0, MemIndex, Value.Length, Value, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("ReadVarDouble_C({0},{1},{2}) O_RW_Double CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException("ERR ReadVarDouble_C O_RW_Double CNC.OSAI")
                    Return False
                End If
            End If

            Return True
        End Function

        ''' <summary>
        ''' Legge o scrive Stringhe da MEMORIE SC
        ''' </summary>
        ''' <param name="bWrite">Se True SCRIVE, se False LEGGE</param>
        ''' <param name="MemIndex">Indice di memoria</param>
        ''' <param name="MemLength">Lunghezza caratteri</param>
        ''' <param name="Value">Stringa da scrivere su scrittura o leggere su lettura</param>
        ''' <returns>True se andata a buon fine</returns>
        Public Overridable Overloads Function O_RW_Text(ByVal bWrite As Boolean, ByVal MemType As MemTypeText, ByVal MemIndex As Integer, ByVal MemLength As Integer, ByRef Value As String) As Boolean
            Dim szReturn As String = ""

            If bWrite Then ' *** Write
                nReturn = Cndex.WriteVarText_C(_UserSession, MemType, 1, MemIndex, MemLength, Value, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("WriteVarText_C({0},{1},{2}) O_RW_Text CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException("ERR WriteVarText_C O_RW_Text CNC.OSAI")
                    Return False
                End If

            Else ' ************* Read
                nReturn = Cndex.ReadVarText_C(_UserSession, MemType, 1, MemIndex, MemLength, Value, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, String.Format("ReadVarText_C({0},{1},{2}) O_RW_Text CNC.OSAI", [Enum].GetName(MemType.GetType, MemType), MemIndex, Value), szReturn) Then
                    Throw New CmsNcException("ERR ReadVarText_C O_RW_Text CNC.OSAI")
                    Return False
                End If
            End If

            Return True
        End Function


        ''' <summary>
        ''' Legge o scrive Length and Radius Offset da tabella Utensili CN
        ''' </summary>
        ''' <param name="bWrite">Se True SCRIVE, se False LEGGE</param>
        ''' <param name="ToolOffsetNumber">Numero dell'offset utensile</param>
        Public Overridable Function O_RW_ToolOffset(ByVal bWrite As Boolean, ByVal ToolOffsetNumber As Integer, ByRef CutterRadius_Wear As Double, ByRef CutterRadius_Geometry As Double, ByRef ToolLenght_Wear As Double, ByRef ToolLenght_Geometry As Double) As Boolean
    
        End Function



        ''' <summary>
        ''' Blocca l'accesso alla tabella dei correttori
        ''' </summary>
        ''' <param name="Lock">=True: Blocca la tabella, =False: Sblocca la tabella</param>
        ''' <returns>True se andata a buon fine</returns>
        Public Overridable Function O_LockOffsetTable(ByVal Lock As Boolean) As Boolean

        End Function


        ''' <summary>
        ''' Legge il numero del processo attivo
        ''' </summary>
        ''' <param name="ProcessId">Valore di ritorno del processo selezionato</param>
        ''' <returns>True se andata a buon fine</returns>
        Public Overridable Overloads Function O_GetSelectedProcess(ByRef ProcessId As Short) As Boolean
            Dim szReturn As String = ""

            nReturn = Cndex.GetSelectedProcess_C(_UserSession, ProcessId, _ErrClass, _ErrNum)
            If O_CheckRetError(nReturn, _ErrClass, _ErrNum, "GetSelectedProcess_C O_GetSelectedProcess CNC.OSAI", szReturn) Then
                Throw New CmsNcException("ERR GetSelectedProcess_C O_GetSelectedProcess CNC.OSAI")
                Return False
            End If

            Return True
        End Function

        ''' <summary>
        ''' Legge la riga del programma attivo
        ''' </summary>
        ''' <param name="Line">Riga in esecuzione del programma attivo</param>
        ''' <returns>True se andata a buon fine</returns>
        Public Overridable Overloads Function O_GetActiveLineProgram(ByRef Line As String) As Boolean

            Dim szReturn As String = ""
            Dim ProcessId As Integer
            Dim szLine1 As String = ""
            Dim szLine2 As String = ""
            Dim szLine3 As String = ""
            Dim szLine4 As String = ""
            Dim szLine5 As String = ""
            Dim szLine6 As String = ""
            Dim szLine7 As String = ""
            Dim szLine8 As String = ""

            O_GetSelectedProcess(ProcessId)

            nReturn = Cndex.GetPartProgramLines_C(_UserSession, ProcessId, szLine1, szLine2, szLine3, szLine4, szLine5, szLine6, szLine7, szLine8, _ErrClass, _ErrNum)
            Line = szLine2

            If O_CheckRetError(nReturn, _ErrClass, _ErrNum, "GetPartProgramLines_C O_GetActiveLineProgram CNC.OSAI", szReturn) Then
                Throw New CmsNcException("ERR GetPartProgramLines_C O_GetActiveLineProgram CNC.OSAI")
                Return False
            End If

            Return True
        End Function

        ''' <summary>
        ''' Legge la tabella assi
        ''' </summary>
        ''' <param name="ProcessId">Processo selezionato</param>
        ''' <param name="AxisTable">Valore di ritorno Assi del processo selezionato</param>
        ''' <returns>True se andata a buon fine</returns>
        Public Overridable Function O_GetAxisTab(ByVal ProcessId As Short, ByRef AxisTable() As Char, ByRef AxisIdTable() As Short) As Boolean
            Dim szReturn As String = ""
            Dim sAxisTable As Cndex.AXIS_TABLE
            Dim i, j As Integer

            For i = 1 To 32
                sAxisTable = New Cndex.AXIS_TABLE
                nReturn = Cndex.GetAxisTabRecord_C(_UserSession, i, sAxisTable, _ErrClass, _ErrNum)
                If O_CheckRetError(nReturn, _ErrClass, _ErrNum, "O_GetAxisTab GetAxisTabRecord_C CNC.OSAI", szReturn) Then
                    Throw New CmsNcException("ERR O_GetAxisTab GetAxisTabRecord_C CNC.OSAI")
                    Return False
                End If
                'Codice dell’ambiente proprietario dell’asse
                If (sAxisTable.ax_owner = (&H6000& + (ProcessId * &H100&))) Then
                    'scarto gli assi slave e l'eventuale asse Spindle quando ho un inverter analogico
                    If (sAxisTable.ax_name < Asc("a") Or sAxisTable.ax_name > Asc("z")) And sAxisTable.ax_name <> Asc("S") Then
                        AxisTable(j) = Chr(sAxisTable.ax_name)
                        AxisIdTable(j) = i
                        j += 1
                    End If
                End If
            Next i

            Return True
        End Function


        Public Overridable Function O_CheckRetError(ByVal nReturn As Short, ByVal ErrClass As Long, ByVal ErrNum As Long, ByVal Position As String, Optional ByRef szReturn As String = "") As Boolean
            Dim szErrorClassDesc As String = String.Empty
            Dim szErrorDesc As String = String.Empty

            'Cndex 3.1.2 messages

            ''' aggiornare dal manuale di programmazione 4606R.pdf
            ''' alcune classi di errori sono del cn e non sono specificate nel documento

            If nReturn = 0 Then
                'Seleziono il messaggio
                Select Case ErrClass
                    Case 1
                        szErrorClassDesc = "COM error class"
                        Select Case ErrNum
                            Case &H80080005 : szErrorDesc = "CO_E_SERVER_EXEC_FAILURE"
                            Case &H800706BA : szErrorDesc = "RPC_S_SERVER_UNAVAILABLE"
                            Case &H80070005 : szErrorDesc = "E_ACCESSDENIED"
                            Case &H80040154 : szErrorDesc = "REGDB_E_CLASSNOTREG"
                            Case &H80012 : szErrorDesc = "CO_S_NOTALLINTERFACES"
                        End Select
                        szErrorDesc = "0x" & Hex(ErrNum) & ": " & szErrorDesc

                    Case 2
                        szErrorClassDesc = "SERVER error class"
                        Select Case ErrNum
                            Case 1 : szErrorDesc = "Memory for dynamic allocations insufficient"
                            Case 2 : szErrorDesc = "Impossible to create synchronisation events"
                            Case 3 : szErrorDesc = "Session aborted and no longer usable"
                            Case 4 : szErrorDesc = "Session not open"
                            Case 5 : szErrorDesc = "Impossible to allocate a channel"
                            Case 6 : szErrorDesc = "Function of a non-existing process requested"
                            Case 7 : szErrorDesc = "Broadcasting command aborted"
                            Case 8 : szErrorDesc = "Buffer supplied by function in which the data supplied by the NC are copied is too small"
                            Case 9 : szErrorDesc = "Session already open"
                            Case 10 : szErrorDesc = "Broadcasting list invalid"
                            Case 11 : szErrorDesc = "Realtime command aborted"
                            Case 12 : szErrorDesc = "Function already active"
                            Case 13 : szErrorDesc = "Function not yet active"
                            Case 14 : szErrorDesc = "Reception thread ended"
                            Case 15 : szErrorDesc = "No reply to command received within allotted time"
                            Case 16 : szErrorDesc = "NC release to which you are connected is not compatible with communications with server"
                            Case 17 : szErrorDesc = "Cookie does not identify any communication session"
                            Case 18 : szErrorDesc = "Realtime thread cannot be created"
                            Case 19 : szErrorDesc = "No more sections available"
                            Case 20 : szErrorDesc = "Error in symbol acquisition"
                            Case 23 : szErrorDesc = "Internal object instance cannot be created"
                            Case 24 : szErrorDesc = "Broadcasting thread cannot be created"
                            Case 25 : szErrorDesc = "Function cannot be executed in the numerical control boot phase"
                            Case 26 : szErrorDesc = "Parameter wrong"
                            Case 27 : szErrorDesc = "Invalid buffer"
                            Case 29 : szErrorDesc = "Session identifier (UserSession) is invalid (session closed or never opened)"
                            Case 31 : szErrorDesc = "Session identifier is invalid (value out of range) or session has been closed automatically by Cndex server"
                        End Select
                        szErrorDesc = ErrNum.ToString & ": " & szErrorDesc

                    Case 3
                        szErrorClassDesc = "NETBIOS error class"
                        Select Case ErrNum
                            Case &H1 : szErrorDesc = "Illegal buffer length"
                            Case &H3 : szErrorDesc = "Illegal command"
                            Case &H5 : szErrorDesc = "Command timed out"
                            Case &H6 : szErrorDesc = "Message incomplete, issue another command"
                            Case &H7 : szErrorDesc = "Illegal buffer address"
                            Case &H8 : szErrorDesc = "Session number out of range"
                            Case &H9 : szErrorDesc = "No resource available"
                            Case &HA : szErrorDesc = "Session closed"
                            Case &HB : szErrorDesc = "Command cancelled"
                            Case &HD : szErrorDesc = "Duplicate name"
                            Case &HE : szErrorDesc = "Name table full"
                            Case &HF : szErrorDesc = "No deletions, name has active sessions"
                            Case &H11 : szErrorDesc = "Local session table full"
                            Case &H12 : szErrorDesc = "Remote session table full"
                            Case &H13 : szErrorDesc = "Illegal name number"
                            Case &H14 : szErrorDesc = "No callname"
                            Case &H15 : szErrorDesc = "Cannot put * in NCB_NAME"
                            Case &H16 : szErrorDesc = "Name in use on remote adapter"
                            Case &H17 : szErrorDesc = "Name deleted"
                            Case &H18 : szErrorDesc = "Session ended abnormally"
                            Case &H19 : szErrorDesc = "Name conflict detected"
                            Case &H21 : szErrorDesc = "Interface busy, IRET before retrying"
                            Case &H22 : szErrorDesc = "Too many commands outstanding, retry later"
                            Case &H23 : szErrorDesc = "Ncb_lana_num field invalid"
                            Case &H24 : szErrorDesc = "Command completed while cancel occurring"
                            Case &H26 : szErrorDesc = "Command not valid to cancel"
                            Case &H30 : szErrorDesc = "Name defined by another local process"
                            Case &H34 : szErrorDesc = "Environment undefined. RESET required"
                            Case &H35 : szErrorDesc = "Required OS resources exhausted"
                            Case &H36 : szErrorDesc = "Max number of applications exceeded"
                            Case &H37 : szErrorDesc = "No saps available for netbios"
                            Case &H38 : szErrorDesc = "Requested resources are not available"
                            Case &H39 : szErrorDesc = "Invalid ncb address or length > segment"
                            Case &H3B : szErrorDesc = "Invalid NCB DDID"
                            Case &H3C : szErrorDesc = "Lock of user area failed"
                            Case &H3F : szErrorDesc = "NETBIOS not loaded"
                            Case &H40 : szErrorDesc = "System error"
                        End Select
                        szErrorDesc = "0x" & Hex(ErrNum) & ": " & szErrorDesc

                    Case 4
                        szErrorClassDesc = "CNC error class"
                        Select Case ErrNum
                            'Error codes for Real Time functions
                            Case &H101 : szErrorDesc = "Command unknown"
                            Case &H102 : szErrorDesc = "No channel available"
                            Case &H103 : szErrorDesc = "Tick requested not multiple of system tick"
                            Case &H104 : szErrorDesc = "Id channel wrong"
                            Case &H105 : szErrorDesc = "Data acquisition still underway"
                            Case &H106 : szErrorDesc = "Channel not configured"
                            Case &H107 : szErrorDesc = "Error on stop trigger"
                            Case &H108 : szErrorDesc = "Channel already configured for other types of data"
                                'Error codes for Dry Run functions
                            Case &H200 : szErrorDesc = "Process not configured"
                            Case &H201 : szErrorDesc = "Axis not present in process"
                            Case &H202 : szErrorDesc = "Dry run not configured"
                            Case &H203 : szErrorDesc = "Dry run already being executed"
                            Case &H204 : szErrorDesc = "Dry run already in stop status"
                        End Select
                        szErrorDesc = "0x" & Hex(ErrNum) & ": " & szErrorDesc

                    Case 10
                        szErrorClassDesc = "DLL_INTERFACE error class"
                        Select Case ErrNum
                            Case 1 : szErrorDesc = "The server has been created more than once"
                            Case 2 : szErrorDesc = "An error has occurred during the creation of the Cndex server"
                            Case 3 : szErrorDesc = "A function has been called without having created the Cndex server"
                            Case 4 : szErrorDesc = "One or more function input parameters are not valid"
                            Case 5 : szErrorDesc = "Option A06 -CndexLink communication- for network communications with external applications is not enabled on the CNC you are trying to connect to"
                        End Select
                        szErrorDesc = ErrNum.ToString & ": " & szErrorDesc

                    Case Else
                        szErrorDesc = ErrNum.ToString
                End Select
                szErrorClassDesc = ErrClass.ToString & ": " & szErrorClassDesc

                'Stampo il messaggio
                szReturn = "ERR  " & szErrorClassDesc & "  " & szErrorDesc & " - Occurred in: " & Position
                Return True 'presenza errore
            End If

            szReturn = ""
            Return False 'assenza errori
        End Function


    End Class

End Namespace
