// Test_KeyChkDlg.cpp : implementation file
//

// Set old Windows system supported - Windows XP with SP2.
#define _WIN32_WINNT 0x0502

#include "stdafx.h"
#include "Test_KeyChk.h"
#include "Test_KeyChkDlg.h"
#include "Scb.h"

SCB scb;

extern "C" __declspec(dllimport) void WINAPI KeyChk( SCB *lpSCB );

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTest_KeyChkDlg dialog

CTest_KeyChkDlg::CTest_KeyChkDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTest_KeyChkDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CTest_KeyChkDlg)
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CTest_KeyChkDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CTest_KeyChkDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CTest_KeyChkDlg, CDialog)
	//{{AFX_MSG_MAP(CTest_KeyChkDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(ID_DOKEYCHK1, OnButton1Click)
    ON_BN_CLICKED(ID_DOKEYCHK2, OnButton2Click)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTest_KeyChkDlg message handlers

BOOL CTest_KeyChkDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

    // Set the Window Title and Button text to indicate Win32 or x64 version.
#ifndef _WIN64
    CTest_KeyChkDlg::SetWindowText(L"EverKey C++ .Net4 MFC Example Program Using KeyChk.dll");
#else
    CTest_KeyChkDlg::SetWindowText(L"EverKey C++ .Net4 MFC Example Program Using KeyChk64.dll");
#endif

    // Set the screen fields of "Product-ID" and "Product PIN" to show the
    //   values that were used by KeyBuild to build the Examples Key.
    // These values will be copied to the SCB before calling the KeyChk DLL.
	SetDlgItemText(IDC_PROD_ID_TO_USE, L"Examples");
	SetDlgItemText(IDC_PROD_PIN_TO_USE, L"375391873");

    // Set the "Uses Limit Update" screen field to "-1" as the Default.
    //   This is how many Uses will be taken away from the Key's current Limit
    //     when KeyChk Function 2 is done.
	SetDlgItemText(IDC_USES_LIMIT_UPDATE, L"-1");

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CTest_KeyChkDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CTest_KeyChkDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CTest_KeyChkDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CTest_KeyChkDlg::OnButton1Click()
{
    // Button 1 was just Clicked.
    //
    // Call the Do_KeyChk_Call() function specifying '1'.
    //
    // That will call KeyChk to:
    //   Verify the presence of the Key with this Product-ID and PIN.

	CTest_KeyChkDlg::Do_KeyChk_Call(1);
}

void CTest_KeyChkDlg::OnButton2Click()
{
    // Button 2 was just Clicked.
    //
    // Call the Do_KeyChk_Call() function specifying '2'.
    //
    // That will call KeyChk to:
    //   Verify the presence of the Key with this Product-ID and PIN
    //     AND Update the Uses Limit of the Key.

	CTest_KeyChkDlg::Do_KeyChk_Call(2);
}

