' !! We strongly recommend that you read the "readme.txt" file in the sample code folder.
' !! It contains important instructions on how to use the sample code

Imports System.Runtime.InteropServices

Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents Label1 As System.Windows.Forms.Label
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.Label1 = New System.Windows.Forms.Label()
        Me.SuspendLayout()
        '
        'Label1
        '
        Me.Label1.Font = New System.Drawing.Font("Microsoft Sans Serif", 24.0!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
        Me.Label1.Location = New System.Drawing.Point(72, 80)
        Me.Label1.Name = "Label1"
        Me.Label1.Size = New System.Drawing.Size(168, 40)
        Me.Label1.TabIndex = 0
        Me.Label1.Text = "It Worked!"
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(304, 213)
        Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.Label1})
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub

#End Region

    ' The sample code contains 11 functions. You will not need to use all these
    ' functions in your code. Just use which ever functions are most appropriate
    ' and customise in your own way. The sample code is just a guide. You should
    ' implement the protection in a stronger way using the techniques described in
    ' the "Increasing your Protection" chapter of the manual.
    '
    ' The 11 functions are:
    ' ProtCheck                         a standard protection check
    ' ProtCheckWithAlg                  a protection check & executing an Algorithm
    ' WriteBytes                        a protection check & write data to the dongle
    ' ReadBytes                         a protection check & read data from the dongle
    ' EncryptUserData                   a protection check,& encrypting data and then decrypting the data
    '
    ' these functions are the same as the functions listed above but encrypting all parameters passed to our API
    ' ProtCheckEnc                      a standard protection check
    ' ProtCheckWithAlgEnc               a protection check & executing an Algorithm
    ' WriteBytesEnc                     a protection check & write data to the dongle
    ' ReadBytesEnc                      a protection check & read data from the dongle
    ' EncryptUserDataEnc                a protection check & encrypting data and then decrypting the data

	' this function displays the current network users
	' DisplayNetUsers

    ' !!!!
    Public Const MY_SDSN As Integer = 10101                 ' !!!! change this value to be the value of your SDSN (demo = 10101)
    Public Const MY_PRODCODE As String = "DEMO"             ' !!!! change this value to match the Product Code in the dongle

	' If you are using Dinkey Lite then you can only use 4 functions:
	' ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc
	
    Private Sub Form1_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load

        ' call the function(s) of your choice here
        ' here I have chosen a standard protection check
        If ProtCheck() <> 0 Then
            End             'terminate
        End If

    End Sub

    ' *************************  our 10 functions **********************************

    ' **************************  ProtCheck  ***************************************
    Function ProtCheck() As Integer
        Dim dris As DRIS = New DRIS
        Dim ret_code As Integer
        On Error GoTo Protection_Err

        ' set the DRIS to have random values
        Call RandomSet(dris)
        ' then set the values we want to use
        dris.header1 = Asc("D")
        dris.header2 = Asc("R")
        dris.header3 = Asc("I")
        dris.header4 = Asc("S")
        dris.size = Marshal.SizeOf(dris)
        dris.myfunction = PROTECTION_CHECK          ' standard protection check
        dris.flags = 0                              ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...

        ret_code = DDProtCheck(dris, Nothing)

        If (ret_code <> 0) Then
            Call DisplayError(ret_code, dris.ext_err)
            ProtCheck = ret_code
            Exit Function
        End If

        ' later in your code you can check other values in the DRIS...
        If (dris.sdsn <> MY_SDSN) Then
            MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error")
            ProtCheck = -1
            Exit Function
        End If

        If (GetProductCode(dris) <> MY_PRODCODE) Then
            MsgBox("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", MsgBoxStyle.OkOnly, "Error")
            ProtCheck = -1
            Exit Function
        End If
		
        ' later on in your program you can check the return code again
        If (dris.ret_code <> 0) Then
            MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error")
            ProtCheck = -1
            Exit Function
        End If


		' NB if you are using a network dongle and you want to list the network users then use this function:
        ' DisplayNetUsers(dris.net_users, dris.model)
		
        ProtCheck = 0
        Exit Function

