// !! 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)

using System;
using System.Runtime.InteropServices;   // so we can marshal the structures as a block of memory
using System.Text;						// for StringBuilder class for GetLastMessage API

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

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

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
public struct LICENCEINFO
{
	[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
	public string LicenceName;
	public int MaxDays;                                     // -1 = no limit
	public int ExpiryDay;                                   // -1 = no limit, 0 = no change
	public int ExpiryMonth;
	public int ExpiryYear;
	public int Execs;					                    // -1 = no limit
	public int ExecsWarn;                                   // 0 = no warning (just for Shell method)
	public int DaysWarn;                                    // 0 = no warning (just for Shell method)
	public uint	Features;
	public int LicenceNetUsers;                             // unlimited = -1  (-2 = not needed (this is for display only))
}

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

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
public struct ALGORITHM
{
	[MarshalAs(UnmanagedType.ByValArray, SizeConst=12)]
	public byte[] alg;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
public struct DATAFILEENC
{
	[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
	public string InputName;                                // file name, wild cards are allowed
	[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
	public string OutputName;                               // file name (or folder name if input is a wildcard)
}

// this structure is used for creating temporary software keys
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
public struct TEMP_SWKEY_INFO
{
	public int size;                                        // size of this structure (must be initialised)
	public uint machineID;                                  // machine ID in (hex) integer form
	public int expiry_day;                                  // expiry date of the Software Key
	public int expiry_month;
	public int expiry_year;
	public int dongle_model;                                // model of the Software Key. See constant values below
	public uint dongle_number;                              // dongle number of the Software Key. 0 = default (random)
}

// this structure is used for creating demo software key templates
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
public struct DEMO_SWKEY_INFO
{
	public int size;                                        // size of this structure (must be initialised)
	public int max_days;                                    // max days demo swkey installation is valid (0-60)
	public int models;                                      // bitmap of valid dongle models. See constant values below. 0 = default (only use if only one model is selected in DINKEYINFO)
}


// **********************  API functions  ************************
// we declare classes for all the API functions for each bitness

// Loads DAPF from disk and returns handle
class LoadDAPFFromFile32
{
	[DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)]
	public static extern IntPtr LoadDAPFFromFile(string dapf_file, out int err_code);
}

class LoadDAPFFromFile64
{
	[DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)]
	public static extern IntPtr LoadDAPFFromFile(string dapf_file, out int err_code);
}

// Loads DAPF from disk into structures supplied (so we can modify DAPF in memory)
class ReadDAPFEx32
{
	[DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)]
	public static extern int ReadDAPFEx(string dapf_file, out DINKEYINFO DinkeyInfo, byte[] licence_bytes, byte[] fileinfo_bytes, byte[] alg_bytes, byte[] datafile_bytes, out int dapf_version, out int dapf_format);
}

class ReadDAPFEx64
{
	[DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)]
	public static extern int ReadDAPFEx(string dapf_file, out DINKEYINFO DinkeyInfo, byte[] licence_bytes, byte[] fileinfo_bytes, byte[] alg_bytes, byte[] datafile_bytes, out int dapf_version, out int dapf_format);
}

// Loads DAPF from structures and returns a handle
class LoadDAPF32
{
	[DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)]
	public static extern IntPtr LoadDAPF(ref DINKEYINFO DinkeyInfo, byte[] licence_bytes, byte[] fileinfo_bytes, byte[] alg_bytes, byte[] datafile_bytes, out int ret_code);
}

class LoadDAPF64
{
	[DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)]
	public static extern IntPtr LoadDAPF(ref DINKEYINFO DinkeyInfo, byte[] licence_bytes, byte[] fileinfo_bytes, byte[] alg_bytes, byte[] datafile_bytes, out int ret_code);
}

// saves the DAPF file to disk
class WriteDAPFEx32
{
	[DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)]
	public static extern int WriteDAPFEx(IntPtr dapf_handle, string dapf_file, int dapf_format, int dapf_version, int flags);
}

class WriteDAPFEx64
{
	[DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)]
	public static extern int WriteDAPFEx(IntPtr dapf_handle, string dapf_file, int dapf_format, int dapf_version, int flags);
}

// unloads the DAPF file
class UnloadDAPF32
{
	[DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)]
	public static extern void UnloadDAPF(ref IntPtr dapf_handle);
}

