// dapfTest

// Sample code for calling DinkeyAdd module

// The sample code contains 5 functions. You will not need to use all these functions in your code.
// Just use which ever are most appropriate and customise in your own way. The sample code
// is just a guide.  

// There are two methods to loading a DAPF file. These are shown in the first two functions:
// DoProgramDongle (simple) and DoProgramDonglewithMod (more complex)

// DoProgramDongle: we load the DAPF file from disk and get a handle and use it "as is" using the API
//                  call LoadDAPFFromFile. You can make some limited changes to overwrite the default
//                  behaviour by using API flags.
                     
// DoProgramDonglewithMod: we load the DAPF file from disk and load into structures. We can then modify the
//                         DAPF settings by modifying this structure. This method uses the API calls
//                         ReadDAPFEx and LoadDAPF.
                        
// The other functions use the first method (as it is simpler) but you can use the second method instead if
// you prefer.

// Note - an alternative to using the DoProgramDongleWithMod technique is to modify the DAPF file on disk
//        and then use the DoProgramDongle technique. To modify a binary DAPF you would use the binary structures
//        that are defined in dapf.h. To modify JSON DAPF you would need to use a JSON parser. In the case of
//        C/C++ we think it is easier to use the DoProgramDongleWithMod technique.

// DoLockSoftware: locks software (protect it) to a dongle as specified by the DAPF file.

// DoEncryptShellData: encrypts the shell data files specified in the DAPF file (this is used with encrypting
//                     data file if you use the Shell Method with "Data File Encryption" enabled).
                     
// DoCreateTempSoftwareKey: creates a Temporary Software Key based on the DAPF file and settings the user has entered. 

// DoCreateDemoSoftwareTemplate: creates a Demo Software Key Template based on the DAPF file and settings the user has entered

#include <windows.h>
#include <stdio.h>

#include "Visual Studio 5\DinkeyAdd\resource.h"
#include "dapf.h"

#ifdef _MSC_VER
  #pragma warning(disable:4996)							// to disable warnings about sprintf etc... means we can use the same source for all compilers
#endif


char g_szAppName[] = "dapfTest";

void DisplayLastMessage(void);							// gets & displays the message from the DinkeyAdd Module


// load a DAPF file from disk and program the dongle as specified by the DAPF file
int DoProgramDongle(char *szFileDAPF) {
	DAPF_HANDLE dapfHandle;
	int err_code;
	unsigned int dongle_number;

	// load DAPF from File into memory
	dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code);
	if (dapfHandle == NULL) {
		DisplayLastMessage();
		return err_code;
	}

	// program dongle as specified by the DAPF file
	err_code = AddProtection(dapfHandle, ACTION_PROGRAM_DONGLE, 0, 0, &dongle_number);

	// Unload DAPF from memory
	UnloadDAPF(&dapfHandle);

	// display message (error or success)
	DisplayLastMessage();
	return err_code;
}


// load a DAPF file from disk, modify it in memory and then program the dongle
int DoProgramDongleWithMod(char *szFileDAPF) {
	DAPF_HANDLE dapfHandle;
	int dummy1, dummy2, err_code;
	unsigned int dongle_number;
	DINKEYINFO DinkeyInfo;
	LICENCEINFO LicenceInfo[MAX_LICENCES];
	FILEINFO FileInfo[10];
	ALGORITHM Algorithms[MAX_USER_ALGS];
	DATAFILEENC DataFileEnc[MAX_DATA_ENCS];

	// in this case we need to read the DAPF into our structures, so that the DAPF values can be modified
	err_code = ReadDAPFEx(szFileDAPF, &DinkeyInfo, (LICENCEINFO *)&LicenceInfo, (FILEINFO *)&FileInfo, (ALGORITHM *)&Algorithms, (DATAFILEENC *)&DataFileEnc, &dummy1, &dummy2);
	if (err_code != 0) {
		DisplayLastMessage();
		return err_code;
	}

	// patch new values
	LicenceInfo[0].Features = 12345;
	LicenceInfo[0].Execs = 100;
	strcpy(LicenceInfo[0].LicenceName, "fred");

	// get DAPF handle
	dapfHandle = LoadDAPF(&DinkeyInfo, LicenceInfo, FileInfo, Algorithms, DataFileEnc, &err_code);
	if (dapfHandle == NULL) {
		DisplayLastMessage();
		return err_code;
	}

	// program dongle
	err_code = AddProtection(dapfHandle, ACTION_PROGRAM_DONGLE, 0, 0, &dongle_number);

	// Unload DAPF from memory
	UnloadDAPF(&dapfHandle);

	// display message (error or success)
	DisplayLastMessage();
	return err_code;	
}