Protection_Err:  ' see readme.txt for explanation of this exception handler
        Protection_Exception()
        ProtCheck = -1
    End Function


    ' **************************  ProtCheckWithAlg  ******************************

    ' !!!! You should replace this function with the one generated by the 
    ' "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm)
    ' or from DinkeyLook if you are using Dinkey Lite dongles. 
    ' see readme.txt notes concerning using the algorithm in vb.net
    Private Function MyAlgorithm(ByVal a As Integer, ByVal b As Integer, ByVal c As Integer, ByVal d As Integer, ByVal e As Integer, ByVal f As Integer, ByVal g As Integer, ByVal h As Integer) As Integer
        MyAlgorithm = a + b + c + d + e + f + g + h
    End Function

    ' NB for this to work you must program at least "user algorithm" into the dongle
    ' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the
    ' sample code generated by DinkeyAdd for the algorithm that you are using. 
    Function ProtCheckWithAlg() As Integer
        Dim dris As DRIS = New DRIS
        Dim ret_code As Integer
        On Error GoTo Protection_Err

        ' set the DRIS to have random values
        Call RandomSet(dris)
        ' then set the values we want to use
        dris.header1 = Asc("D")
        dris.header2 = Asc("R")
        dris.header3 = Asc("I")
        dris.header4 = Asc("S")
        dris.size = Marshal.SizeOf(dris)
        dris.myfunction = EXECUTE_ALGORITHM         ' standard protection check & execute algorithm
        dris.flags = 0                              ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
        dris.alg_number = 1                         ' execute first algorithm (you do not need to specify this field for Dinkey Lite dongles)
        ' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random
        dris.var_a = 1                              ' sample values
        dris.var_b = 2
        dris.var_c = 3
        dris.var_d = 4
        dris.var_e = 5
        dris.var_f = 6
        dris.var_g = 7
        dris.var_h = 8

        ret_code = DDProtCheck(dris, Nothing)

        If (ret_code <> 0) Then
            Call DisplayError(ret_code, dris.ext_err)
            ProtCheckWithAlg = ret_code
            Exit Function
        End If

        ' later in your code you can check other values in the DRIS...
        If (dris.sdsn <> MY_SDSN) Then
            MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error")
            ProtCheckWithAlg = -1
            Exit Function
        End If

        ' later on in your program you can check the return code again
        If (dris.ret_code <> 0) Then
            MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error")
            ProtCheckWithAlg = -1
            Exit Function
        End If

        ' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code
        ' NB read the note in the "readme.txt" about possible overflow errors in VB.NET
        ' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd
        If (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) Then
            MsgBox("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", MsgBoxStyle.OkOnly, "Error")
            ProtCheckWithAlg = -1
            Exit Function
        End If

        ProtCheckWithAlg = 0
        Exit Function
Protection_Err:  ' see readme.txt for explanation of this exception handler
        Protection_Exception()
        ProtCheckWithAlg = -1
    End Function

    ' **************************  WriteBytes  ******************************
    ' This writes the data array 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7
    ' In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long.
    ' if you want to write a string then you need to convert it to a byte array first:  
    ' encoding.GetBytes(your_string, 0, your_string.Length, data, 0)    where encoding is declared: Dim encoding As New ASCIIEncoding()  You also need to include System.Text
    Function WriteBytes() As Integer
        Dim dris As DRIS = New DRIS
        Dim ret_code As Integer
        Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
        On Error GoTo Protection_Err

        ' set the DRIS to have random values
        Call RandomSet(dris)
        ' then set the values we want to use
        dris.header1 = Asc("D")
        dris.header2 = Asc("R")
        dris.header3 = Asc("I")
        dris.header4 = Asc("S")
        dris.size = Marshal.SizeOf(dris)
        dris.myfunction = WRITE_DATA_AREA           ' standard protection check & write data
        dris.flags = USE_FUNCTION_ARGUMENT          ' you have to do it this way in vb.net
        dris.rw_offset = 7
        dris.rw_length = data.Length

        ret_code = DDProtCheck(dris, data)

        If (ret_code <> 0) Then
            Call DisplayError(ret_code, dris.ext_err)
            WriteBytes = ret_code
            Exit Function
        End If

        ' later in your code you can check other values in the DRIS...
        If (dris.sdsn <> MY_SDSN) Then
            MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error")
            WriteBytes = -1
            Exit Function
        End If

        ' later on in your program you can check the return code again
        If (dris.ret_code <> 0) Then
            MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error")
            WriteBytes = -1
            Exit Function
        End If

        WriteBytes = 0
        Exit Function