class UnloadDAPF64
{
	[DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)]
	public static extern void UnloadDAPF(ref IntPtr dapf_handle);
}

class AddProtection32
{
	[DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)]
	public static extern int AddProtection(IntPtr dapf_handle, int action, int file_num, int flags, out uint dongle_number);
}

class AddProtection64
{
	[DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)]
	public static extern int AddProtection(IntPtr dapf_handle, int action, int file_num, int flags, out uint dongle_number);
}

class CreateTempSoftwareKey32
{
	[DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)]
	public static extern int CreateTempSoftwareKey(IntPtr dapf_handle, ref TEMP_SWKEY_INFO swkey_info, int flags);
}

class CreateTempSoftwareKey64
{
	[DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)]
	public static extern int CreateTempSoftwareKey(IntPtr dapf_handle, ref TEMP_SWKEY_INFO swkey_info, int flags);
}

class CreateDemoSoftwareKeyTemplate32
{
	[DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)]
	public static extern int CreateDemoSoftwareKeyTemplate(IntPtr dapf_handle, ref DEMO_SWKEY_INFO swkey_info, int flags);
}

class CreateDemoSoftwareKeyTemplate64
{
	[DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)]
	public static extern int CreateDemoSoftwareKeyTemplate(IntPtr dapf_handle, ref DEMO_SWKEY_INFO swkey_info, int flags);
}

class EncryptShellDataFiles32
{
	[DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)]
	public static extern int EncryptShellDataFiles(IntPtr dapf_handle, int file_num, int flags);
}

class EncryptShellDataFiles64
{
	[DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)]
	public static extern int EncryptShellDataFiles(IntPtr dapf_handle, int file_num, int flags);
}

class GetLastMessage32
{
	[DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)]
	public static extern void GetLastMessage(StringBuilder message, int buffer_size, out int message_length);
}

class GetLastMessage64
{
	[DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)]
	public static extern void GetLastMessage(StringBuilder message, int buffer_size, out int message_length);
}

class GetLastExtendedError32
{
	[DllImport("DinkeyAdd32.dll", CharSet = CharSet.Ansi)]
	public static extern int GetLastExtendedError();
}

class GetLastExtendedError64
{
	[DllImport("DinkeyAdd64.dll", CharSet = CharSet.Ansi)]
	public static extern int GetLastExtendedError();
}

// ********************* DinkeyAdd class **********************
class DinkeyAdd
{
	// constants
	public const int DAPF_VERSION = 9;					// current DAPF version

	// WriteDAPFEx API flags
	public const int FLAGS_LOSE_FEATURES = 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 int ACTION_USE_DAPF_SETTINGS   = 0;	// means you just ignore the action value and use the default dapf settings
	public const int ACTION_PROGRAM_DONGLE      = 1;	// program the dongle only
	public const int ACTION_PROTECT_SOFTWARE    = 2;	// protect a software file (index indicated by separate parameter)
	public const int ACTION_PROGRAM_AND_PROTECT = 3;	// program the dongle and protect software

	// AddProtection API flags values
	public const int FLAGS_OVERWRITE_OUTPUT = 1;		// overwrite the output file if it already exists (default is to give an error)

	// SoftwareKey API flags
	public const int FLAGS_OVERWRITE_SWKEY = 1;			// overwrite an existing swkey with the new one
	public const int FLAGS_EXPIRY_DONTCARE = 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 int DAPF_FORMAT_BINARY = 1;
	public const int DAPF_FORMAT_JSON = 2;
	public const int DAPF_FORMAT_JSON_MIN = 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 int SWKEY_MODEL_PRO_LITE = 0;			
	public const int SWKEY_MODEL_PRO_PLUS = 1;
	public const int SWKEY_MODEL_PRO_NET  = 2;
	public const int SWKEY_MODEL_FD_LITE  = 3;
	public const int SWKEY_MODEL_FD_PLUS  = 4;
	public const int SWKEY_MODEL_FD_NET   = 5;

