工具说明:
此工具是功能是: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); }
以上是个人的工作小节,写的可能自有自己能看懂。。。。。