Protection_Err:  ' see readme.txt for explanation of this exception handler
        Protection_Exception()
        WriteBytes = -1
    End Function

    ' ************************  ReadBytes  ************************************
    ' This reads 10 bytes of data from offset 7 in the dongle data area
    ' In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long.
    '   if you want to read a string then you need to convert it from a byte array (via an array of char). You also need to include System.Text 
    '   CharArray = encoding.GetChars(data);			where CharArray is of type char[] and encoding is of type ASCIIEncoding
    '   your_string = new String(CharArray, 0, your_string_length);
    Function ReadBytes() As Integer
        Dim dris As DRIS = New DRIS
        Dim ret_code As Integer
        Dim data(10) As Byte
        On Error GoTo Protection_Err

        ' set the DRIS to have random values
        Call RandomSet(dris)
        ' then set the values we want to use
        dris.header1 = Asc("D")
        dris.header2 = Asc("R")
        dris.header3 = Asc("I")
        dris.header4 = Asc("S")
        dris.size = Marshal.SizeOf(dris)
        dris.myfunction = READ_DATA_AREA            ' standard protection check & read data
        dris.flags = USE_FUNCTION_ARGUMENT          ' you have to do it this way in vb.net
        dris.rw_offset = 7
        dris.rw_length = data.Length

        ret_code = DDProtCheck(dris, data)

        If (ret_code <> 0) Then
            Call DisplayError(ret_code, dris.ext_err)
            ReadBytes = ret_code
            Exit Function
        End If

        ' later in your code you can check other values in the DRIS...
        If (dris.sdsn <> MY_SDSN) Then
            MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error")
            ReadBytes = -1
            Exit Function
        End If

        ' later on in your program you can check the return code again
        If (dris.ret_code <> 0) Then
            MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error")
            ReadBytes = -1
            Exit Function
        End If

        MsgBox("Dinkey Dongle Data Area, offset 7 is : " + Str(data(0)) + "," + Str(data(1)) + "," + Str(data(2)) + "," + Str(data(3)) + "," + _
            Str(data(4)) + "," + Str(data(5)) + "," + Str(data(6)) + "," + Str(data(7)) + "," + Str(data(8)) + "," + Str(data(9)), MsgBoxStyle.OkOnly)
        ReadBytes = 0
        Exit Function
Protection_Err:  ' see readme.txt for explanation of this exception handler
        Protection_Exception()
        ReadBytes = -1
    End Function

    ' **************************  EncryptUserData  ************************************
    ' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1
    ' It will then do another protection check & decrypt the data
    ' to encrypt or decrypt strings please read notes for WriteBytes and ReadBytes functions
    Function EncryptUserData() As Integer
        Dim dris As DRIS = New DRIS
        Dim ret_code As Integer
        Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
        On Error GoTo Protection_Err

        ' set the DRIS to have random values
        Call RandomSet(dris)
        ' then set the values we want to use
        dris.header1 = Asc("D")
        dris.header2 = Asc("R")
        dris.header3 = Asc("I")
        dris.header4 = Asc("S")
        dris.size = Marshal.SizeOf(dris)
        dris.myfunction = ENCRYPT_USER_DATA         ' standard protection check & encrypt data
        dris.flags = USE_FUNCTION_ARGUMENT          ' you have to do it this way in vb.net
        dris.rw_length = data.Length
        dris.data_crypt_key_num = 1

        ret_code = DDProtCheck(dris, data)

        If (ret_code <> 0) Then
            Call DisplayError(ret_code, dris.ext_err)
            EncryptUserData = ret_code
            Exit Function
        End If

        ' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ...

        ' Now decrypt the same data to get the original values
        Call RandomSet(dris)
        ' then set the values we want to use
        dris.header1 = Asc("D")
        dris.header2 = Asc("R")
        dris.header3 = Asc("I")
        dris.header4 = Asc("S")
        dris.size = Marshal.SizeOf(dris)
        dris.myfunction = DECRYPT_USER_DATA         ' standard protection check & decrypt data
        dris.flags = USE_FUNCTION_ARGUMENT          ' you have to do it this way in vb.net
        dris.rw_length = data.Length
        dris.data_crypt_key_num = 1

        ret_code = DDProtCheck(dris, data)

        If (ret_code <> 0) Then
            Call DisplayError(ret_code, dris.ext_err)
            EncryptUserData = ret_code
            Exit Function
        End If

        ' later in your code you can check other values in the DRIS...
        If (dris.sdsn <> MY_SDSN) Then
            MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error")
            EncryptUserData = -1
            Exit Function
        End If

        ' later on in your program you can check the return code again
        If (dris.ret_code <> 0) Then
            MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error")
            EncryptUserData = -1
            Exit Function
        End If

        MsgBox("Decrypted data is : " + Str(data(0)) + "," + Str(data(1)) + "," + Str(data(2)) + "," + Str(data(3)) + "," + _
            Str(data(4)) + "," + Str(data(5)) + "," + Str(data(6)) + "," + Str(data(7)) + "," + Str(data(8)) + "," + Str(data(9)), MsgBoxStyle.OkOnly)
        EncryptUserData = 0
        Exit Function
