' !! this file should not be modified

' DAPF file is in the following format:
' DINKEYINFO
' LICENCEINFO (however many are needed)
' FILEINFO (however many are needed)
' ALGORITHM (however many are needed)
' DATAFILEENC (however many are needed)

Imports System
Imports System.Runtime.InteropServices     ' so we can marshal the structures as a block of memory
Imports System.Text                        ' for StringBuilder

' ***********  define structures that make up the DAPF file   *******************

Module dapf_code

	<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi, Pack:=1)> _
	 Structure DINKEYINFO
		Dim Header1 As Byte                ' should be set to "DAPF"
		Dim Header2 As Byte
		Dim Header3 As Byte
		Dim Header4 As Byte
		Dim Version As Integer              ' version of this structure. Currently 9.
		Dim SelectedModels As Integer       ' BIT0 = Dinkey Pro Lite, BIT1 = Dinkey Pro Plus, BIT2 = Dinkey Pro Net etc...
        <VBFixedString(12), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=12)> _
        Dim ProdCode As String
		Dim PerLicence As Integer           ' 1 = per licence, 0 = per product (default)
		Dim MaxNetUsers As Integer          ' product net users, unlimited = -1, no entry = -2
		Dim RangeSettings As Integer        ' 0 = any number, 1 = dongle in computer, 2 = range
		Dim RangeMin As UInt32
		Dim RangeMax As UInt32
		Dim NumLicences As Integer			' number of LICENCEINFO structures in this DAPF file
		Dim NumProgs As Integer				' number of FILEINFO structures in this DAPF file
		Dim NumAlgs As Integer
		Dim DataSizeType As Integer         ' 1 = set the zero data size, 0 = use file to initialise data area
		Dim ZeroDataSize As Integer         ' size of the data area area in bytes
		' NB some of these entries were for an older (deprecated) FD model. Now marked as deprecated. These fields are ignored.
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim DataFile As String               ' path to data file (0 = no data file)
		Dim DataAreaSize As Integer          ' file size in bytes, -1 = file not found
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim ShellSuccessMsg As String         ' Shell Method messages...
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim ShellNoDongleMsg As String
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim ShellExpiryDateMsg As String
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim ShellExpiryExecsMsg As String
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim ShellWarnDateMsg As String
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim ShellWarnExecsMsg As String
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim ShellNetUserLimitMsg As String
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim ShellOtherErrorMsg As String
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim ShellBackgroundMsg As String
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim NetNoServerMsg As String
        <VBFixedArray(12), MarshalAs(UnmanagedType.ByValArray, SizeConst:=12)> _
		Dim rwalg As Byte()                   ' coded form of rw algorithm (0 = no algorithm)
		Dim SecOptions As Integer             ' BIT0: DRIS encryption, BIT1: Data encryption, BIT2: Data enc with alg, BIT3: only secure update codes
		Dim SecDRISEncKey1 As Byte            ' DRIS encryption parameters
		Dim SecDRISEncKey2 As Byte			
		Dim SecDRISEncKey3 As Byte			
		Dim Ignored1 As Byte                  ' this byte is ignored
		Dim SecDataEncKey1 As Byte            ' API Data encryption parameters
		Dim SecDataEncKey2 As Byte			
		Dim SecDataEncKey3 As Byte
		Dim Ignored2 As Byte			      ' this byte is ignored
		Dim ProtectionType As Integer         ' 0 = software + dongle, 1 = dongle only, 2 = program only
        <VBFixedString(12), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=12)> _
        Dim DataEncKeyProdCode As String      ' Alternative Product Code used to generate internal encryption keys. Normally set to 0.
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim Notes As String                   ' user-defined notes
        Dim LockDongle As Integer             ' 0 = don't lock (default), 1 = lock dongle to user's computer
        Dim Reserved1 As Integer              ' must be 0
        Dim Reserved2 As Integer              ' must be 0
        Dim AdvancedOptions As Integer        ' BIT0 = do not allow usb-over-network for non-Net dongles, BIT1 = do not check for Software Key at Runtime. 
        Dim NumDataFileEnc As Integer         ' Number of data files in our encryption list
    End Structure

	<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi, Pack:=1)> _
	 Structure LICENCEINFO
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim LicenceName As String              ' licence name
		Dim MaxDays As Integer                 ' -1 = no limit
		Dim ExpiryDay As Integer               ' -1 = no limit, 0 = no change
		Dim ExpiryMonth As Integer
		Dim ExpiryYear As Integer
		Dim Execs As Integer		           ' -1 = no limit
		Dim ExecsWarn As Integer               ' 0 = no warning (just for Shell method)
		Dim DaysWarn As Integer                ' 0 = no warning (just for Shell method)
		Dim	Features As Uint32
		Dim LicenceNetUsers As Integer         ' unlimited = -1  (-2 = not needed (this is for display only))
	End Structure

	<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi, Pack:=1)> _
	 Structure FILEINFO
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim InputName As String               ' input file (full path)
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim OutputName As String               ' output file/folder
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim CallingProg As String              ' calling program name
        Dim LicenceIndex As Integer            ' index (of licence) in the LicenceInfo structure (1-based index. 0 = no selection)
        Dim Method As Integer                  ' 0-api, 1-shell, 2-shell & api
        Dim ShellFlags As Integer              ' same bit flag values as in dris. i.e. 1 = DEC_ONE_EXEC, 4 = START_NET_USER
        Dim BackGround As Integer              ' 0=no background, 1=1min, 2=5min, 3=10min, 4=30min, 5=60min
        Dim OtherShellOptions As Integer       ' BIT0 = Shell Data Encryption Enabled, BIT1: Extra Anti-Debug is disabled, BIT2: Extra Anti-Piracy is disabled
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim EncFileList As String              ' files (or file types) that the Shell-protected program will treat as encrypted (separated by ':')
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim ExceptList As String               ' files (or file types) that are exceptions to the above list (separated by ':')
        Dim ExtraAntiPiracy As Integer         ' 0 = off, 1=min, 10=max
	End Structure

	<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi, Pack:=1)> _
	 Structure ALGORITHM
        <VBFixedArray(12), MarshalAs(UnmanagedType.ByValArray, SizeConst:=12)> _
		Dim alg As Byte()                      ' coded form of algorithm
	End Structure 

	<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi, Pack:=1)> _
	 Structure DATAFILEENC
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim InputName As String                ' file name, wild cards are allowed
        <VBFixedString(256), MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
        Dim OutputName As String               ' file name (or folder name if input is a wildcard)
	End Structure 
	
    ' this structure is used for creating Temporary Software Keys
	<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi, Pack:=1)> _
	 Structure TEMP_SWKEY_INFO
		Dim Size As Integer
        Dim MachineID As UInt32
        Dim ExpiryDay As Integer
        Dim ExpiryMonth As Integer
        Dim ExpiryYear As Integer
        Dim DongleModel As Integer
        Dim DongleNumber As UInt32
	End Structure 

    ' this structure is used for creating Demo Software Key Templates
	<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi, Pack:=1)> _
	 Structure DEMO_SWKEY_INFO
		Dim Size As Integer
        Dim MaxDays As Int32                    ' max days demo swkey installation is valid (0-60)
        Dim Models As Int32                     ' bitmap of valid dongle models. See constant values below. 0 = default (only use if only one model is selected in DINKEYINFO)
	End Structure    
    