// load a DAPF file from disk and protect the files specified
// (in practice it is better to protect the files one at a time and output messages as you go along, similar to DinkeyAdd.exe)
// In this example we specify the flag to overwrite any existing output file that might exist.
int DoLockSoftware(char *szFileDAPF) {
	DAPF_HANDLE dapfHandle;
	int err_code;
	unsigned int dummy;

	// load DAPF from File into memory
	dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code);
	if (dapfHandle == NULL) {
		DisplayLastMessage();
		return err_code;
	}

	// program dongle as specified by the DAPF file
	err_code = AddProtection(dapfHandle, ACTION_PROTECT_SOFTWARE, -1, FLAGS_OVERWRITE_OUTPUT, &dummy);

	// Unload DAPF from memory
	UnloadDAPF(&dapfHandle);

	// display message (error or success)
	DisplayLastMessage();
	return err_code;
}


// load a DAPF file from disk and encrypt the shell data files specified
// (in practice it is better to encrypt the files one at a time and output messages as you go along, similar to DinkeyAdd.exe)
// In this example we specify the flag to overwrite any existing output file that might exist.
int DoEncryptShellDataFiles(char *szFileDAPF) {
	DAPF_HANDLE dapfHandle;
	int err_code;

	// load DAPF from File into memory
	dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code);
	if (dapfHandle == NULL) {
		DisplayLastMessage();
		return err_code;
	}

	// program dongle as specified by the DAPF file
	err_code = EncryptShellDataFiles(dapfHandle, -1, FLAGS_OVERWRITE_OUTPUT);

	// Unload DAPF from memory
	UnloadDAPF(&dapfHandle);

	// display message (error or success)
	DisplayLastMessage();
	return err_code;
}


// load a DAPF file from disk and create a Temporary Software Key using the info that the user entered
int DoCreateTempSoftwareKey(char *szFileDAPF, char *szMachineID, char *szExpDay, char *szExpMonth, char *szExpYear) {
	DAPF_HANDLE dapfHandle;
	TEMP_SWKEY_INFO swkey_info;
	int err_code;
	unsigned int machineID = 0;

	// load DAPF from File into memory
	dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code);
	if (dapfHandle == NULL) {
		DisplayLastMessage();
		return err_code;
	}

	// fill out the SWKEY structure from the values the user entered
	swkey_info.size = sizeof(TEMP_SWKEY_INFO);
	if (szMachineID != NULL)
		sscanf(szMachineID, "%x", &machineID);
	swkey_info.machineID = machineID;
	swkey_info.expiry_day = atoi(szExpDay);			
	swkey_info.expiry_month = atoi(szExpMonth);			
	swkey_info.expiry_year = atoi(szExpYear);
	
	// !!!! in this case we just choose Pro Plus. You could load the DAPF file into structures and see which model is selected.
	// If there is more than one model selected you can ask the customer to choose which model they want.
	swkey_info.dongle_model = SWKEY_MODEL_PRO_PLUS;
	swkey_info.dongle_number = 0;				// default

	// create the Temporary Software Key
	err_code = CreateTempSoftwareKey(dapfHandle, &swkey_info, 0);

	// Unload DAPF from memory
	UnloadDAPF(&dapfHandle);

	// display message (error or success)
	DisplayLastMessage();
	return err_code;
}

// load a DAPF file from disk and create a Demo Software Key Template using the info that the user entered
int DoCreateDemoSoftwareTemplate(char *szFileDAPF, char *szMaxDays) {
	DAPF_HANDLE dapfHandle;
	DEMO_SWKEY_INFO swkey_info;
	int err_code;

	// load DAPF from File into memory
	dapfHandle = LoadDAPFFromFile(szFileDAPF, &err_code);
	if (dapfHandle == NULL) {
		DisplayLastMessage();
		return err_code;
	}

	// fill out the SWKEY structure from the values the user entered
	swkey_info.size = sizeof(DEMO_SWKEY_INFO);
	swkey_info.max_days = atoi(szMaxDays);
	
	// !!!! in this case we just choose the default model (assuming you only selected one in the DAPF file).
    // If you want to specify more than one model then OR the flags together. e.g. SWKEY_BITMAP_PRO_LITE | SWKEY_BITMAP_PRO_PLUS
	swkey_info.models = SWKEY_BITMAP_DEFAULT;

	// create the Temporary Software Key
	err_code = CreateDemoSoftwareKeyTemplate(dapfHandle, &swkey_info, 0);

	// Unload DAPF from memory
	UnloadDAPF(&dapfHandle);

	// display message (error or success)
	DisplayLastMessage();
	return err_code;
}