Protection_Err:  ' see readme.txt for explanation of this exception handler
        Protection_Exception()
        EncryptUserData = -1
    End Function

    ' !!!!!!!!!!!   all the functions listed below encrypt all parameters to our API  !!!!!!!!!!!!!!!!!!!!!
    ' In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API"
    ' in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm
    ' but the code can be modified easily to use the 3 encryption parameters.

    ' !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm
    Private Function MyRWAlgorithm(ByVal a As Integer, ByVal b As Integer, ByVal c As Integer, ByVal d As Integer, ByVal e As Integer, ByVal f As Integer, ByVal g As Integer, ByVal h As Integer) As Integer
        MyRWAlgorithm = a Xor b Xor c Xor d Xor e Xor f
        MyRWAlgorithm = MyRWAlgorithm And &HFFFFFF      ' we only use bottom 3 bytes. -ve numbers can cause problems for CryptApiData
    End Function

    ' !!!! please overwrite this function with the one generated by DinkeyAdd
    Private Sub CryptDRIS(ByRef dris As DRIS)
        Dim i, j, k, t As Integer
        Dim bigseed(255) As Byte
        Dim S(255) As Byte
        Dim temp As Byte
        Dim temp_dris(Marshal.SizeOf(dris) - 1) As Byte

        DrisToByteArray(dris, temp_dris)  ' convert DRIS to byte array so we can encrypt it

        For i = 0 To 255 Step 8
            Call Set4Bytes(bigseed, i, dris.seed1)
            Call Set4Bytes(bigseed, i + 4, dris.seed2)
        Next
        For i = 0 To 255
            S(i) = i
        Next
        j = 0
        For i = 0 To 255
            j = (j + CInt(S(i)) + CInt(bigseed(i)) + 123) Mod 256
            temp = S(i)
            S(i) = S(j)
            S(j) = temp
        Next
        i = 0
        j = 0
        For k = 16 To Marshal.SizeOf(dris) - 1
            i = (i + 1) Mod 256
            j = (j + CInt(S(i)) + 212) Mod 256
            temp = S(i)
            S(i) = S(j)
            S(j) = temp
            t = (CInt(S(i)) + CInt(S(j)) + 97) Mod 256
            temp_dris(k) = temp_dris(k) Xor S(t)
        Next

        ByteArrayToDris(temp_dris, dris)                ' convert it back again
    End Sub


    ' !!!! please overwrite this function with the one generated by DinkeyAdd
    Private Sub CryptApiData(ByVal dris As DRIS, ByVal data() As Byte, ByVal length As Integer, ByVal alg_answer As Integer)
        Dim i, j, k, t As Integer
        Dim bigseed(255) As Byte
        Dim S(255) As Byte
        Dim temp As Byte

        For i = 0 To 255 Step 8
            Call Set4Bytes(bigseed, i, dris.seed1)
            Call Set4Bytes(bigseed, i + 4, dris.seed2)
        Next
        For i = 0 To 255
            S(i) = i
        Next
        j = 0
        For i = 0 To 255
            j = (j + CInt(S(i)) + CInt(bigseed(i)) + (alg_answer And &HFF)) Mod 256
            temp = S(i)
            S(i) = S(j)
            S(j) = temp
        Next
        i = 0
        j = 0
        For k = 0 To length - 1
            i = (i + 1) Mod 256
            j = (j + CInt(S(i)) + ((alg_answer \ &H100) And &HFF)) Mod 256
            temp = S(i)
            S(i) = S(j)
            S(j) = temp
            t = (CInt(S(i)) + CInt(S(j)) + ((alg_answer \ &H10000) And &HFF)) Mod 256
            data(k) = data(k) Xor S(t)
        Next
    End Sub

    ' **************************  ProtCheckEnc  ************************************
    ' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd.
    Function ProtCheckEnc() As Integer
        Dim dris As DRIS = New DRIS
        Dim ret_code As Integer
        On Error GoTo Protection_Err

        ' set the DRIS to have random values
        Call RandomSet(dris)
        ' then set the values we want to use
        dris.header1 = Asc("D")
        dris.header2 = Asc("R")
        dris.header3 = Asc("I")
        dris.header4 = Asc("S")
        dris.size = Marshal.SizeOf(dris)
        dris.myfunction = PROTECTION_CHECK          ' standard protection check
        dris.flags = 0                              ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...

        Call CryptDRIS(dris)                          ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)

        ret_code = DDProtCheck(dris, Nothing)

        Call CryptDRIS(dris)                          ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)

        If (ret_code <> 0) Then
            Call DisplayError(ret_code, dris.ext_err)
            ProtCheckEnc = ret_code
            Exit Function
        End If

        ' later in your code you can check other values in the DRIS...
        If (dris.sdsn <> MY_SDSN) Then
            MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error")
            ProtCheckEnc = -1
            Exit Function
        End If

        If (GetProductCode(dris) <> MY_PRODCODE) Then
            MsgBox("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", MsgBoxStyle.OkOnly, "Error")
            ProtCheckEnc = -1
            Exit Function
        End If

        ' later on in your program you can check the return code again
        If (dris.ret_code <> 0) Then
            MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error")
            ProtCheckEnc = -1
            Exit Function
        End If

        ProtCheckEnc = 0
        Exit Function