	// constants for models bitmap in the DEMO_SWKEY_INFO structure
	public const int SWKEY_BITMAP_DEFAULT  = 0;         // use default value set in DINKEYINFO.SelectedModels
	public const int SWKEY_BITMAP_PRO_LITE = 1;         // BIT0
	public const int SWKEY_BITMAP_PRO_PLUS = 2;         // BIT1
	public const int SWKEY_BITMAP_PRO_NET  = 4;         // BIT2
	public const int SWKEY_BITMAP_FD_LITE  = 8;         // BIT3
	public const int SWKEY_BITMAP_FD_PLUS  = 16;        // BIT4
    public const int SWKEY_BITMAP_FD_NET   = 32;        // BIT5  

	// private constants
	private const int MAX_LICENCES = 255;				// max number of licences in a DAPF file
	private const int MAX_FILE_INFO = 1000;				// theoretically unlimited but in practice it is easier if we limit it
	private const int MAX_USER_ALGS = 20;				// max number of user algs in DAPF file
	private const int MAX_DATA_ENCS = 255;				// max number of Shell data encryption files in DAPF file

	// **** main API
	// 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

    public static IntPtr LoadDAPFFromFile(string dapf_file, out int err_code)
    {
        if (IntPtr.Size == 4)
			return LoadDAPFFromFile32.LoadDAPFFromFile(dapf_file, out err_code);
        return LoadDAPFFromFile64.LoadDAPFFromFile(dapf_file, out err_code);
    }

	// we have to do some marshalling of arrays of bytes into arrays of structures
	public static int ReadDAPFEx(string dapf_file, out DINKEYINFO DinkeyInfo, out LICENCEINFO[] LicenceInfo, out FILEINFO[] FileInfo, out ALGORITHM[] Algorithms, out DATAFILEENC[] DataFileEnc, out int dapf_version, out int dapf_format)
	{
		int ret_code, i;
		byte[] licence_bytes = new byte[MAX_LICENCES * Marshal.SizeOf(typeof(LICENCEINFO))];
		byte[] licence_bytes_one_struct = new byte[Marshal.SizeOf(typeof(LICENCEINFO))];
		byte[] fileinfo_bytes = new byte[MAX_FILE_INFO * Marshal.SizeOf(typeof(FILEINFO))];
		byte[] fileinfo_bytes_one_struct = new byte[Marshal.SizeOf(typeof(FILEINFO))];
		byte[] alg_bytes = new byte[MAX_USER_ALGS * Marshal.SizeOf(typeof(ALGORITHM))];
		byte[] alg_bytes_one_struct = new byte[Marshal.SizeOf(typeof(ALGORITHM))];
		byte[] datafile_bytes = new byte[MAX_DATA_ENCS * Marshal.SizeOf(typeof(DATAFILEENC))];
		byte[] datafile_bytes_one_struct = new byte[Marshal.SizeOf(typeof(DATAFILEENC))];
		GCHandle MyGC;
		DinkeyInfo = new DINKEYINFO();
		LicenceInfo = null;
		FileInfo = null;
		Algorithms = null;
		DataFileEnc = null;

        if (IntPtr.Size == 4)
			ret_code = ReadDAPFEx32.ReadDAPFEx(dapf_file, out DinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, out dapf_version, out dapf_format);
		else 
			ret_code = ReadDAPFEx64.ReadDAPFEx(dapf_file, out DinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, out dapf_version, out dapf_format);
		
		if (ret_code != 0)
			return ret_code;
		
		// convert byte array to an array of structs
		LicenceInfo = new LICENCEINFO[DinkeyInfo.NumLicences];
		for (i=0; i<DinkeyInfo.NumLicences; i++)
		{
			Array.Copy(licence_bytes, i*Marshal.SizeOf(typeof(LICENCEINFO)), licence_bytes_one_struct, 0, Marshal.SizeOf(typeof(LICENCEINFO)));
			MyGC = GCHandle.Alloc(licence_bytes_one_struct, GCHandleType.Pinned);
			LicenceInfo[i] = (LICENCEINFO)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(LICENCEINFO));
			MyGC.Free();
		}

