工具說明:
此工具是功能是:1)用掃描槍掃描裝置的序列号(如在超市買商品都要掃描一樣),然後序列号會自動寫入到圖中的文本框中,序列号要求是:1、它必須是10位數的。2、每位數是0~9。
當不能掃描時,手動輸入到文本框中,輸入要求如上。
2)将裝置被序列号用指令發送到裝置中去,一共發4條指令,最後一
條指令傳回序列号,與輸入的序列号進行比對,相同則裝置寫入成功。(用到智能卡大師軟體)
3)為了測試人員友善使用,隻要測試人用掃描器掃描,其餘的工作由
工具自動完成。
遇到的難點:1)首先沒有按鈕驅動,在這裡用多線程解決了此問題。
2)在此過程中,遇到了雜七雜八的小問題,大多數都是調試解決。
// ReadShoterDlg.cpp : implementation file
//
#include "stdafx.h"
#include "ReadShoter.h"
#include "ReadShoterDlg.h"
#include <Afxwin.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <STRING>
#include "PCSCReader.h"
#include "ToolFun.h"
#include "softenc.h"
#include "Message.h"
#include "MessageW.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// CAboutDlg dialog used for App About
#define MAX_NUM 30
#define MAXSIZE_20 20
#define MAXSIZE_30 30
#define MaxCount 10
// CPCSCReader g_objReader;
// CStringArray objStrArr;
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()
/
// CReadShoterDlg dialog
CReadShoterDlg::CReadShoterDlg(CWnd* pParent /*=NULL*/)
: CDialog(CReadShoterDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CReadShoterDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CReadShoterDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CReadShoterDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CReadShoterDlg, CDialog)
//{{AFX_MSG_MAP(CReadShoterDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
// ON_BN_CLICKED(IDC_SN_WRITE, OnSnWrite)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CReadShoterDlg message handlers
BOOL CReadShoterDlg::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
// TODO: Add extra initialization here
static int flag = 1;
if(flag==1)
//修改系統資料庫
{
RegeditDevice();
SetRegedit();
flag = 0;
}
//建立子線程
CWinThread *pThread = new CWinThread();
pThread = AfxBeginThread(OnSnWrite,this);
if (pThread == NULL)
{
MessageBox(_T("線程啟動失敗!"));
}
// delete pThread;
return TRUE; // return TRUE unless you set the focus to a control
}
void CReadShoterDlg::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 CReadShoterDlg::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 CReadShoterDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
UINT CReadShoterDlg::OnSnWrite(LPVOID pParam)
{
//線程處理
CReadShoterDlg* pDlg = (CReadShoterDlg*)pParam;
ASSERT(pDlg!=NULL);
// CString strTemp;
byteArray baSN;
char tmp[6];
char zero[10]={0};
//SN數組
char snArray[MAXSIZE_20] = {0};
//廠商代碼
char devid = '\x01';
//預留
char devrfu[MAX_NUM] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
//段内偏移
char devoff[3] = "\x20\x00";
//長度
char devlen = '\x14';
//密鑰
BYTE authkey[17] = {0};
//des傳回資料
unsigned char ucOutBlock[8] = {0};
//随機數存放
BYTE random[8] = {0};
//指令1格式
BYTE array[MAXSIZE_20] = "\xF0\x91\x00\x00\x08";
//指令2格式
//BYTE array1[MAXSIZE_20] = "\xF0\x92\x00\x00\x08";
BYTE array1[MAXSIZE_20] = "\xF0\x00\x00\x00\x08";
//指令3格式
BYTE array2[MAXSIZE_30] = "\xF0\xA2\x01\x00\x17";
//指令4格式
BYTE array3[MAXSIZE_30] = "\xF0\x02\x03\x00\x00";
LPBYTE pcCmdHead;
DWORD dwDataLen;
LPBYTE pbRecv;
LPDWORD pdwRecvLen;
DWORD dwRecvLen;
LPWORD pwSW;
WORD sW;
// DWORD dwSlot;
while(1)
{
CPCSCReader g_objReader;
CStringArray objStrArr;
CString strTemp;
CReadShoterDlg dlg;
CWnd wnd;
Message msg;
//資料合法性判斷
//等待輸入成功
static char lpText[MaxCount];
int f_flag = 0;
// static int statue = 0 ;
pDlg->GetDlgItemText(IDC_SN_NUM,strTemp);
if(strTemp.GetLength()<10)
{
continue;//不滿足十個數字則循環等待滿10個數字
}
if(strTemp.GetLength()==10)
{
Sleep(2000);
pDlg->GetDlgItemText(IDC_SN_NUM,strTemp);//确認一下是否是10個數字
}
if(strTemp.GetLength()>10)
{
AfxMessageBox(_T("請輸入正确數字個數!"));//大于10個提示錯誤并清除
pDlg->SetDlgItemText(IDC_SN_NUM,zero);
continue;
}
memcpy(lpText,strTemp.GetBuffer(0),MaxCount);
for (int j = 0; j<MaxCount; j++)
{
if (!((lpText[j] >='\x30') && (lpText[j] <= '\x39')))
{
AfxMessageBox(_T("請輸入0~9的正确數字!"));
pDlg->SetDlgItemText(IDC_SN_NUM,zero);
f_flag = 1;
break;
}
}
if(f_flag == 1)
continue;
static int flag = 1;
//裝置初始化
if(flag)
{
if (!CPCSCReader::ListPcscReader(objStrArr,CPCSCReader::LPR_TRUST_PAY_PORTABLE))
{
AfxMessageBox(_T("擷取裝置失敗,請插入裝置!"));
g_objReader.DisConnect();
pDlg->SetDlgItemText(IDC_SN_NUM,zero);
continue;
}
std::string strName = "";
int nCount = objStrArr.GetSize();
for (int i=0; i<nCount; i++)
{
std::string strStr= objStrArr.GetAt(i);
strStr = strupr((char*)strStr.c_str());
#ifdef _NT_DEV_
if (strStr.find("NANTIAN") != std::string::npos)
#else
if (strStr.find("TIANYU") != std::string::npos)
#endif
{
strName = strStr;
break;
}
}
if (strName.empty())
{
AfxMessageBox(_T("沒有找到 TIANYU 的裝置!"));
g_objReader.DisConnect();
pDlg->SetDlgItemText(IDC_SN_NUM,zero);
continue;
}
if (!g_objReader.Init(strName.c_str()))
{
AfxMessageBox(_T("初始化裝置失敗!"));
g_objReader.DisConnect();
pDlg->SetDlgItemText(IDC_SN_NUM,zero);
continue;
}
if (!g_objReader.Connect(TRUE))
{
AfxMessageBox(_T("連接配接裝置失敗!"));
g_objReader.DisConnect();
pDlg->SetDlgItemText(IDC_SN_NUM,zero);
continue;
}
flag = 1;
}
// TODO: Add your control notification handler code here
//第一次發送指令
pcCmdHead = array;
// LPBYTE pbData;
dwDataLen = (DWORD)5;
dwRecvLen = (DWORD)MAXSIZE_20;
pbRecv = (BYTE*) malloc(dwRecvLen*sizeof(BYTE));
pdwRecvLen = &dwRecvLen;
pwSW = &sW;
/* if(!(g_objReader.SendCommand(pcCmdHead,dwDataLen,pbRecv,pdwRecvLen,pwSW,dwSlot,0,FALSE)))*/
if(!(g_objReader.SendCommandI(pcCmdHead,dwDataLen,pbRecv,pdwRecvLen,pwSW,TRUE)))
{
AfxMessageBox(_T("指令發送失敗1!"));
g_objReader.DisConnect();
pDlg->SetDlgItemText(IDC_SN_NUM,zero);
continue;
}
// free(pbRecv);
//第二次發送指令
pcCmdHead = array1;
dwDataLen = (DWORD)13;
dwRecvLen = (DWORD)MAXSIZE_20;
pdwRecvLen = &dwRecvLen;
pwSW = &sW;
// pbRecv = (BYTE*) malloc(dwRecvLen*sizeof(BYTE));
//讀取檔案的密鑰id和密鑰
FILE * fd = fopen("key.bin","rb+");
if (fd == NULL)
{
AfxMessageBox(_T("打開key檔案失敗!"));
return -1;
}
memset(authkey,0,sizeof(authkey));
if(fread(authkey,17,1,fd) < 1)
{
AfxMessageBox(_T("讀取key失敗!"));
return -1;
}
fclose(fd);
array1[1] = authkey[0];//密鑰id = 0x02;
//去随機數
memset(random,0,sizeof(random));
memcpy(random,pbRecv,sizeof(random));
DES_EDE_Encryption cipher(authkey+1);//3des加密密鑰
cipher.ProcessBlock(random,ucOutBlock);
memcpy(array1+5,ucOutBlock,sizeof(ucOutBlock));
if(!(g_objReader.SendCommandI(pcCmdHead,dwDataLen,pbRecv,pdwRecvLen,pwSW,TRUE)))
{
AfxMessageBox(_T("指令發送失敗2!"));
g_objReader.DisConnect();
pDlg->SetDlgItemText(IDC_SN_NUM,zero);
continue;
}
//第3次發送指令
pcCmdHead = array2;
// dwDataLen = (DWORD)28;
dwRecvLen = (DWORD)MAXSIZE_30;
pdwRecvLen = &dwRecvLen;
pwSW = &sW;
// pDlg->GetDlgItemText(IDC_SN_NUM,strTemp);
StrToHex(strTemp.GetBuffer(0),strTemp.GetLength(),baSN);
dwDataLen = (DWORD)(23+baSN.GetSize());
for (int i = 0; i <baSN.GetSize(); i++)
{
snArray[i] = *((BYTE*)(baSN.GetData()+i));
}
memcpy(array2+5,devoff,strlen(devoff));
array2[7] = devlen;
memcpy(array2+8,devrfu,strlen(devrfu));
array2[22] = devid;
memcpy(array2+23,snArray,baSN.GetSize());
if(!(g_objReader.SendCommandI(pcCmdHead,dwDataLen,pbRecv,pdwRecvLen,pwSW,TRUE)))
{
AfxMessageBox(_T("指令發送失敗3!"));
g_objReader.DisConnect();
pDlg->SetDlgItemText(IDC_SN_NUM,zero);
continue;
}
//第4次發指令
pcCmdHead = array3;
dwDataLen = (DWORD)5;
dwRecvLen = (DWORD)MAXSIZE_30;
pdwRecvLen = &dwRecvLen;
// pwSW = &sW;
if(!(g_objReader.SendCommandI(pcCmdHead,dwDataLen,pbRecv,pdwRecvLen,pwSW,TRUE)))
{
AfxMessageBox(_T("指令發送失敗4!"));
g_objReader.DisConnect();
pDlg->SetDlgItemText(IDC_SN_NUM,zero);
continue;
}
memcpy(tmp,pbRecv+15,baSN.GetSize());
if(strncmp(snArray,tmp,5)==0)
{
dlg.MessageboxDlgRight();
// AfxMessageBox(_T("√"));
// Sleep(3000);
// HWND hwnd = ::FindWindow(NULL,"ReadShoter");
}
else
{
// AfxMessageBox(_T("×"));
dlg.MessageboxDlgWrong();
}
//清除輸入框
pDlg->SetDlgItemText(IDC_SN_NUM,zero);
free(pbRecv);
g_objReader.DisConnect();
}
delete pDlg;
return 0;
}
void CReadShoterDlg::MessageboxDlgRight()
{
// 模态
// Message msg;
// msg.DoModal();
//非模态
Message *pMsg = new Message;
pMsg->Create(IDD_Message_DIALOG,NULL);
pMsg->ShowWindow(SW_SHOWNORMAL);
pMsg->UpdateWindow();
Sleep(2000);
pMsg->SendMessage(WM_CLOSE);
delete pMsg;
}
void CReadShoterDlg::MessageboxDlgWrong()
{
// 模态
// Message msg;
// msg.DoModal();
//非模态
Message *pMsg = new Message;
pMsg->Create(IDD_MSG_WRONG,NULL);
pMsg->ShowWindow(SW_SHOWNORMAL);
pMsg->UpdateWindow();
Sleep(3000);
pMsg->SendMessage(WM_CLOSE);
delete pMsg;
}
/************************************************************************/
/* 函數功能:設定系統資料庫鍵值 */
/* 入參: 無 */
/* */
/* 出參: 無 */
/* 傳回值: 無 */
/* */
/************************************************************************/
void CReadShoterDlg::SetRegedit()
{
HKEY hKey = 0;
HKEY hSubKey = 0;
DWORD dwKeyValue = 1;
DWORD dwSize =0;
DWORD dwValue = 0;
// char* pchPath = "SYSTEM\\CurrentControlSet\\Enum\\USB\\Vid_1a2c&Pid_0002&MI_00";
char acTemp[MAX_PATH] = {0};//\\5&2c5c6891&0&4\\Device Parameters";
DWORD dwTempLen = 0;
char abSubKeyName[MAX_PATH] = {0};
DWORD dwSubKeyNameLen = 0;
DWORD i = 0;
DWORD dwRet = 0;
DWORD dwFlagModify = 0;
TCHAR athPchPath[MAX_PATH] = {0};
CString strMidVar;
BOOL m_bFirstFlag;
if (m_strarrMidVar.GetSize()==0)
{
AfxMessageBox("CCID讀卡器,設定系統資料庫鍵值失敗!");
}
for (int j = 0; j < m_strarrMidVar.GetSize(); j++)
{
strMidVar = m_strarrMidVar.GetAt(j);
strcpy(athPchPath,strMidVar.GetBuffer(0));
RegCreateKey(HKEY_LOCAL_MACHINE,athPchPath,&hKey);
if( !hKey )
{
AfxMessageBox("CCID讀卡器,設定系統資料庫鍵值失敗!");
return ;
}
i = 0;
while(1)
{
dwTempLen = sizeof(acTemp);
memset(acTemp,0,dwTempLen);
dwSubKeyNameLen = sizeof(abSubKeyName);
memset(abSubKeyName,0,dwSubKeyNameLen);
if( ERROR_SUCCESS != RegEnumKeyEx(
hKey, i++,abSubKeyName,&dwSubKeyNameLen, 0,0, 0,0) ||!sprintf(acTemp,"%s\\%s\\Device Parameters",athPchPath,abSubKeyName) ||ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE,acTemp,&hSubKey) )
{
if(hSubKey)
{
RegCloseKey(hSubKey);
}
hSubKey = 0;
break;
}
if(ERROR_SUCCESS != RegQueryValueEx(hSubKey,"EscapeCommandEnable",0,NULL,NULL,&dwSize))
{
m_bFirstFlag = TRUE;
// AfxMessageBox("由于您是第一次使用本裝置,本裝置将進行相關的初始化設定,請稍後...");
// GetDlgItem(IDC_DOWNLOAD_BUTTON)->EnableWindow(FALSE);
Sleep(3000);
}
else if(ERROR_SUCCESS == RegQueryValueEx(hSubKey,"EscapeCommandEnable",0,NULL,(unsigned char*)&dwValue,&dwSize))
{
if (1 != dwValue)
{
m_bFirstFlag = TRUE;
// AfxMessageBox("由于您是第一次使用本裝置,本裝置将進行相關的初始化設定,請稍後...");
// GetDlgItem(IDC_DOWNLOAD_BUTTON)->EnableWindow(FALSE);
Sleep(3000);
}
else
{
m_bFirstFlag = FALSE;
}
}
else
{
m_bFirstFlag = FALSE;
}
dwRet = RegSetValueEx(hSubKey,"EscapeCommandEnable",0,REG_DWORD,(unsigned char*)&dwKeyValue,sizeof(dwKeyValue));
}
}
if(hSubKey)
{
RegCloseKey(hSubKey);
}
hSubKey = 0;
}
/************************************************************************/
/* 函數功能:添加系統資料庫項 */
/* 入參: 無 */
/* */
/* 出參: 無 */
/* 傳回值: 無 */
/* */
/************************************************************************/
void CReadShoterDlg::RegeditDevice()
{
HANDLE hToken = NULL;
CString strPchPath1;
CString strPchPath2;
CString strPchPath3;
CString strPchPath;
strPchPath1 = _T("SYSTEM\\CurrentControlSet\\Enum\\USB\\Vid_a625&Pid_0902");
strPchPath2 = _T("SYSTEM\\CurrentControlSet\\Enum\\USB\\Vid_a625&Pid_0902&MI_00");
strPchPath3 = _T("SYSTEM\\CurrentControlSet\\Enum\\USB\\Vid_a625&Pid_0902&MI_01");
m_strarrMidVar.Add(strPchPath1);
m_strarrMidVar.Add(strPchPath2);
m_strarrMidVar.Add(strPchPath3);
SetRegedit();
//StartInteractiveClientProcess(NULL, NULL, NULL, NULL, hToken);
}
以上是個人的工作小節,寫的可能自有自己能看懂。。。。。