Protection_Err:  ' see readme.txt for explanation of this exception handler
        Protection_Exception()
        ProtCheckEnc = -1
    End Function


    ' **************************  ProtCheckWithAlgEnc  ****************************
    ' NB for this to work you must program at least "user algorithm" into the dongle
    ' NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the
    ' sample code generated by DinkeyAdd for the algorithm that you are using. For Dinkey Lite get source from DinkeyLook.
    ' We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd.
    Function ProtCheckWithAlgEnc() As Integer
        Dim dris As DRIS = New DRIS
        Dim ret_code As Integer
        On Error GoTo Protection_Err

        ' set the DRIS to have random values
        Call RandomSet(dris)
        ' then set the values we want to use
        dris.header1 = Asc("D")
        dris.header2 = Asc("R")
        dris.header3 = Asc("I")
        dris.header4 = Asc("S")
        dris.size = Marshal.SizeOf(dris)
        dris.myfunction = EXECUTE_ALGORITHM         ' standard protection check & execute algorithm
        dris.flags = 0                              ' no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
        dris.alg_number = 1                       ' execute first algorithm (you do not need to specify this field for Dinkey Lite dongles)
        ' you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random
        dris.var_a = 1                              ' sample values
        dris.var_b = 2
        dris.var_c = 3
        dris.var_d = 4
        dris.var_e = 5
        dris.var_f = 6
        dris.var_g = 7
        dris.var_h = 8

        Call CryptDRIS(dris)                          ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)

        ret_code = DDProtCheck(dris, Nothing)

        Call CryptDRIS(dris)                          ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)

        If (ret_code <> 0) Then
            Call DisplayError(ret_code, dris.ext_err)
            ProtCheckWithAlgEnc = ret_code
            Exit Function
        End If

        ' later in your code you can check other values in the DRIS...
        If (dris.sdsn <> MY_SDSN) Then
            MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error")
            ProtCheckWithAlgEnc = -1
            Exit Function
        End If

        ' later on in your program you can check the return code again
        If (dris.ret_code <> 0) Then
            MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error")
            ProtCheckWithAlgEnc = -1
            Exit Function
        End If

        ' if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code
        ' !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd
        If (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) <> dris.alg_answer) Then
            MsgBox("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", MsgBoxStyle.OkOnly, "Error")
            ProtCheckWithAlgEnc = -1
            Exit Function
        End If

        ProtCheckWithAlgEnc = 0
        Exit Function
Protection_Err:  ' see readme.txt for explanation of this exception handler
        Protection_Exception()
        ProtCheckWithAlgEnc = -1
    End Function

    ' **************************  WriteBytesEnc  ******************************
    ' This writes the data array 0,1,2,3,4,5,6,7,8,9 to the dongle data area at offset 7
    ' In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long.
    ' We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.
    ' to write string data please read notes for WriteBytes
    Function WriteBytesEnc() As Integer
        Dim dris As DRIS = New DRIS
        Dim ret_code, alg_ans As Integer
        Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
        On Error GoTo Protection_Err

        ' set the DRIS to have random values
        Call RandomSet(dris)                        ' sets DRIS to have random values including seed1, seed2 and var_a..var_h
        ' then set the values we want to use
        dris.header1 = Asc("D")
        dris.header2 = Asc("R")
        dris.header3 = Asc("I")
        dris.header4 = Asc("S")
        dris.size = Marshal.SizeOf(dris)
        dris.myfunction = WRITE_DATA_AREA           ' standard protection check & write data
        dris.flags = USE_FUNCTION_ARGUMENT          ' you have to do it this way in vb.net
        dris.rw_offset = 7
        dris.rw_length = data.Length
        dris.var_a = dris.var_a And &HFFFFFF        ' restrict to 24-bit to prevent potential overflow in algorithm
        dris.var_b = dris.var_b And &HFFFFFF
        dris.var_c = dris.var_c And &HFFFFFF
        dris.var_d = dris.var_d And &HFFFFFF
        dris.var_e = dris.var_e And &HFFFFFF
        dris.var_f = dris.var_f And &HFFFFFF
        dris.var_g = dris.var_g And &HFFFFFF
        dris.var_h = dris.var_h And &HFFFFFF

        ' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
        alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h)

        ' encrypt data we want to write.
        CryptApiData(dris, data, data.Length, alg_ans)

        Call CryptDRIS(dris)                          ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)

        ret_code = DDProtCheck(dris, data)

        Call CryptDRIS(dris)                          ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)

        If (ret_code <> 0) Then
            Call DisplayError(ret_code, dris.ext_err)
            WriteBytesEnc = ret_code
            Exit Function
        End If

        ' later in your code you can check other values in the DRIS...
        If (dris.sdsn <> MY_SDSN) Then
            MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error")
            WriteBytesEnc = -1
            Exit Function
        End If

        ' later on in your program you can check the return code again
        If (dris.ret_code <> 0) Then
            MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error")
            WriteBytesEnc = -1
            Exit Function
        End If

        WriteBytesEnc = 0
        Exit Function