' **********************  DinkeyAdd Module Imports  ************************

    ' Loads DAPF from disk and returns handle
    Declare Ansi Function LoadDAPFFromFile32 Lib "DinkeyAdd32.dll" Alias "LoadDAPFFromFile" (ByVal dapf_file As String, ByRef err_code As Integer) As IntPtr
    Declare Ansi Function LoadDAPFFromFile64 Lib "DinkeyAdd64.dll" Alias "LoadDAPFFromFile" (ByVal dapf_file As String, ByRef err_code As Integer) As IntPtr

    ' Loads DAPF from disk into structures supplied (so we can modify DAPF in memory)
    Declare Ansi Function ReadDAPFEx32 Lib "DinkeyAdd32.dll" Alias "ReadDAPFEx" (ByVal dapf_file As String, ByRef MyDinkeyInfo As DINKEYINFO, ByVal licence_bytes() As Byte, _
        ByVal fileinfo_bytes() As Byte, ByVal alg_bytes() As Byte, ByVal datafile_bytes() As Byte, ByRef dapf_version As Integer, ByRef dapf_format As Integer) As Integer
    Declare Ansi Function ReadDAPFEx64 Lib "DinkeyAdd64.dll" Alias "ReadDAPFEx" (ByVal dapf_file As String, ByRef MyDinkeyInfo As DINKEYINFO, ByVal licence_bytes() As Byte, _
        ByVal fileinfo_bytes() As Byte, ByVal alg_bytes() As Byte, ByVal datafile_bytes() As Byte, ByRef dapf_version As Integer, ByRef dapf_format As Integer) As Integer

    ' Loads DAPF from structures and returns a handle
    Declare Ansi Function LoadDAPF32 Lib "DinkeyAdd32.dll" Alias "LoadDAPF" (ByRef MyDinkeyInfo As DINKEYINFO, ByVal licence_bytes() As Byte, ByVal fileinfo_bytes() As Byte, _
        ByVal alg_bytes() As Byte, ByVal datafile_bytes() As Byte, ByRef ret_code As Integer) As IntPtr
    Declare Ansi Function LoadDAPF64 Lib "DinkeyAdd64.dll" Alias "LoadDAPF" (ByRef MyDinkeyInfo As DINKEYINFO, ByVal licence_bytes() As Byte, ByVal fileinfo_bytes() As Byte, _
        ByVal alg_bytes() As Byte, ByVal datafile_bytes() As Byte, ByRef ret_code As Integer) As IntPtr

    ' saves the DAPF file to disk
    Declare Ansi Function WriteDAPFEx32 Lib "DinkeyAdd32.dll" Alias "WriteDAPFEx" (ByVal dapf_handle As IntPtr, ByVal dapf_file As String, ByVal dapf_format As Integer, _
        ByVal dapf_version As Integer, ByVal flags As Integer) As Integer
    Declare Ansi Function WriteDAPFEx64 Lib "DinkeyAdd64.dll" Alias "WriteDAPFEx" (ByVal dapf_handle As IntPtr, ByVal dapf_file As String, ByVal dapf_format As Integer, _
        ByVal dapf_version As Integer, ByVal flags As Integer) As Integer

    ' unloads the DAPF file
    Declare Ansi Sub UnloadDAPF32 Lib "DinkeyAdd32.dll" Alias "UnloadDAPF" (ByRef dapf_handle As IntPtr)
    Declare Ansi Sub UnloadDAPF64 Lib "DinkeyAdd64.dll" Alias "UnloadDAPF" (ByRef dapf_handle As IntPtr)

    'main functions
    Declare Ansi Function AddProtection32 Lib "DinkeyAdd32.dll" Alias "AddProtection" (ByVal dapf_handle As IntPtr, ByVal action As Integer, ByVal file_num As Integer, _
        ByVal flags As Integer, ByRef dongle_number As UInt32) As Integer
    Declare Ansi Function AddProtection64 Lib "DinkeyAdd64.dll" Alias "AddProtection" (ByVal dapf_handle As IntPtr, ByVal action As Integer, ByVal file_num As Integer, _
        ByVal flags As Integer, ByRef dongle_number As UInt32) As Integer

    Declare Ansi Function CreateTempSoftwareKey32 Lib "DinkeyAdd32.dll" Alias "CreateTempSoftwareKey" (ByVal dapf_handle As IntPtr, ByRef my_swkey_info As TEMP_SWKEY_INFO, _
        ByVal flags As Integer) As Integer
    Declare Ansi Function CreateTempSoftwareKey64 Lib "DinkeyAdd64.dll" Alias "CreateTempSoftwareKey" (ByVal dapf_handle As IntPtr, ByRef my_swkey_info As TEMP_SWKEY_INFO, _
        ByVal flags As Integer) As Integer

    Declare Ansi Function CreateDemoSoftwareKeyTemplate32 Lib "DinkeyAdd32.dll" Alias "CreateDemoSoftwareKeyTemplate" (ByVal dapf_handle As IntPtr, ByRef my_swkey_info As DEMO_SWKEY_INFO, _
        ByVal flags As Integer) As Integer
    Declare Ansi Function CreateDemoSoftwareKeyTemplate64 Lib "DinkeyAdd64.dll" Alias "CreateDemoSoftwareKeyTemplate" (ByVal dapf_handle As IntPtr, ByRef my_swkey_info As DEMO_SWKEY_INFO, _
        ByVal flags As Integer) As Integer

    Declare Ansi Function EncryptShellDataFiles32 Lib "DinkeyAdd32.dll" Alias "EncryptShellDataFiles" (ByVal dapf_handle As IntPtr, ByVal file_num As Integer, _
        ByVal flags As Integer) As Integer
    Declare Ansi Function EncryptShellDataFiles64 Lib "DinkeyAdd64.dll" Alias "EncryptShellDataFiles" (ByVal dapf_handle As IntPtr, ByVal file_num As Integer, _
        ByVal flags As Integer) As Integer

    ' get the message output by DinkeyAdd
    Declare Ansi Sub GetLastMessage32 Lib "DinkeyAdd32.dll" Alias "GetLastMessage" (ByVal message As StringBuilder, ByVal buffer_size As Integer, ByRef message_length As Integer)
    Declare Ansi Sub GetLastMessage64 Lib "DinkeyAdd64.dll" Alias "GetLastMessage" (ByVal message As StringBuilder, ByVal buffer_size As Integer, ByRef message_length As Integer)

    ' get the extended error (set if an error occurs)
    Declare Ansi Function GetLastExtendedError32 Lib "DinkeyAdd32.dll" Alias "GetLastExtendedError" () As Integer
    Declare Ansi Function GetLastExtendedError64 Lib "DinkeyAdd64.dll" Alias "GetLastExtendedError" () As Integer

    ' **********************  Constants  ************************
    Public Const DAPF_VERSION As Integer = 9                ' current DAPF version

	' WriteDAPFEx API flags
	Public Const FLAGS_LOSE_FEATURES As Integer = 1         ' means that you can save the DAPF file to an earlier version even if it means losing some new features that have been currently set

	' AddProtection API action values
	Public Const ACTION_USE_DAPF_SETTINGS As Integer = 0    ' means you just ignore the action value and use the default dapf settings
	Public Const ACTION_PROGRAM_DONGLE As Integer = 1       ' program the dongle only
	Public Const ACTION_PROTECT_SOFTWARE As Integer = 2     ' protect a software file (index indicated by separate parameter)
	Public Const ACTION_PROGRAM_AND_PROTECT As Integer = 3  ' program the dongle and protect software

	' AddProtection API flags values
	Public Const FLAGS_OVERWRITE_OUTPUT As Integer = 1      ' overwrite the output file if it already exists (default is to give an error)

	' CreateSoftwareKey API flags
	Public Const FLAGS_OVERWRITE_SWKEY As Integer = 1       ' ovewrite an existing swkey with the new one
	Public Const FLAGS_EXPIRY_DONTCARE As Integer = 2       ' create the Software Key even though the expiry date (or max days) is less than the expiry date of the key itself.

	' constants for dapf_format in ReadDAPFEx and WriteDAPFEx functions
	Public Const DAPF_FORMAT_BINARY As Integer = 1
	Public Const DAPF_FORMAT_JSON As Integer = 2
	Public Const DAPF_FORMAT_JSON_MIN As Integer = 3        ' this value is only used with WriteDAPEx. ReadDAPFEx cannot return this value.

	' constants for values for model in the TEMP_SWKEY_INFO structure
	Public Const SWKEY_MODEL_PRO_LITE As Integer = 0
	Public Const SWKEY_MODEL_PRO_PLUS As Integer = 1
	Public Const SWKEY_MODEL_PRO_NET As Integer = 2
	Public Const SWKEY_MODEL_FD_LITE As Integer = 3
	Public Const SWKEY_MODEL_FD_PLUS As Integer = 4
	Public Const SWKEY_MODEL_FD_NET As Integer = 5

	' constants for models bitmap in the DEMO_SWKEY_INFO structure
	Public Const SWKEY_BITMAP_DEFAULT As Integer = 0        ' use default value set in DINKEYINFO.SelectedModels
	Public Const SWKEY_BITMAP_PRO_LITE As Integer = 1       ' BIT0
	Public Const SWKEY_BITMAP_PRO_PLUS As Integer = 2       ' BIT1
	Public Const SWKEY_BITMAP_PRO_NET As Integer = 4        ' BIT2
	Public Const SWKEY_BITMAP_FD_LITE As Integer = 8        ' BIT3
	Public Const SWKEY_BITMAP_FD_PLUS As Integer = 16       ' BIT4
	Public Const SWKEY_BITMAP_FD_NET As Integer = 32        ' BIT5

	' private constants
	Private Const MAX_LICENCES As Integer = 255             ' max number of licences in a DAPF file
	Private Const MAX_FILE_INFO As Integer = 1000           ' theoretically unlimited but in practice it is easier if we limit it
	Private Const MAX_USER_ALGS As Integer = 20             'max number of user algs in DAPF file
	Private Const MAX_DATA_ENCS As Integer = 255            ' max number of Shell data encryption files in DAPF file       