		FileInfo = new FILEINFO[DinkeyInfo.NumProgs];
		for (i=0; i<DinkeyInfo.NumProgs; i++)
		{
			Array.Copy(fileinfo_bytes, i*Marshal.SizeOf(typeof(FILEINFO)), fileinfo_bytes_one_struct, 0, Marshal.SizeOf(typeof(FILEINFO)));
			MyGC = GCHandle.Alloc(fileinfo_bytes_one_struct, GCHandleType.Pinned);
			FileInfo[i] = (FILEINFO)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(FILEINFO));
			MyGC.Free();
		}

		Algorithms = new ALGORITHM[DinkeyInfo.NumAlgs];
		for (i=0; i<DinkeyInfo.NumAlgs; i++)
		{
			Array.Copy(alg_bytes, i*Marshal.SizeOf(typeof(ALGORITHM)), alg_bytes_one_struct, 0, Marshal.SizeOf(typeof(ALGORITHM)));
			MyGC = GCHandle.Alloc(alg_bytes_one_struct, GCHandleType.Pinned);
			Algorithms[i] = (ALGORITHM)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(ALGORITHM));
			MyGC.Free();
		}

		DataFileEnc = new DATAFILEENC[DinkeyInfo.NumDataFileEnc];
		for (i=0; i<DinkeyInfo.NumDataFileEnc; i++)
		{
			Array.Copy(datafile_bytes, i*Marshal.SizeOf(typeof(DATAFILEENC)), datafile_bytes_one_struct, 0, Marshal.SizeOf(typeof(DATAFILEENC)));
			MyGC = GCHandle.Alloc(datafile_bytes_one_struct, GCHandleType.Pinned);
			DataFileEnc[i] = (DATAFILEENC)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(DATAFILEENC));
			MyGC.Free();
		}

		return ret_code;
	}

	// we have to do some marshalling of an array of structures into an array of bytes
	public static IntPtr LoadDAPF(DINKEYINFO DinkeyInfo, LICENCEINFO[] LicenceInfo, FILEINFO[] FileInfo, ALGORITHM[] Algorithms, DATAFILEENC[] DataFileEnc, out int ret_code)
	{
		int i;
		byte[] licence_bytes = new byte[MAX_LICENCES * Marshal.SizeOf(typeof(LICENCEINFO))];
		byte[] licence_bytes_one_struct = new byte[Marshal.SizeOf(typeof(LICENCEINFO))];
		byte[] fileinfo_bytes = new byte[MAX_FILE_INFO * Marshal.SizeOf(typeof(FILEINFO))];
		byte[] fileinfo_bytes_one_struct = new byte[Marshal.SizeOf(typeof(FILEINFO))];
		byte[] alg_bytes = new byte[MAX_USER_ALGS * Marshal.SizeOf(typeof(ALGORITHM))];
		byte[] alg_bytes_one_struct = new byte[Marshal.SizeOf(typeof(ALGORITHM))];
		byte[] datafile_bytes = new byte[MAX_DATA_ENCS * Marshal.SizeOf(typeof(DATAFILEENC))];
		byte[] datafile_bytes_one_struct = new byte[Marshal.SizeOf(typeof(DATAFILEENC))];
		GCHandle MyGC;
		
		// convert array of structs to a byte array
		for (i=0; i<DinkeyInfo.NumLicences; i++)
		{
			MyGC = GCHandle.Alloc(licence_bytes_one_struct, GCHandleType.Pinned);
			Marshal.StructureToPtr(LicenceInfo[i], MyGC.AddrOfPinnedObject(), false);
			MyGC.Free();
			Array.Copy(licence_bytes_one_struct, 0, licence_bytes, i*Marshal.SizeOf(typeof(LICENCEINFO)), Marshal.SizeOf(typeof(LICENCEINFO)));
		}

		for (i=0; i<DinkeyInfo.NumProgs; i++)
		{
			MyGC = GCHandle.Alloc(fileinfo_bytes_one_struct, GCHandleType.Pinned);
			Marshal.StructureToPtr(FileInfo[i], MyGC.AddrOfPinnedObject(), false);
			MyGC.Free();
			Array.Copy(fileinfo_bytes_one_struct, 0, fileinfo_bytes, i*Marshal.SizeOf(typeof(FILEINFO)), Marshal.SizeOf(typeof(FILEINFO)));
		}

		for (i=0; i<DinkeyInfo.NumAlgs; i++)
		{
			MyGC = GCHandle.Alloc(alg_bytes_one_struct, GCHandleType.Pinned);
			Marshal.StructureToPtr(Algorithms[i], MyGC.AddrOfPinnedObject(), false);
			MyGC.Free();
			Array.Copy(alg_bytes_one_struct, 0, alg_bytes, i*Marshal.SizeOf(typeof(ALGORITHM)), Marshal.SizeOf(typeof(ALGORITHM)));
		}

		for (i=0; i<DinkeyInfo.NumDataFileEnc; i++)
		{
			MyGC = GCHandle.Alloc(datafile_bytes_one_struct, GCHandleType.Pinned);
			Marshal.StructureToPtr(DataFileEnc[i], MyGC.AddrOfPinnedObject(), false);
			MyGC.Free();
			Array.Copy(datafile_bytes_one_struct, 0, datafile_bytes, i*Marshal.SizeOf(typeof(DATAFILEENC)), Marshal.SizeOf(typeof(DATAFILEENC)));
		}

		if (IntPtr.Size == 4)
			return LoadDAPF32.LoadDAPF(ref DinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, out ret_code);
		return LoadDAPF64.LoadDAPF(ref DinkeyInfo, licence_bytes, fileinfo_bytes, alg_bytes, datafile_bytes, out ret_code);
	}

	public static int WriteDAPFEx(IntPtr dapf_handle, string dapf_file, int dapf_format, int dapf_version, int flags)
	{
		if (IntPtr.Size == 4)
			return WriteDAPFEx32.WriteDAPFEx(dapf_handle, dapf_file, dapf_format, dapf_version, flags);
		return WriteDAPFEx64.WriteDAPFEx(dapf_handle, dapf_file, dapf_format, dapf_version, flags);
	}
	
	public static void UnloadDAPF(ref IntPtr dapf_handle)
	{
		if (IntPtr.Size == 4)
			UnloadDAPF32.UnloadDAPF(ref dapf_handle);
		else
			UnloadDAPF64.UnloadDAPF(ref dapf_handle);
		return;
	}

	public static int AddProtection(IntPtr dapf_handle, int action, int file_num, int flags, out uint dongle_number)
	{
		if (IntPtr.Size == 4)
			return AddProtection32.AddProtection(dapf_handle, action, file_num, flags, out dongle_number);
		return AddProtection64.AddProtection(dapf_handle, action, file_num, flags, out dongle_number);
	}

	public static int CreateTempSoftwareKey(IntPtr dapf_handle, TEMP_SWKEY_INFO swkey_info, int flags) 
	{
		if (IntPtr.Size == 4)
			return CreateTempSoftwareKey32.CreateTempSoftwareKey(dapf_handle, ref swkey_info, flags);
		return CreateTempSoftwareKey64.CreateTempSoftwareKey(dapf_handle, ref swkey_info, flags);
	}

	public static int CreateDemoSoftwareKeyTemplate(IntPtr dapf_handle, DEMO_SWKEY_INFO swkey_info, int flags) 
	{
		if (IntPtr.Size == 4)
			return CreateDemoSoftwareKeyTemplate32.CreateDemoSoftwareKeyTemplate(dapf_handle, ref swkey_info, flags);
		return CreateDemoSoftwareKeyTemplate64.CreateDemoSoftwareKeyTemplate(dapf_handle, ref swkey_info, flags);
	}

    public static int EncryptShellDataFiles(IntPtr dapf_handle, int file_num, int flags)
    {
        if (IntPtr.Size == 4)
            return EncryptShellDataFiles32.EncryptShellDataFiles(dapf_handle, file_num, flags);
        return EncryptShellDataFiles64.EncryptShellDataFiles(dapf_handle, file_num, flags);
    }

	// do a bit of work here to make the function easier to use for C#
	public static string GetLastMessage()
	{
		int length, dummy;
		StringBuilder message;

		if (IntPtr.Size == 4)
		{
			GetLastMessage32.GetLastMessage(null, 0, out length);
			message = new StringBuilder(length);
			GetLastMessage32.GetLastMessage(message, length, out dummy);
		}
		else
		{
			GetLastMessage64.GetLastMessage(null, 0, out length);
			message = new StringBuilder(length);
			GetLastMessage64.GetLastMessage(message, length, out dummy);
		}

		return message.ToString();
	}

	public static int GetLastExtendedError()
	{
		if (IntPtr.Size == 4)
			return GetLastExtendedError32.GetLastExtendedError();
		return GetLastExtendedError64.GetLastExtendedError();
	}

}