Protection_Err:  ' see readme.txt for explanation of this exception handler
        Protection_Exception()
        WriteBytesEnc = -1
    End Function

    ' ************************  ReadBytesEnc  ************************************
    ' This reads 10 bytes of data from offset 7 in the dongle data area
    ' In order for this function to work you will need to have a data area in your dongle that is at least 18 bytes long.
    ' We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.
    ' to read string data please notes for ReadBytes function
    Function ReadBytesEnc() As Integer
        Dim dris As DRIS = New DRIS
        Dim ret_code, alg_ans As Integer
        Dim data(10) As Byte
        On Error GoTo Protection_Err

        ' set the DRIS to have random values
        Call RandomSet(dris)                        ' sets DRIS to have random values including seed1, seed2 and var_a..var_h
        ' then set the values we want to use
        dris.header1 = Asc("D")
        dris.header2 = Asc("R")
        dris.header3 = Asc("I")
        dris.header4 = Asc("S")
        dris.size = Marshal.SizeOf(dris)
        dris.myfunction = READ_DATA_AREA            ' standard protection check & read data
        dris.flags = USE_FUNCTION_ARGUMENT          ' you have to do it this way in vb.net
        dris.rw_offset = 7
        dris.rw_length = data.Length
        dris.var_a = dris.var_a And &HFFFFFF        ' restrict to 24-bit to prevent potential overflow in algorithm
        dris.var_b = dris.var_b And &HFFFFFF
        dris.var_c = dris.var_c And &HFFFFFF
        dris.var_d = dris.var_d And &HFFFFFF
        dris.var_e = dris.var_e And &HFFFFFF
        dris.var_f = dris.var_f And &HFFFFFF
        dris.var_g = dris.var_g And &HFFFFFF
        dris.var_h = dris.var_h And &HFFFFFF

        ' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
        alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h)

        Call CryptDRIS(dris)                          ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)

        ret_code = DDProtCheck(dris, data)

        Call CryptDRIS(dris)                          ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)

        If (ret_code <> 0) Then
            Call DisplayError(ret_code, dris.ext_err)
            ReadBytesEnc = ret_code
            Exit Function
        End If

        ' later in your code you can check other values in the DRIS...
        If (dris.sdsn <> MY_SDSN) Then
            MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error")
            ReadBytesEnc = -1
            Exit Function
        End If

        ' later on in your program you can check the return code again
        If (dris.ret_code <> 0) Then
            MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error")
            ReadBytesEnc = -1
            Exit Function
        End If

        ' decrypt data just read.
        CryptApiData(dris, data, data.Length, alg_ans)
        MsgBox("Dinkey Dongle Data Area, offset 7 is : " + Str(data(0)) + "," + Str(data(1)) + "," + Str(data(2)) + "," + Str(data(3)) + "," + _
            Str(data(4)) + "," + Str(data(5)) + "," + Str(data(6)) + "," + Str(data(7)) + "," + Str(data(8)) + "," + Str(data(9)), MsgBoxStyle.OkOnly)
        ReadBytesEnc = 0
        Exit Function