// routine for main dialog box
BOOL CALLBACK MainDlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {            
	char szFileDAPF[256];
	char szMachineID[9], szMaxDays[3];
	char szExpDay[3], szExpMonth[3], szExpYear[5];

	switch (message)
		{
		case WM_INITDIALOG:
			SetDlgItemText(hwnd, IDC_TEMP_EXP_DAY, "dd");
			SetDlgItemText(hwnd, IDC_TEMP_EXP_MONTH, "mm");
			SetDlgItemText(hwnd, IDC_TEMP_EXP_YEAR, "yyyy");
			break;
	
		case WM_COMMAND:
			GetDlgItemText(hwnd, IDC_DAPF_PATH, szFileDAPF, sizeof(szFileDAPF));
			
			// *** Program Dongle button clicked ***
			if (LOWORD(wParam) == IDC_PROGRAM_DONGLE && HIWORD(wParam) == BN_CLICKED) {	
				DoProgramDongle(szFileDAPF);		
			}			

			// *** Program Dongle with Modification button clicked ***
			if (LOWORD(wParam) == IDC_PROGRAM_DONGLE_MOD && HIWORD(wParam) == BN_CLICKED) {
				DoProgramDongleWithMod(szFileDAPF);
			}
			
			// *** Lock Software button clicked ***
			if (LOWORD(wParam) == IDC_LOCK_SOFTWARE && HIWORD(wParam) == BN_CLICKED) {
				DoLockSoftware(szFileDAPF);
			}

			// *** Encrypt Shell Data Files button clicked ***
			if (LOWORD(wParam) == IDC_ENCRYPT_SHELL_DATA_FILES && HIWORD(wParam) == BN_CLICKED) {
				DoEncryptShellDataFiles(szFileDAPF);
			}

			// *** Create Temporary Software Key button clicked ***
			if (LOWORD(wParam) == IDC_CREATE_TEMP_SWKEY && HIWORD(wParam) == BN_CLICKED) {
				GetDlgItemText(hwnd, IDC_MACHINEID, szMachineID, sizeof(szMachineID));
				GetDlgItemText(hwnd, IDC_TEMP_EXP_DAY, szExpDay, sizeof(szExpDay));
				GetDlgItemText(hwnd, IDC_TEMP_EXP_MONTH, szExpMonth, sizeof(szExpMonth));
				GetDlgItemText(hwnd, IDC_TEMP_EXP_YEAR, szExpYear, sizeof(szExpYear));
				DoCreateTempSoftwareKey(szFileDAPF, szMachineID, szExpDay, szExpMonth, szExpYear);
			}			

			// *** Create Demo Software Key Template button clicked ***
			if (LOWORD(wParam) == IDC_CREATE_DEMO_SWKEY && HIWORD(wParam) == BN_CLICKED) {
				GetDlgItemText(hwnd, IDC_DEMO_MAX_DAYS, szMaxDays, sizeof(szMaxDays));
				DoCreateDemoSoftwareTemplate(szFileDAPF, szMaxDays);
			}			
			
			break;
			
		case WM_CLOSE:
			EndDialog(hwnd, TRUE);
		    return TRUE;
		}

	return FALSE;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow ) {
	// display dialog allow user to enter code
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC)MainDlgProc);					// display main screen
   	return 0;
}


// gets & displays the message from the last API call to the DinkeyAdd Module
void DisplayLastMessage(void) {
	char *szMessage;
	int msg_len;

	GetLastMessage(NULL, 0, &msg_len);

	szMessage  = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, msg_len);

	if (szMessage != NULL) {
		GetLastMessage(szMessage, msg_len, NULL);
		MessageBox(NULL, szMessage, g_szAppName, MB_OK);
		HeapFree(GetProcessHeap(), 0, szMessage); 
	}
	return;
}