void CTest_KeyChkDlg::Do_KeyChk_Call(UINT keychk_func)
{
    // This function setups the SCB and calls the KeyChk DLL.
    //
    // The Caller has set the keychk_func parameter to the
    //     KeyChk Function to use.

    HCURSOR     hSaveCursor;
    WCHAR       szText[81], szWork1[81], szWork2[81];
    size_t      size;
    byte        utf8_bytes[21];

	// Zero the SCB structure.
	memset( &scb, 0, sizeof( SCB ) );

    // Start by checking that the size of the SCB Structure is correct.
    //   Test programs are sometimes used to experiment...
    size = sizeof(scb);
    if ( size != 512 )
    {
    	wsprintf(szText,
                 L"Size of SCB Structure Must Be 512 Bytes.\n"
                 L"    It's size is currently %d Bytes.",
                 size );
        MessageBox( szText,
                    (LPCWSTR)L"KeyChk DLL Test Error",
                    MB_OK );
        return;
    }

    // Before calling KeyChk, set the SCB Error Code to "SCB Not Found".
    //   If, for some reason, KeyChk can't find the SCB memory block,
    //   it will not be able to access and set the "err_code" SCB field.
    //   Pre-Setting this error code allows us to know if this happened.
    scb.err_code = 0x6240;

    // Before calling KeyChk, set the "func_code" SCB field
    //   to what the Caller passed to us in the "keychk_func" parameter.
    scb.func_code = keychk_func;

    // Before calling KeyChk, initialize the "scb_id" SCB field so
    //   KeyChk will know that it's using the correct memory block.
    strncpy_s(scb.scb_id, 5, "Kc.6", 4);

    // Before calling KeyChk, set the "prod_id" SCB field to "Examples"
    //   since this is the Product-ID of the Examples Key.
    //   The "Product-ID" screen field has already been set to "Examples".
    // This field must match the Product-ID of the Key that you want to find.
    //   In your Source Code, you would set this field to the Product-ID
    //     of your Product. This is shown on the KeyBuild "Build Keys" panel.
    // The Product-ID is a zero-terminated, case-sensitive, UTF8 Unicode field.
    GetDlgItemText(IDC_PROD_ID_TO_USE, szText, sizeof(szText));
    size = WideCharToMultiByte( CP_UTF8, 0, szText, -1, (LPSTR)utf8_bytes, sizeof(utf8_bytes), NULL, NULL );
    // Copy the UTF8 bytes into Product-ID SCB field.
    for (int i = 0; i < sizeof(scb.prod_id); i++)
        scb.prod_id[i] = utf8_bytes[i];

    // Before calling KeyChk, set the "Serial Number" field to Zero
    //   to skip the validation of the Key's Serial Number.
    // Normally, you will set the "prod_serial" SCB field to zero so
    //   the Key check will succeed as long as KeyChk finds a Key
    //   with your specific Product-ID and Product PIN.
    //   In this case, the Serial Number of the Key found
    //     will be returned in the "prod_serial" SCB field.
    // If you want to verify that the Key present has a
    //   specific Product Serial Number, then set this field to
    //   the specific Serial Number that you want to verify.
    scb.prod_serial = 0;

    // Before calling KeyChk, set the "Prod_PIN" SCB field to "375391873"
    //   since this is the Product PIN of the Examples Key.
    //   The "Product PIN" screen field has already been set to "375391873".
    // This field must match the Product PIN of the Key that you want to find.
    //   In your Source Code, you would set this field to the Product PIN
    //     of your Product. This is shown on the KeyBuild "Build Keys" panel.
    GetDlgItemText(IDC_PROD_PIN_TO_USE, szText, sizeof(szText));
    scb.prod_pin = wcstoul(szText, NULL, 10);
    if ( (scb.prod_pin == 0) || (scb.prod_pin == 0xFFFFFFFF) )
    {
        MessageBox( L"Product PIN Must Be From 1 to 4,294,967,295.",
                    L"KeyChk DLL Test Error",
                    MB_OK );
        return;
    }

    // Before calling KeyChk, copy the "Uses Limit Update" screen field
    //   to the "Uses_Limit" SCB field.
    // NOTE: The Uses Limit of the Key is only updated
    //       if KeyChk Function 2 or 3 is used.
    // To update the Uses Limit of the Key from this Example program,
    //   set the "Uses Limit Update" screen field to '-1', '-2' or '-3'
    //   and then click the "Do KeyChk Function 2" button.
    GetDlgItemText(IDC_USES_LIMIT_UPDATE, szText, sizeof(szText));
    scb.uses_limit = LOWORD(wcstol(szText, NULL, 10));
    if ( (scb.uses_limit < -3) || (scb.uses_limit > -1) )
    {
        MessageBox( L"Uses Limit Update Must Be '-1', '-2' or '-3'.",
                    L"KeyChk DLL Test Error",
                    MB_OK );
        return;
    }

    // Before calling KeyChk,
    //   clear out all the screen field results from the last run.
    SetDlgItemText(IDC_KEYCHK_RESULT, L"");
    SetDlgItemText(IDC_ERR_CODE, L"");
    SetDlgItemText(IDC_PROD_SERIAL, L"");
    SetDlgItemText(IDC_USES_LIMIT, L"");
    SetDlgItemText(IDC_TIME_LIMIT, L"");
    SetDlgItemText(IDC_EXPIRE_DATE, L"");
    SetDlgItemText(IDC_EXPIRE_TIME, L"");
    SetDlgItemText(IDC_USER_DATA, L"");
    SetDlgItemText(IDC_FEATURE_FLAGS, L"");
    SetDlgItemText(IDC_LASERED_ID, L"");
    SetDlgItemText(IDC_KEY_TYPE, L"");
    SetDlgItemText(IDC_REG_NAME, L"");
    SetDlgItemText(IDC_REG_COMPANY, L"");
    SetDlgItemText(IDC_REG_OTHER, L"");

    // Save the current cursor and then set it to the hourglass (waiting) cursor
    //   to let the User know we are doing something.
    hSaveCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

    // Call the KeyChk DLL using the values setup in the SCB.
    //   This will check for the presence of the Key that matches
    //     the Product-ID and Product PIN fields.
    // If the Key is found, all the information from the Key will
    //   be returned in the SCB.
    KeyChk( &scb );

    // Restore the original cursor.
    SetCursor(hSaveCursor);

    // Display the Result of the Key Check operation.
    if (scb.err_code == 0)
        SetDlgItemText(IDC_KEYCHK_RESULT, L" The Key was Found and is Not Expired.");
    else if (scb.err_code == 0x6043)
        SetDlgItemText(IDC_KEYCHK_RESULT, L" The Key was Not Found.");
    else if (scb.err_code == 0x6142)
        SetDlgItemText(IDC_KEYCHK_RESULT, L" The Key was Found but the Uses Limit is Expired.");
    else if (scb.err_code == 0x6143)
        SetDlgItemText(IDC_KEYCHK_RESULT, L" The Key was Found but the Time Limit is Expired.");
    else
        SetDlgItemText(IDC_KEYCHK_RESULT, L" The Key Check Failed and the Error Code will Explain why.");

    // Display the full Error Code in Hexadecimal.
	wsprintf(szText, L" %04X-%04X-%04X", scb.err_code, scb.err_status1, scb.err_status2);
	SetDlgItemText(IDC_ERR_CODE, szText);

    // If there was any Error besides "Expired", we don't need
    //   to show the Key's Information since it's probably Invalid.
    //
    // So, only show the Key's Information if the Error Code is:
    //        0 - The Key was Found and is Not Expired.
    //   0x6142 - The Key was Found but the Uses Limit is Expired.
    //   0x6143 - The Key was Found but the Time Limit is Expired.
    if ((scb.err_code != 0) && (scb.err_code != 0x6142) && (scb.err_code != 0x6143))
        return;

	// Display the Product Serial Number.
	wsprintf(szText, L" %lu", scb.prod_serial);
	SetDlgItemText(IDC_PROD_SERIAL, szText);

    // Display the current Uses Limit.
    if (scb.err_code == 0x6142)
		wsprintf(szText, L" Expired");
    else if (scb.uses_limit == -1)
		wsprintf(szText, L" Unlimited");
    else if (scb.uses_limit == 0)
		wsprintf(szText, L" On Last Use");
    else
        wsprintf(szText, L" %u", scb.uses_limit);
	SetDlgItemText(IDC_USES_LIMIT, szText);

    // Display the current Time Limit.
    if (scb.err_code == 0x6143)
		wsprintf(szText, L" Expired");
    else if (scb.time_limit == 0xFFFF)
		wsprintf(szText, L" Unlimited");
    else if (scb.time_limit == 0)
		wsprintf(szText, L" On Last Day");
    else
        wsprintf(szText, L" %d Day(s)", scb.time_limit);
	SetDlgItemText(IDC_TIME_LIMIT, szText);

	// Display the Expire-Date (Local Time Zone, Unicode).
	wsprintf(szText, L" %s", scb.expire_date);
	SetDlgItemText(IDC_EXPIRE_DATE, szText);

	// Display the Expire-Time (Local Time Zone, Unicode).
	wsprintf(szText, L" %s", scb.expire_time);
	SetDlgItemText(IDC_EXPIRE_TIME, szText);

    // Display the User-Data.
    wsprintf(szText,
		     L" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
             scb.user_data[0], scb.user_data[1], scb.user_data[2], scb.user_data[3],
             scb.user_data[4], scb.user_data[5], scb.user_data[6], scb.user_data[7],
             scb.user_data[8], scb.user_data[9], scb.user_data[10], scb.user_data[11],
             scb.user_data[12], scb.user_data[13], scb.user_data[14], scb.user_data[15]);
	SetDlgItemText(IDC_USER_DATA, szText);

    // Display the Feature-Flags.
    if (scb.feature_flags == 0)
		wsprintf(szWork1, L" None ");
    else
    {
        // Build a string showing all Feature-Flags that are set ON.
		wsprintf(szWork1, L"");             // Start with empty work string.
        WORD ff_test_bit = 0x0001;          // Setup to test 1st Feature-Flag.
        for (int j = 0; j < 16; j++)
        {
    		wsprintf(szWork2, L"%d", j+1);  // Convert current test flag number to string.
            if ((ff_test_bit & scb.feature_flags) != 0)         // If this FF is ON...
            {
                wsprintf(szText, L"%s%s ", szWork1, szWork2);   // Add FF to string.
                wsprintf(szWork1, szText);                      // Copy back to work string.
            }
            ff_test_bit <<= 1;              // Setup to test next Feature-Flag.
        }
    }
    // Also show the Feature-Flags Word Field (Hex).
    wsprintf(szText, L" %s (0x%04X)", szWork1, scb.feature_flags);
	SetDlgItemText(IDC_FEATURE_FLAGS, szText);

    // Display the Lasered-ID.
    wsprintf(szText,
		     L" %02X %02X %02X %02X %02X %02X %02X %02X",
             scb.lasered_id[0], scb.lasered_id[1], scb.lasered_id[2], scb.lasered_id[3],
             scb.lasered_id[4], scb.lasered_id[5], scb.lasered_id[6], scb.lasered_id[7]);
	SetDlgItemText(IDC_LASERED_ID, szText);

    // Display the Key Type of Device determined by the Lasered-ID.
	if(scb.lasered_id[0] == 0xE1)
		SetDlgItemText(IDC_KEY_TYPE, L" Rockey4");
	else if(scb.lasered_id[0] == 0xE2)
		SetDlgItemText(IDC_KEY_TYPE, L" Rockey4ND");
	else
		SetDlgItemText(IDC_KEY_TYPE, L" Unknown");

    // Display the Registered Name (Unicode).
    wsprintf(szText, L" %s", scb.reg_name);
	SetDlgItemText(IDC_REG_NAME, szText);

    // Display the Registered Company (Unicode).
    wsprintf(szText, L" %s", scb.reg_company);
	SetDlgItemText(IDC_REG_COMPANY, szText);

    // Display the Registered Other Info (Unicode).
    wsprintf(szText, L" %s", scb.reg_other);
	SetDlgItemText(IDC_REG_OTHER, szText);
}

// End of Source File.