Protection_Err:  ' see readme.txt for explanation of this exception handler
        Protection_Exception()
        ReadBytesEnc = -1
    End Function

    ' **************************  EncryptUserDataEnc  *********************************
    ' This function will do a protection check and ask the dongle to encrypt some data using encryption key 1
    ' It will then do another protection check & decrypt the data
    ' We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.
    ' to encrypt or decrypt strings please read notes for WriteBytes and ReadBytes functions
    Function EncryptUserDataEnc() As Integer
        Dim dris As DRIS = New DRIS
        Dim ret_code, alg_ans As Integer
        Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
        On Error GoTo Protection_Err

        ' set the DRIS to have random values
        Call RandomSet(dris)                        ' sets DRIS to have random values including seed1, seed2 and var_a..var_h
        ' then set the values we want to use
        dris.header1 = Asc("D")
        dris.header2 = Asc("R")
        dris.header3 = Asc("I")
        dris.header4 = Asc("S")
        dris.size = Marshal.SizeOf(dris)
        dris.myfunction = ENCRYPT_USER_DATA         ' standard protection check & encrypt data
        dris.flags = USE_FUNCTION_ARGUMENT          ' you have to do it this way in vb.net
        dris.rw_length = data.Length
        dris.data_crypt_key_num = 1
        dris.var_a = dris.var_a And &HFFFFFF        ' restrict to 24-bit to prevent potential overflow in algorithm
        dris.var_b = dris.var_b And &HFFFFFF
        dris.var_c = dris.var_c And &HFFFFFF
        dris.var_d = dris.var_d And &HFFFFFF
        dris.var_e = dris.var_e And &HFFFFFF
        dris.var_f = dris.var_f And &HFFFFFF
        dris.var_g = dris.var_g And &HFFFFFF
        dris.var_h = dris.var_h And &HFFFFFF

        ' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
        alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h)

        ' encrypt data we pass to our API
        CryptApiData(dris, data, data.Length, alg_ans)

        Call CryptDRIS(dris)                          ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)

        ret_code = DDProtCheck(dris, data)

        Call CryptDRIS(dris)                          ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)

        If (ret_code <> 0) Then
            Call DisplayError(ret_code, dris.ext_err)
            EncryptUserDataEnc = ret_code
            Exit Function
        End If

        ' ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ...

        ' Now decrypt the same data to get the original values
        Call RandomSet(dris)                        ' sets DRIS to have random values including seed1, seed2 and var_a..var_h
        ' then set the values we want to use
        dris.header1 = Asc("D")
        dris.header2 = Asc("R")
        dris.header3 = Asc("I")
        dris.header4 = Asc("S")
        dris.size = Marshal.SizeOf(dris)
        dris.myfunction = DECRYPT_USER_DATA         ' standard protection check & decrypt data
        dris.flags = USE_FUNCTION_ARGUMENT          ' you have to do it this way in vb.net
        dris.rw_length = data.Length
        dris.data_crypt_key_num = 1
        dris.var_a = dris.var_a And &HFFFFFF        ' restrict to 24-bit to prevent potential overflow in algorithm
        dris.var_b = dris.var_b And &HFFFFFF
        dris.var_c = dris.var_c And &HFFFFFF
        dris.var_d = dris.var_d And &HFFFFFF
        dris.var_e = dris.var_e And &HFFFFFF
        dris.var_f = dris.var_f And &HFFFFFF
        dris.var_g = dris.var_g And &HFFFFFF
        dris.var_h = dris.var_h And &HFFFFFF

        Call CryptDRIS(dris)                          ' encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)

        ret_code = DDProtCheck(dris, data)

        Call CryptDRIS(dris)                          ' decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)

        If (ret_code <> 0) Then
            Call DisplayError(ret_code, dris.ext_err)
            EncryptUserDataEnc = ret_code
            Exit Function
        End If

        ' calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
        alg_ans = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h)

        ' later in your code you can check other values in the DRIS...
        If (dris.sdsn <> MY_SDSN) Then
            MsgBox("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", MsgBoxStyle.OkOnly, "Error")
            EncryptUserDataEnc = -1
            Exit Function
        End If

        ' later on in your program you can check the return code again
        If (dris.ret_code <> 0) Then
            MsgBox("Dinkey Dongle protection error", MsgBoxStyle.OkOnly, "Error")
            EncryptUserDataEnc = -1
            Exit Function
        End If

        ' decrypt data just returned by API.
        CryptApiData(dris, data, data.Length, alg_ans)
        MsgBox("Decrypted data is : " + Str(data(0)) + "," + Str(data(1)) + "," + Str(data(2)) + "," + Str(data(3)) + "," + _
            Str(data(4)) + "," + Str(data(5)) + "," + Str(data(6)) + "," + Str(data(7)) + "," + Str(data(8)) + "," + Str(data(9)), MsgBoxStyle.OkOnly)
        EncryptUserDataEnc = 0
        Exit Function