' **********************  API Functions  ************************
' We only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist.
' if the appropriate DLL does not exist in the same directory as this test program you will receive a DllNotFoundException
    
    ' call the correct dll depending on whether we are running 32-bit or 64-bit code
    Function LoadDAPFFromFile(ByVal dapf_file As String, ByRef err_code As Integer) As IntPtr
        If (IntPtr.Size = 4) Then
            LoadDAPFFromFile = LoadDAPFFromFile32(dapf_file, err_code)
        Else
            LoadDAPFFromFile = LoadDAPFFromFile64(dapf_file, err_code)
        End If
    End Function

    ' we have to do some marshalling of arrays of bytes into arrays of structures
    Function ReadDAPFEx(ByVal dapf_file As String, ByRef MyDinkeyInfo As DINKEYINFO, ByRef LicenceInfoArray() As LICENCEINFO, ByRef FileInfoArray() As FILEINFO, _
            ByRef AlgorithmArray() As ALGORITHM, ByRef DataFileEncArray() As DATAFILEENC, ByRef dapf_version As Integer, ByRef dapf_format As Integer) As Integer
        Dim i As Integer
        Dim MyLicenceInfo As New LICENCEINFO
        Dim licence_bytes(MAX_LICENCES * Marshal.SizeOf(MyLicenceInfo)) As Byte
        Dim licence_bytes_one_struct(Marshal.SizeOf(MyLicenceInfo)) As Byte
        Dim MyFileInfo As New FILEINFO
        Dim fileinfo_bytes(MAX_FILE_INFO * Marshal.SizeOf(MyFileInfo)) As Byte
        Dim fileinfo_bytes_one_struct(Marshal.SizeOf(MyFileInfo)) As Byte
        Dim MyAlgorithm As New ALGORITHM
        Dim alg_bytes(MAX_USER_ALGS * Marshal.SizeOf(MyAlgorithm)) As Byte
        Dim alg_bytes_one_struct(Marshal.SizeOf(MyAlgorithm)) As Byte
        Dim MyDataFileEnc As New DATAFILEENC
        Dim datafile_bytes(MAX_DATA_ENCS * Marshal.SizeOf(MyDataFileEnc)) As Byte
        Dim datafile_bytes_one_struct(Marshal.SizeOf(MyDataFileEnc)) As Byte
        Dim MyGC As GCHandle
        MyDinkeyInfo = New DINKEYINFO

        If (IntPtr.Size = 4) Then
            ReadDAPFEx = ReadDAPFEx32(dapf_file, MyDinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, dapf_version, dapf_format)
        Else
            ReadDAPFEx = ReadDAPFEx64(dapf_file, MyDinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, dapf_version, dapf_format)
        End If

        If ReadDAPFEx <> 0 Then
            Exit Function
        End If

        ' convert byte array to an array of structs
        ReDim LicenceInfoArray(MyDinkeyInfo.NumLicences)
        For i = 0 To MyDinkeyInfo.NumLicences - 1
            LicenceInfoArray(i) = New LICENCEINFO
            Array.Copy(licence_bytes, i * Marshal.SizeOf(MyLicenceInfo.GetType), licence_bytes_one_struct, 0, Marshal.SizeOf(MyLicenceInfo.GetType))
            MyGC = GCHandle.Alloc(licence_bytes_one_struct, GCHandleType.Pinned)
            LicenceInfoArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyLicenceInfo.GetType)
            MyGC.Free()
        Next

        ReDim FileInfoArray(MyDinkeyInfo.NumProgs)
        For i = 0 To MyDinkeyInfo.NumProgs - 1
            FileInfoArray(i) = New FILEINFO
            Array.Copy(fileinfo_bytes, i * Marshal.SizeOf(MyFileInfo.GetType), fileinfo_bytes_one_struct, 0, Marshal.SizeOf(MyFileInfo.GetType))
            MyGC = GCHandle.Alloc(fileinfo_bytes_one_struct, GCHandleType.Pinned)
            FileInfoArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyFileInfo.GetType)
            MyGC.Free()
        Next

        ReDim AlgorithmArray(MyDinkeyInfo.NumAlgs)
        For i = 0 To MyDinkeyInfo.NumAlgs - 1
            AlgorithmArray(i) = New ALGORITHM
            Array.Copy(alg_bytes, i * Marshal.SizeOf(MyAlgorithm.GetType), alg_bytes_one_struct, 0, Marshal.SizeOf(MyAlgorithm.GetType))
            MyGC = GCHandle.Alloc(alg_bytes_one_struct, GCHandleType.Pinned)
            AlgorithmArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyAlgorithm.GetType)
            MyGC.Free()
        Next

        ReDim DataFileEncArray(MyDinkeyInfo.NumDataFileEnc)
        For i = 0 To MyDinkeyInfo.NumDataFileEnc - 1
            DataFileEncArray(i) = New DATAFILEENC
            Array.Copy(datafile_bytes, i * Marshal.SizeOf(MyDataFileEnc.GetType), datafile_bytes_one_struct, 0, Marshal.SizeOf(MyDataFileEnc.GetType))
            MyGC = GCHandle.Alloc(datafile_bytes_one_struct, GCHandleType.Pinned)
            DataFileEncArray(i) = Marshal.PtrToStructure(MyGC.AddrOfPinnedObject, MyDataFileEnc.GetType)
            MyGC.Free()
        Next

    End Function

    Function LoadDAPF(ByRef MyDinkeyInfo As DINKEYINFO, ByRef LicenceInfoArray() As LICENCEINFO, ByRef FileInfoArray() As FILEINFO, _
            ByRef AlgorithmArray() As ALGORITHM, ByRef DataFileEncArray() As DATAFILEENC, ByRef ret_code As Integer) As IntPtr
        Dim i As Integer
        Dim MyLicenceInfo As New LICENCEINFO
        Dim licence_bytes(MAX_LICENCES * Marshal.SizeOf(MyLicenceInfo)) As Byte
        Dim licence_bytes_one_struct(Marshal.SizeOf(MyLicenceInfo)) As Byte
        Dim MyFileInfo As New FILEINFO
        Dim fileinfo_bytes(MAX_FILE_INFO * Marshal.SizeOf(MyFileInfo)) As Byte
        Dim fileinfo_bytes_one_struct(Marshal.SizeOf(MyFileInfo)) As Byte
        Dim MyAlgorithm As New ALGORITHM
        Dim alg_bytes(MAX_USER_ALGS * Marshal.SizeOf(MyAlgorithm)) As Byte
        Dim alg_bytes_one_struct(Marshal.SizeOf(MyAlgorithm)) As Byte
        Dim MyDataFileEnc As New DATAFILEENC
        Dim datafile_bytes(MAX_DATA_ENCS * Marshal.SizeOf(MyDataFileEnc)) As Byte
        Dim datafile_bytes_one_struct(Marshal.SizeOf(MyDataFileEnc)) As Byte
        Dim MyGC As GCHandle

        ' convert array of structs to byte arrays
        For i = 0 To MyDinkeyInfo.NumLicences - 1
            MyGC = GCHandle.Alloc(licence_bytes_one_struct, GCHandleType.Pinned)
            Marshal.StructureToPtr(LicenceInfoArray(i), MyGC.AddrOfPinnedObject, False)
            MyGC.Free()
            Array.Copy(licence_bytes_one_struct, 0, licence_bytes, i * Marshal.SizeOf(MyLicenceInfo.GetType), Marshal.SizeOf(MyLicenceInfo.GetType))
        Next

        For i = 0 To MyDinkeyInfo.NumProgs - 1
            MyGC = GCHandle.Alloc(fileinfo_bytes_one_struct, GCHandleType.Pinned)
            Marshal.StructureToPtr(FileInfoArray(i), MyGC.AddrOfPinnedObject, False)
            MyGC.Free()
            Array.Copy(fileinfo_bytes_one_struct, 0, fileinfo_bytes, i * Marshal.SizeOf(MyFileInfo.GetType), Marshal.SizeOf(MyFileInfo.GetType))
        Next

        For i = 0 To MyDinkeyInfo.NumAlgs - 1
            MyGC = GCHandle.Alloc(alg_bytes_one_struct, GCHandleType.Pinned)
            Marshal.StructureToPtr(AlgorithmArray(i), MyGC.AddrOfPinnedObject, False)
            MyGC.Free()
            Array.Copy(alg_bytes_one_struct, 0, alg_bytes, i * Marshal.SizeOf(MyAlgorithm.GetType), Marshal.SizeOf(MyAlgorithm.GetType))
        Next

        For i = 0 To MyDinkeyInfo.NumDataFileEnc - 1
            MyGC = GCHandle.Alloc(datafile_bytes_one_struct, GCHandleType.Pinned)
            Marshal.StructureToPtr(DataFileEncArray(i), MyGC.AddrOfPinnedObject, False)
            MyGC.Free()
            Array.Copy(datafile_bytes_one_struct, 0, datafile_bytes, i * Marshal.SizeOf(MyDataFileEnc.GetType), Marshal.SizeOf(MyDataFileEnc.GetType))
        Next

        If (IntPtr.Size = 4) Then
            LoadDAPF = LoadDAPF32(MyDinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, ret_code)
        Else
            LoadDAPF = LoadDAPF64(MyDinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, ret_code)
        End If

    End Function

    Function WriteDAPFEx(ByVal dapf_handle As IntPtr, ByVal dapf_file As String, ByVal dapf_format As Integer, ByVal dapf_version As Integer, ByVal flags As Integer) As Integer
        If (IntPtr.Size = 4) Then
            WriteDAPFEx = WriteDAPFEx32(dapf_handle, dapf_file, dapf_format, dapf_version, flags)
        Else
            WriteDAPFEx = WriteDAPFEx64(dapf_handle, dapf_file, dapf_format, dapf_version, flags)
        End If
    End Function

    Sub UnloadDAPF(ByRef dapf_handle As IntPtr)
        If (IntPtr.Size = 4) Then
            UnloadDAPF32(dapf_handle)
        Else
            UnloadDAPF64(dapf_handle)
        End If
    End Sub

    Function AddProtection(ByVal dapf_handle As IntPtr, ByVal action As Integer, ByVal file_num As Integer, ByVal flags As Integer, ByRef dongle_number As UInt32) As Integer
        If (IntPtr.Size = 4) Then
            AddProtection = AddProtection32(dapf_handle, action, file_num, flags, dongle_number)
        Else
            AddProtection = AddProtection64(dapf_handle, action, file_num, flags, dongle_number)
        End If
    End Function

    Function CreateTempSoftwareKey(ByVal dapf_handle As IntPtr, ByRef swkey_info As TEMP_SWKEY_INFO, ByVal flags As Integer) As Integer
        If (IntPtr.Size = 4) Then
            CreateTempSoftwareKey = CreateTempSoftwareKey32(dapf_handle, swkey_info, flags)
        Else
            CreateTempSoftwareKey = CreateTempSoftwareKey64(dapf_handle, swkey_info, flags)
        End If
    End Function

    Function CreateDemoSoftwareKeyTemplate(ByVal dapf_handle As IntPtr, ByRef swkey_info As DEMO_SWKEY_INFO, ByVal flags As Integer) As Integer
        If (IntPtr.Size = 4) Then
            CreateDemoSoftwareKeyTemplate = CreateDemoSoftwareKeyTemplate32(dapf_handle, swkey_info, flags)
        Else
            CreateDemoSoftwareKeyTemplate = CreateDemoSoftwareKeyTemplate64(dapf_handle, swkey_info, flags)
        End If
    End Function    
    
    Function EncryptShellDataFiles(ByVal dapf_handle As IntPtr, ByVal file_num As Integer, ByVal flags As Integer) As Integer
        If (IntPtr.Size = 4) Then
            EncryptShellDataFiles = EncryptShellDataFiles32(dapf_handle, file_num, flags)
        Else
            EncryptShellDataFiles = EncryptShellDataFiles64(dapf_handle, file_num, flags)
        End If
    End Function

    ' do a bit of work here to make the function easier to use for VB.NET
    Function GetLastMessage() As String
        Dim length, dummy As Integer
        Dim message As StringBuilder

        If (IntPtr.Size = 4) Then
            GetLastMessage32(Nothing, 0, length)
            message = New StringBuilder(length)
            GetLastMessage32(message, length, dummy)
        Else
            GetLastMessage64(Nothing, 0, length)
            message = New StringBuilder(length)
            GetLastMessage64(message, length, dummy)
        End If

        Return message.ToString()
    End Function

    Function GetLastExtendedError() As Integer
        If (IntPtr.Size = 4) Then
            GetLastExtendedError = GetLastExtendedError32()
        Else
            GetLastExtendedError = GetLastExtendedError64()
        End If
    End Function

End Module