Protection_Err:  ' see readme.txt for explanation of this exception handler
        Protection_Exception()
        EncryptUserDataEnc = -1
    End Function

	
	' ***********************   DisplayNetUsers   *******************************
	' This function displays the current network users (for DinkeyNet only).
	' The DDProtCheck function must be called before this function is called.
	' (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want) 
	Function DisplayNetUsers(net_users As Integer, model As Integer) As Integer
		Dim num_net_users, extended_error, ret_code, i, max_net_users As Integer
		Dim DisplayString As String

        If net_users = -1 Then
            max_net_users = 100    ' if unlimited network users are allowed then display up to 100 users (for example)
        Else
            max_net_users = net_users
        End If

        If max_net_users = 0 Then   ' no network users are allowed, so nothing to do!
            DisplayNetUsers = 0
            Exit Function
        End If

        If model < 3 Then
            MsgBox("A network dongle has not been detected. Therefore you cannot display the network users.", MsgBoxStyle.OKOnly)
            DisplayNetUsers = -1
            Exit Function
        End If

        Dim nu_info_array(max_net_users) As NU_INFO

        ' now get net users
        ret_code = DDGetNetUserList(Nothing, num_net_users, nu_info_array, max_net_users, extended_error)

        If ret_code <> 0 Then
            MsgBox("Error " + Str(ret_code) + "/" + Str(extended_error) + " finding network user information.", MsgBoxStyle.OKOnly)
        Else
            DisplayString = "number of net users: " + Str(num_net_users) + Environment.NewLine
            For i = 0 To num_net_users - 1
                DisplayString = DisplayString + Str(i + 1) + ". licence: " + nu_info_array(i).LicenceName + ", user: " + nu_info_array(i).UserName + ", computer: " + nu_info_array(i).ComputerName + ", ip address: " + nu_info_array(i).IPAddress + Environment.NewLine
            Next
            MsgBox(DisplayString, MsgBoxStyle.OKOnly, "Net Users")
        End If
        DisplayNetUsers = ret_code

	End Function		

    ' look at the error code and try to display an appropriate message
    ' you may want to change these messages and specify your own
    Public Sub DisplayError(ByVal ret_code As Integer, ByVal extended_error As Integer)
        Select Case ret_code
            Case 401
                MsgBox("Error! No dongles detected!", MsgBoxStyle.OKOnly, "Error")
            Case 403
                MsgBox("Error! A dongle was detected but it was a different type to the one specified in DinkeyAdd.", MsgBoxStyle.OKOnly, "Error")
            Case 404
                MsgBox("Error! A dongle was detected but it was a different model to those specified in DinkeyAdd.", MsgBoxStyle.OKOnly, "Error")
            Case 409
                MsgBox("Error! The dongle detected has not been programmed by DinkeyAdd.", MsgBoxStyle.OKOnly, "Error")
            Case 410
                MsgBox("Error! A dongle was detected but it has a different Product Code to the one specified in DinkeyAdd.", MsgBoxStyle.OKOnly, "Error")
            Case 411
                MsgBox("Error! The dongle detected does not contain the licence associated with this program.", MsgBoxStyle.OKOnly, "Error")
            Case 413
                MsgBox("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.", MsgBoxStyle.OKOnly, "Error")
            Case 417
                MsgBox("Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.", MsgBoxStyle.OKOnly, "Error")
            Case 423
                MsgBox("Error! The number of network users has been exceeded.", MsgBoxStyle.OKOnly, "Error")
            Case 435
                MsgBox("Error! DinkeyServer has not been detected on the network.", MsgBoxStyle.OKOnly, "Error")
            Case 922
                MsgBox("Error! The Software Key has expired.", MsgBoxStyle.OKOnly, "Error")
            Case Else
                MsgBox("An error occurred checking the dongle. Error: " + Str(ret_code) + ". Extended Error: " + Str(extended_error) + ".", MsgBoxStyle.OKOnly, "Error")
        End Select
    End Sub

    ' if an error exception occurs during a protection check function then display an appropiate message
    ' see readme.txt for an explaination
    Sub Protection_Exception()
        If (TypeOf Err.GetException() Is DllNotFoundException) Then
            If (IntPtr.Size = 4) Then
                MsgBox("Error! Cannot find dpwin32.dll. This should be in the same folder that DLLTest.exe is in.", MsgBoxStyle.OKOnly, "Error")
            Else
                MsgBox("Error! Cannot find dpwin64.dll. This should be in the same folder that DLLTest.exe is in.", MsgBoxStyle.OKOnly, "Error")
            End If
        Else
            MsgBox("Error! An exception occurred: " + Err.GetException.Message, MsgBoxStyle.OKOnly, "Error")
        End If
    End Sub

End Class
