在好例子网,分享、交流、成长!
您当前所在位置:首页C/C++ 开发实例桌面应用界面/GUI → CRT-571-V10 IC卡发卡机软件

CRT-571-V10 IC卡发卡机软件

桌面应用界面/GUI

下载此实例
  • 开发语言:C/C++
  • 实例大小:0.20M
  • 下载次数:23
  • 浏览次数:785
  • 发布时间:2015-04-24
  • 实例类别:桌面应用界面/GUI
  • 发 布 人:kongxa2008
  • 文件格式:.rar
  • 所需积分:2
 相关标签: IC卡 发卡机

实例介绍

【实例简介】
【实例截图】

【核心代码】


#include "stdafx.h"
#include "dcic32.h"
#include "CICcard.h"

byte gstrPIN[] = {0x63 , 0x18 , 0x78 , 0x52 , 0x26 , 0x99 , 0x83 , 0x07 };
byte gstrver[]={ (byte)'B' , (byte)'K' , 0x00 , 0x01};
byte gdefPIN1[]=  { 0x31, 0x32, 0x33, 0x34, 0xFF, 0xFF, 0xFF, 0xFF };
byte gdefPIN2[]=  { 0x35, 0x36, 0x37, 0x38, 0xFF, 0xFF, 0xFF, 0xFF };
byte gstrPIN1[]= { 0x32, 0x36, 0x39, 0x39, 0x38, 0x33, 0x30, 0x37 };
byte gstrPIN2[]=  { 0x32, 0x36, 0x39, 0x39, 0x38, 0x33, 0x30, 0x37 };

byte gdefPUK1[]=  { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 };
byte gdefPUK2[]=  { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 };

byte gnewPUK1[]=  { 0x32, 0x36, 0x39, 0x39, 0x38, 0x33, 0x30, 0x37 };
byte gnewPUK2[]=  { 0x32, 0x36, 0x39, 0x39, 0x38, 0x33, 0x30, 0x37 };

CICcard::CICcard()
{
	icdev = 0;
	st  = 0;
	ic_type=-1;
	ICerror = 0;
	ICstate = -1;
	iPrgAuth = -1;
	
	gCardType = -1;
	icdev=NULL;
}

CICcard::~CICcard()
{
	Close();
}

/// <summary>
/// 校验个人密码
/// </summary>
/// <param name="keyleft">控制密码左8位</param>
/// <param name="keyleft">控制密码右8位</param>
/// <returns></returns>
short CICcard::IC_VerifyPIN(byte* CtlKey , byte* strPIN)
{
	byte Randdata_hex[64];
	byte keyright[8];
	byte sedata[64];
	byte relen = 0;
	byte outbuf[64];
	short st;
	
	if (gCardType == 0)
	{
		//1.取随机数
		st = IC_GetChallenge(Randdata_hex);
		if (st != 0)
		{
			//error
			ICerror = 201;
			return -1;
		}
		IC_Strcat(keyright, 0, CtlKey, 8, 8);
		//3.算密钥
		/*8字节PIN密文计算方法:使用16字节3DES控制密钥(初始值为全FF)
		* 对8字节随机数加密得到8字节密文数据作为过程密钥;用这个过程密钥
		* 对8字节PIN原文(初始值为8字节唯一芯片序列号,可以通过Reset PIN指令重置,
		* 11 11 11 11 11 11 11 11)进行DES加密得到8字节PIN密文。*/
		byte temp1[64];
		byte temp2[64];
		st = IC_DES3(CtlKey, keyright, Randdata_hex, temp1);
		st = IC_Encrypt((char*)temp1, (char*)strPIN, 8, (char*)temp2);
		//sedata=sedata   temp2;
		if (st != 0)
		{
			//error
			ICerror = 201;
			return -1;
		}
		//4.认证密钥
		//00200008
		sedata[0] = 0;
		sedata[1] = 0x20;
		sedata[2] = 0;
		sedata[3] = 0;
		sedata[4] = 8;
		sedata[5] = 0;
		IC_Strcat(sedata, 5, temp2, 0, 8);
		st = IC_CpuApdu(icdev, 13, sedata, &relen, outbuf);
		if ((st != 0)||(outbuf[0]!=0x90))
		{
			//error
			ICerror = 202;
			return -1;
		}
	}
	else
	{
		
		if (CtlKey[0] == 1)
		{
			//验证PIN1
			//A0 20 00 01 08
			sedata[0] = 0xA0;
			sedata[1] = 0x20;
			sedata[2] = 0;
			sedata[3] = 1;
			sedata[4] = 8;
			sedata[5] = 0;
			IC_Strcat(sedata, 5, strPIN, 0, 8);
			st = IC_CpuApdu(icdev, 13, sedata, &relen, outbuf);
			if ((st != 0)||(outbuf[0]!=0x90))
			{
				//error
				ICerror = 202;
				return -1;
			}
		}
		else if (CtlKey[0] == 2)
		{
			//验证PIN2
			//A0 20 00 02 08
			sedata[0] = 0xA0;
			sedata[1] = 0x20;
			sedata[2] = 0;
			sedata[3] = 2;
			sedata[4] = 8;
			sedata[5] = 0;
			IC_Strcat(sedata, 5, strPIN, 0, 8);
			st = IC_CpuApdu(icdev, 13, sedata, &relen, outbuf);
			if ((st != 0) || (outbuf[0] != 0x90))
			{
				//error
				ICerror = 202;
				return -1;
			}
		}
    }
	return 0;
	
}

// / <summary>
// / 选择IC卡文件
// / </summary>
// / <param name="fileid">文件ID</param>
// / <returns>0 成功</returns>
short CICcard::IC_SelectFile(unsigned short offset)
{
	byte relen = 0;
	byte tempbuf[128];
	short st;
	
	if (gCardType == 1)
	{
		//组成命令
		//A0A40000021F00
		byte sedata[64];
		sedata[0] = 0xa0;
		sedata[1] = 0xa4;
		sedata[2] = 0x00;
		sedata[3] = 0x00;
		sedata[4] = 0x02;
		sedata[5] = 0x1f;
		sedata[6] = 0x00;
		
		if (offset < (20 * 1024))
		{
			sedata[6] = (byte)(offset / (4 * 1024));
		}
		else
		{
			sedata[6] = (byte)(5   (offset - (20 * 1024)) / 3584);//(3.5 * 1024);
		}
		st = IC_CpuApdu(icdev, 7, sedata, &relen, tempbuf);
		// || (tempbuf[0] != 0x90))
		if (st != 0)
		{
			//error
			ICerror = 301;
			return -1;
		}
	}
	
	return 0;
}

short CICcard::IC_EnablePIN(byte PINtype,byte* newPIN)
{
	byte relen = 0;
	byte tempbuf[128];
	short st;
	
	if (gCardType == 1)
	{
		//组成命令
		//A028000108
		byte sedata[64];
		sedata[0] = 0xa0;
		sedata[1] = 0x28;
		sedata[2] = 0x00;
		sedata[3] = PINtype;
		sedata[4] = 0x08;
		
		IC_Strcat(sedata, 5, newPIN, 0, 8);
		
		st = IC_CpuApdu(icdev, 13, sedata, &relen, tempbuf);
		// || (tempbuf[0] != 0x90))
		if (st != 0)
		{
			//error
			ICerror = 301;
			return -1;
		}
	}
	
	return 0;
}
/// <summary>
/// 解锁IC卡密码
/// </summary>
/// <param name="newPIN">解锁新PIN密钥</param>
/// <returns>0 成功</returns>
short CICcard::IC_UnblockPIN(byte PINtype, byte* newPUK, byte* newPIN)
{
	byte relen = 0;
	byte tempbuf[128];
	short st;
	
	if (gCardType == 1)
	{
		//组成命令
		//A02C000x10
		byte sedata[64];
		sedata[0] = 0xa0;
		sedata[1] = 0x2c;
		sedata[2] = 0x00;
		sedata[3] = PINtype;
		sedata[4] = 0x10;
		
		IC_Strcat(sedata, 5, newPUK, 0, 8);
		IC_Strcat(sedata, 13, newPIN, 0, 8);
		
		st = IC_CpuApdu(icdev, 21, sedata, &relen, tempbuf);
		// 
		if ((st != 0)|| (tempbuf[0] != 0x90))
		{
			//error
			ICerror = 301;
			return -1;
		}
	}
	
	return 0;
}
/// <summary>
/// 读IC卡数据
/// </summary>
/// <param name="offset">偏移</param>
/// <param name="len">读取长度</param>
/// <param name="buf">输出数据缓存</param>
/// <returns></returns>
short CICcard::IC_ReadData( unsigned short offset , unsigned short len , byte* buf )
{
	int rlen=0;
	byte relen = 0;
	byte tempbuf[512];
	short st;
	
	if (gCardType == 0)
	{
		//组成命令
		byte sedata[64];
		sedata[0] = 0;
		sedata[1] = 0xb0;
		while (rlen < len)
		{
			if ((len - rlen) > 112)
			{
				/*循环取数据*/
				sedata[2] = (byte)((((offset   rlen)) >> 8) & 0xFF);
				sedata[3] = (byte)((offset   rlen) & 0xFF);
				sedata[4] = 112;
				sedata[5] = 0;
				st = IC_CpuApdu(icdev, 5, sedata, &relen, tempbuf);
				if ((st != 0) || (tempbuf[relen-2] != 0x90))
				{
					//error
					ICerror = 301;
					return -1;
				}
				
				tempbuf[relen - 2] = 0;
				IC_Strcat(buf, rlen, tempbuf, 0, relen - 2);
				rlen  = 112;
			}
			else
			{
				/*循环取数据*/
				sedata[2] = (byte)((((offset   rlen)) >> 8) & 0xFF);
				sedata[3] = (byte)((offset   rlen) & 0xFF);
				sedata[4] = (byte)(len - rlen);
				sedata[5] = 0;
				st = IC_CpuApdu(icdev, 5, sedata, &relen, tempbuf);
				if ((st != 0) || (tempbuf[relen-2] != 0x90))
				{
					//error
					ICerror = 301;
					return -1;
				}
				//去除返回码
				
				tempbuf[relen - 2] = 0;
				IC_Strcat(buf, rlen, tempbuf, 0, relen - 2);
				break;
			}
		}
	}
	else
	{
	
		byte packetlen = 250;
		
		//当前偏移
		unsigned short curoffset = offset;
		byte isneedselectfile = 1;
		
		//本次循环OFFSET
		unsigned short fileoffset = 0;
		byte curreadlen = 0;
		
		//组成命令
		// A0B0000010
		byte sedata[64];
		sedata[0] = 0xa0;
		sedata[1] = 0xb0;
		while (rlen < len)
		{
			//判断是否重新选择文件
			if (isneedselectfile == 1)
			{
				IC_SelectFile(curoffset);
				isneedselectfile = 0;
			}
			
			if ((len - rlen) > packetlen)
			{
				//取得相对文件内部的offset
				if (curoffset < (20 * 1024))
				{
					fileoffset = (unsigned short)(curoffset % (4 * 1024));
					curreadlen = packetlen;
					//是否超出文件边界
					if ((fileoffset   packetlen) >= (4 * 1024))
					{
						curreadlen = (byte)((4 * 1024) - fileoffset);
						isneedselectfile = 1;
					}
					
				}
				else
				{
					fileoffset = (unsigned short)((curoffset - (20 * 1024)) % 3584);//(3.5 * 1024);
					curreadlen = packetlen;
					//是否超出文件边界
					if ((fileoffset   packetlen) >= (3584))
					{
						curreadlen = (byte)((3584) - fileoffset);
						isneedselectfile = 1;
					}
				}
				
				/*循环取数据*/
				sedata[2] = (byte)((((fileoffset )) >> 8) & 0xFF);
				sedata[3] = (byte)((fileoffset ) & 0xFF);
				sedata[4] = curreadlen;
				sedata[5] = 0;
				st = IC_CpuApdu(icdev, 5, sedata, &relen, tempbuf);
				//if ((st != 0) || (tempbuf[0] != 0x90))
				if (st != 0)
				{
					//error
					ICerror = 301;
					return -1;
				}
				
				tempbuf[relen - 2] = 0;
				IC_Strcat(buf, rlen, tempbuf, 0, relen - 2);
				rlen  = curreadlen;
				curoffset  = curreadlen;
				
			}
			else
			{
				//取得相对文件内部的offset
				if (curoffset < (20 * 1024))
				{
					fileoffset = (unsigned short)(curoffset % (4 * 1024));
					curreadlen = (byte)(len - rlen);
					//是否超出文件边界
					if ((fileoffset   (len - rlen)) >= (4 * 1024))
					{
						curreadlen = (byte)((4 * 1024) - fileoffset);
						isneedselectfile = 1;
					}
					
				}
				else
				{
					fileoffset = (unsigned short)((curoffset - (20 * 1024)) % 3584);//(3.5 * 1024);
					curreadlen = (byte)(len - rlen);
					//是否超出文件边界
					if ((fileoffset   (len - rlen)) >= (3584))
					{
						curreadlen = (byte)((3584) - fileoffset);
						isneedselectfile = 1;
					}
				}
				
				/*循环取数据*/
				sedata[2] = (byte)((((fileoffset  )) >> 8) & 0xFF);
				sedata[3] = (byte)((fileoffset ) & 0xFF);
				sedata[4] = (byte)(curreadlen);
				sedata[5] = 0;
				st = IC_CpuApdu(icdev, 5, sedata, &relen, tempbuf);
				//if ((st != 0) || (tempbuf[0] != 0x90))
				if (st != 0)
				{
					//error
					ICerror = 301;
					return -1;
				}
				//去除返回码
				
				tempbuf[relen - 2] = 0;
				IC_Strcat(buf, rlen, tempbuf, 0, relen - 2);
				rlen  = curreadlen;
				curoffset  = curreadlen;
				if (rlen == len)
				{
					break;
				}
			}
		}
                
    }
	return 0;
}
/// <summary>
/// 写IC卡数据
/// </summary>
/// <param name="offset">偏移</param>
/// <param name="len">写长度</param>
/// <param name="buf">数据缓存</param>
/// <returns></returns>
short CICcard::IC_UpdateData( unsigned short offset , unsigned short len ,int bufflen, byte* buf )
{
	
	
	int curlen=0;
	byte relen = 0;
	
	byte tempbuf[128];
	short st;
	
	//判断参数合法行
	if ( len>( bufflen ))
	{
		return -1;
	}
	if (gCardType == 0)
	{
		//组成命令
		byte sedata[1024];
		sedata[0] = 0;
		sedata[1] = 0xd6;
		while (curlen < len)
		{
			if ((len - curlen) > 112)
			{
				/*循环写数据*/
				sedata[2] = (byte)((((offset   curlen)) >> 8) & 0xFF);
				sedata[3] = (byte)((offset   curlen) & 0xFF);
				sedata[4] = 112;
				sedata[112   5] = 0;
				IC_Strcat(sedata, 5, buf, curlen, 112);
				st = IC_CpuApdu(icdev, (112   5), sedata, &relen, tempbuf);
				if ((st != 0) || (tempbuf[relen-2] != 0x90))
				{
					//error
					ICerror = 301;
					return -1;
				}
				curlen  = 112;
			}
			else
			{
				/*循环写数据*/
				sedata[2] = (byte)((((offset   curlen)) >> 8) & 0xFF);
				sedata[3] = (byte)((offset   curlen) & 0xFF);
				sedata[4] = (byte)(len - curlen);
				sedata[(len - curlen)   5] = 0;
				IC_Strcat(sedata, 5, buf, curlen, len - curlen);
				st = IC_CpuApdu(icdev, (byte)((len - curlen)   5), sedata, &relen, tempbuf);
				if ((st != 0) || (tempbuf[relen-2] != 0x90))
				{
					//error
					ICerror = 301;
					return -1;
				}
				curlen  = 112;
				break;
			}
		}
	}
	else
	{
		
		
		
		//校验写
		byte pintype[]= { 0x2};
		st = IC_VerifyPIN(pintype, gstrPIN2);
		if (st != 0)
		{
			//error
			ICerror = 301;
			return -1;
		}
		
		byte packetlen = 250;
		
		//当前偏移
		unsigned short curoffset = offset;
		byte isneedselectfile = 1;
		
		//本次循环OFFSET
		unsigned short fileoffset = 0;
		byte curreadlen = 0;
		
		//组成命令
		// A0D6000004 1234ABCD
		byte sedata[1024];
		sedata[0] = 0xa0;
		sedata[1] = 0xd6;
		while (curlen < len)
		{
			//判断是否重新选择文件
			if (isneedselectfile == 1)
			{
				IC_SelectFile(curoffset);
				isneedselectfile = 0;
			}
			
			if ((len - curlen) > packetlen)
			{
				//取得相对文件内部的offset
				if (curoffset < (20 * 1024))
				{
					fileoffset = (unsigned short)(curoffset % (4 * 1024));
					curreadlen = packetlen;
					//是否超出文件边界
					if ((fileoffset   packetlen) >= (4 * 1024))
					{
						curreadlen = (byte)((4 * 1024) - fileoffset);
						isneedselectfile = 1;
					}
					
				}
				else
				{
					fileoffset = (unsigned short)((curoffset - (20 * 1024)) % 3584);//(3.5 * 1024);
					curreadlen = packetlen;
					//是否超出文件边界
					if ((fileoffset   packetlen) >= (3584))
					{
						curreadlen = (byte)((3584) - fileoffset);
						isneedselectfile = 1;
					}
				}
				
				/*循环处理数据*/
				sedata[2] = (byte)((((fileoffset)) >> 8) & 0xFF);
				sedata[3] = (byte)((fileoffset) & 0xFF);
				sedata[4] = curreadlen;
				sedata[5] = 0;
				IC_Strcat(sedata, 5, buf, curlen, curreadlen);
				st = IC_CpuApdu(icdev, (byte)(curreadlen 5), sedata, &relen, tempbuf);
				//if ((st != 0) || (tempbuf[0] != 0x90))
				if (st != 0)
				{
					//error
					ICerror = 301;
					return -1;
				}
				
				curlen  = curreadlen;
				curoffset  = curreadlen;
				
			}
			else
			{
				//取得相对文件内部的offset
				if (curoffset < (20 * 1024))
				{
					fileoffset = (unsigned short)(curoffset % (4 * 1024));
					curreadlen = (byte)(len - curlen);
					//是否超出文件边界
					if ((fileoffset   (len - curlen)) >= (4 * 1024))
					{
						curreadlen = (byte)((4 * 1024) - fileoffset);
						isneedselectfile = 1;
					}
					
				}
				else
				{
					fileoffset = (unsigned short)((curoffset - (20 * 1024)) % 3584);//(3.5 * 1024);
					curreadlen = (byte)(len - curlen);
					//是否超出文件边界
					if ((fileoffset   (len - curlen)) >= (3584))
					{
						curreadlen = (byte)((3584) - fileoffset);
						isneedselectfile = 1;
					}
				}
				
				/*循环处理数据*/
				sedata[2] = (byte)((((fileoffset)) >> 8) & 0xFF);
				sedata[3] = (byte)((fileoffset) & 0xFF);
				sedata[4] = (byte)(curreadlen);
				sedata[5] = 0;
				IC_Strcat(sedata, 5, buf, curlen, curreadlen);
				st = IC_CpuApdu(icdev, (byte)(curreadlen   5), sedata, &relen, tempbuf);
				if ((st != 0) || (tempbuf[0] != 0x90))
				{
					//error
					ICerror = 301;
					return -1;
				}
				curlen  = curreadlen;
				curoffset  = curreadlen;
				if (curlen == len)
				{
					break;
				}
			}
		}
	}
	return 0;
}
/// <summary>
/// 3DES加密
/// </summary>
/// <param name="keyleft">密钥低8位</param>
/// <param name="keyright">密钥高8位</param>
/// <param name="psrc">源串</param>
/// <param name="pdest">加密后的串</param>
/// <returns></returns>
short CICcard::IC_DES3( byte* keyleft , byte* keyright , byte* psrc , byte* pdest )
{
	byte temp1[8];
	byte temp2[8];
	IC_Encrypt((char*) keyleft , (char*)psrc , 8 ,(char*) temp1 );
	IC_Decrypt((char*) keyright , (char*)temp1 , 8 ,(char*) temp2 );
	IC_Encrypt((char*) keyleft ,(char*) temp2 , 8 ,(char*) pdest );
	return 0;
}

short CICcard::IC_Strcat( byte* pdest , int doff , byte* psrc , int soff , int len )
{
	//判断参数合法性
/*
	if ( ( doff len ) > sizeof((char*)pdest) )
	{
		return -1;
	}
	if ( ( soff len )>strlen((char*)psrc) )
	{
		return -1;
	}
*/
	for ( int i=0 ; i<len ; i   )
	{
		
		pdest[doff i]=psrc[soff i];
		
	}
	
	return 0;
}

short CICcard::IC_GetChipID( byte* ChipID )
{
	byte Serdata_hex[64];
	byte sedata[64];
	byte relen = 0;
	short st;
	
	//1.取序列号
	sedata[0] = 0;
	sedata[1] = 0x24;
	sedata[2] = 0;
	sedata[3] = 0;
	sedata[4] = 8;
	//{"0024000008"};
	st = IC_CpuApdu( icdev , 5 , sedata , &relen , Serdata_hex );
	if ((st != 0) || (Serdata_hex[relen-2] != 0x90))
	{
		//error
		ICerror = 201;
		return -1;
	}
	IC_Strcat( ChipID , 0 , Serdata_hex , 0 , 8 );
	return 0;
}

short CICcard::IC_GetChallenge( byte* Randdata )
{
	byte tempout[64];
	byte sedata[64];
	byte relen = 0;
	short st;
	
	//1.取随机数
	sedata[0] = 0;
	sedata[1] = 0x84;
	sedata[2] = 0;
	sedata[3] = 0;
	sedata[4] = 8;
	//{"0084000008"};
	st = IC_CpuApdu( icdev , 5 , sedata , &relen , tempout );
	if ((st != 0) || (tempout[relen-2] != 0x90))
	{
		//error
		ICerror = 201;
		return -1;
	}
	IC_Strcat( Randdata , 0 , tempout , 0 , 8 );
	return 0;
}
/// <summary>
/// 修改卡片控制密钥
/// </summary>
/// <param name="oldctrl">旧控制密钥</param>
/// <param name="newctl">新控制密钥</param>
/// <returns>0 成功 -1 失败</returns>
short CICcard::IC_ChangeCtrlkey( byte* oldctrl , byte* newctl )
{
	byte Randdata[64];
	byte sedata[64];
	byte relen = 0;
	short st;
	
	//1.取随机数
	st = IC_GetChallenge( Randdata );
	if ( st != 0 )
	{
		//error
		ICerror = 201;
		return -1;
	}
	
	//使用16字节旧3DES控制密钥对8字节随机数加密得到8字节密文数据作为认证数据
	byte tempstr[8];
	byte keyright[8];
	IC_Strcat( keyright , 0 , oldctrl , 8 , 8 );
	IC_DES3( oldctrl , keyright , Randdata , tempstr );
	IC_Strcat( sedata , 5 , tempstr , 0 , 8 );
	
	//用16字节旧3DES控制密钥对新的3DES控制密钥的左8字节进行DES加密得到左8字节新3DES控制密钥密文
	IC_DES3( oldctrl , keyright , newctl , tempstr );
	IC_Strcat( sedata , 13 , tempstr , 0 , 8 );
	//用16字节旧3DES控制密钥对新的3DES控制密钥的右8字节进行DES加密得到右8字节新3DES控制密钥密文
	IC_Strcat( keyright , 0 , newctl , 8 , 8 );
	IC_DES3( oldctrl , keyright , keyright , tempstr );
	IC_Strcat( sedata , 21 , tempstr , 0 , 8 );
	
	sedata[0] = 0x00;
	sedata[1] = 0x23;
	sedata[2] = 0x00;
	sedata[3] = 0x00;
	sedata[4] = 0x18;
	//"0023000018"
	st = IC_CpuApdu( icdev , 29 , sedata , &relen , Randdata );
	if ((st != 0) || (Randdata[relen-2] != 0x90))
	{
		//error
		ICerror = 201;
		return -1;
	}
	return 0;
}

/// <summary>
/// 修改个人密钥
/// </summary>
/// <param name="Ctlkey">控制密钥</param>
/// <param name="oldPIN">旧密钥</param>
/// <param name="newPIN">新密钥</param>
/// <returns>0 成功 -1 失败</returns>
short CICcard::IC_ChangePIN( byte* Ctlkey , byte* oldPIN , byte* newPIN )
{
	byte Randdata[64];
	byte sedata[64];
	byte relen = 0;
	short st;
	
	if (gCardType == 0)
	{
		//1.取随机数
		st = IC_GetChallenge(Randdata);
		if (st != 0)
		{
			//error
			ICerror = 201;
			return -1;
		}
		//使用16字节3DES控制密钥对8字节随机数加密得到8字节密文数据作为过程密钥;
		byte tempstr[8];
		byte keyright[8];
		IC_Strcat(keyright, 0, Ctlkey, 8, 8);
		IC_DES3(Ctlkey, keyright, Randdata, tempstr);
		IC_Strcat(sedata, 5, tempstr, 0, 8);
		//用这个过程密钥对8字节旧PIN原文进行DES加密得到8字节旧PIN密文;
		byte oldPinEn[8];
		IC_Encrypt((char*)tempstr, (char*)oldPIN, 8, (char*)oldPinEn);
		//用这个过程密钥对8字节新PIN原文进行DES加密得到8字节新PIN密文。
		byte newPinEn[8];
		IC_Encrypt((char*)tempstr, (char*)newPIN, 8, (char*)newPinEn);
		
		//0021000010
		sedata[0] = 0x00;
		sedata[1] = 0x21;
		sedata[2] = 0x00;
		sedata[3] = 0x00;
		sedata[4] = 0x10;
		IC_Strcat(sedata, 5, oldPinEn, 0, 8);
		IC_Strcat(sedata, 13, newPinEn, 0, 8);
		st = IC_CpuApdu(icdev, 21, sedata, &relen, Randdata);
		if ((st != 0) || (Randdata[0] != 0x90))
		{
			//error
			ICerror = 201;
			//判断返回值
			if (relen == 2)
			{
				if (Randdata[0] != 0x90)
				{
					if (Randdata[0] == 0x63)
					{
						byte a;
						a = Randdata[1];
					}
				}
			}
			return -1;
		}
	}
	else if (gCardType == 1)
	{
		byte outbuf[64];
		if (Ctlkey[0] == 1)
		{
			//PIN1
			//A0 	24 	00 	PIN NO. 	10 
			sedata[0] = 0xA0;
			sedata[1] = 0x24;
			sedata[2] = 0;
			sedata[3] = 1;
			sedata[4] = 0x10;
			sedata[5] = 0;
			IC_Strcat(sedata, 5, oldPIN, 0, 8);
			IC_Strcat(sedata, 13, newPIN, 0, 8);
			st = IC_CpuApdu(icdev, 21, sedata, &relen, outbuf);
			if ((st != 0) || (outbuf[0] != 0x90))
			{
				//error
				ICerror = 202;
				return -1;
			}
		}
		else if(Ctlkey[0]==2)
		{
			//PIN2
			//A0 	24 	00 	PIN NO. 	10 
			sedata[0] = 0xA0;
			sedata[1] = 0x24;
			sedata[2] = 0;
			sedata[3] = 2;
			sedata[4] = 0x10;
			sedata[5] = 0;
			IC_Strcat(sedata, 5, oldPIN, 0, 8);
			IC_Strcat(sedata, 13, newPIN, 0, 8);
			st = IC_CpuApdu(icdev, 21, sedata, &relen, outbuf);
			if ((st != 0) || (outbuf[0] != 0x90))
			{
				//error
				ICerror = 202;
				return -1;
			}
		}
	}
	return 0;
}

short CICcard::IC_ResetPIN( byte* Ctlkey , byte* newPIN )
{
	byte Randdata[64];
	byte sedata[64];
	byte relen = 0;
	short st;
	
	//1.取随机数
	st = IC_GetChallenge( Randdata );
	if ( st != 0 )
	{
		//error
		ICerror = 201;
		return -1;
	}
	//使用16字节3DES控制密钥对8字节随机数加密得到8字节密文数据作为认证数据;
	byte tempstr[8];
	byte keyright[8];
	IC_Strcat( keyright , 0 , Ctlkey , 8 , 8 );
	IC_DES3( Ctlkey , keyright , Randdata , tempstr );
	IC_Strcat( sedata , 5 , tempstr , 0 , 8 );
	
	//用16字节3DES控制密钥对8字节新PIN原文进行DES加密得到8字节新PIN密文。
	byte newPinEn[8];
	IC_DES3( Ctlkey , keyright , newPIN , newPinEn );
	IC_Strcat( sedata , 13 , newPinEn , 0 , 8 );
	
	//0022000010
	sedata[0] = 0x00;
	sedata[1] = 0x22;
	sedata[2] = 0x00;
	sedata[3] = 0x00;
	sedata[4] = 0x10;
	st = IC_CpuApdu( icdev , 21 , sedata , &relen , Randdata );
	if ((st != 0) || (Randdata[relen-2] != 0x90))
	{
		//error
		ICerror = 201;
		return -1;
	}
	return 0;
}

int CICcard::IC_GetCardType(byte* sATR)
{
	if(strlen((char*)sATR)==0)
	{
		return -1;
	}
	if((sATR[5]==0x56)||(sATR[6]==0x12))
	{
		return 0;
	}
	else if((sATR[5]==0x00)||(sATR[6]==0x81))
	{
		return 1;
	}
	return -1;
}


/// <summary>
/// IC卡模块初始化
/// </summary>
/// <param name="ikey">程序模块初始化校验字符串</param>
/// <returns>-1 读卡器错误 -2 未插卡  -3 读卡器错误 -4 卡片损坏(无法复位) -5 卡未初始化</returns>

short CICcard::Init(CString ikey)
{
	short iret;
	byte rlen;
	byte rbuf[64];
	short st;
	
	// 一、对程序进行认证
	// 对程序合法性进行验证
	if ( ikey == ( "^A1&4CM." ) )
	{
		iPrgAuth = 1;
	}
	else
	{
		//error
		ICerror = 100;
		IC_Beep( icdev , 100 , 3 );
		iPrgAuth=0;
		return -1;
	}
	// 二、对设备初始化
	// 1.初始化端口
	icdev = IC_InitComm( 100 );
	if ( icdev <= 0 )
	{
		//error
		ICerror = 100;
		IC_Beep( icdev , 100 , 3 );
		return -1;
	}
	// 2.初始化IC卡类型(CPU卡)
	iret = IC_InitType( icdev , 0x0C );
	if ( iret != 0 )
	{
		//error
		ICerror = 101;
		IC_Beep( icdev , 100 , 3 );
		return -1;
	}
	// 3.取卡状态
	iret = IC_Status( icdev );
	if ( iret == 1 )
	{
		//正确,但没卡
		ICstate = 1;
		//未插卡
		return -2;
	}
	else if ( iret==0 )
	{
		ICstate = 2;
	}
	else
	{
		ICerror = 103;
		IC_Beep( icdev , 100 , 3 );
		//读卡错误
		return -3;
	}
	
	//卡复位
	iret = IC_CpuReset( icdev , & rlen , rbuf );
	if ( iret != 0 )
	{
		//error
		ICerror = 201;
		//读卡错误,(可能插反)
		return -4;
	}
	
	//判断卡类型
	gCardType = IC_GetCardType(rbuf);
	if(gCardType<0)
	{
		//error
		ICerror = 201;
		return -1;
	}
	
	//根据不同的卡类型做不同的初始化
	
	if (gCardType == 0)
	{
		//设置波特率
		byte bpsstring[] ={ 0xff, 0x10, 0x96 };
		iret = IC_CpuApdu(icdev, 3, bpsstring, & rlen, rbuf);
		if (iret != 0)
		{
			//error
			ICerror = 201;
			return -1;
		}
		
		//三、对卡进行个人密码认证
		byte defCtlkey[] ={ 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
			255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 };
#if 0
		//test liufr
		byte serdata[8];
		//默认PIN为序列号
		iret = IC_GetChipID(serdata);
		if (iret != 0)
		{
			return -1;
		}
		
		
		//默认CTLkey为全FF
		iret = IC_VerifyPIN(defCtlkey, serdata);
		if (iret != 0)
		{
			return -1;
		}
		//test end
#endif
		iret = IC_VerifyPIN( defCtlkey , gstrPIN );
		if (iret != 0)
		{
			//未初始化
			return -5;
		}
	}
	else
	{
		//设置波特率
		byte bpsstring[] ={ 0xff, 0x10, 0x95 };
		iret = IC_CpuApdu(icdev, 3, bpsstring, & rlen, rbuf);
		if (iret != 0)
		{
			//error
			ICerror = 201;
			return -1;
		}
		
		//校验写
		byte pintype[] ={ 0x1 };
		st = IC_VerifyPIN(pintype, gstrPIN1);
		if (st != 0)
		{
			//error
			ICerror = 301;
			//未初始化
			return -5;
		}
		pintype[0] = 2;
		st = IC_VerifyPIN(pintype, gstrPIN2);
		if (st != 0)
		{
			//error
			ICerror = 301;
			//未初始化
			return -5;
		}
	}
	
	
	//判断卡片初始化标识
	byte strver[64];
	iret =IC_ReadData( 0 , 4 , strver );
	if ( iret!=0 )
	{
		return -1;
	}
	if ( ( strver[0]!=gstrver[0] )||( strver[1]!=gstrver[1] ) )
	{
		//未初始化
		return -5;
	}
	return 0;
}
short CICcard::GetICStatus()
{
	short iret;
	HANDLE tempdev=IC_InitComm(100);
	iret=IC_Status(tempdev);
	IC_ExitComm(tempdev);
	return iret;
}
short CICcard::FormatIC(CString  ikey)
{
	short iret;
	byte rlen;
	byte rbuf [64];
	short st;
	
	// 一、对程序进行认证
	// 对程序合法性进行验证
	if ( ikey==( "^A1&4CM." ) )
	{
		iPrgAuth = 1;
	}
	else
	{
		//error
		ICerror = 100;
		IC_Beep( icdev , 100 , 3 );
		iPrgAuth=0;
		return -1;
	}
	// 二、对设备初始化
	// 1.初始化端口
	icdev = IC_InitComm( 100 );
	if ( icdev <= 0 )
	{
		//error
		ICerror = 100;
		IC_Beep( icdev , 100 , 3 );
		return -1;
	}
	// 2.初始化IC卡类型(CPU卡)
	iret = IC_InitType( icdev , 0x0C );
	if ( iret != 0 )
	{
		//error
		ICerror = 101;
		IC_Beep( icdev , 100 , 3 );
		return -1;
	}
	// 3.取卡状态
	iret = IC_Status( icdev );
	if ( iret == 1 )
	{
		//正确,但没卡
		ICstate = 1;
		return -2;
	}
	else if ( iret==0 )
	{
		ICstate = 2;
	}
	else
	{
		ICerror = 103;
		IC_Beep( icdev , 100 , 3 );
		return -1;
	}
	
	st= IC_CpuReset( icdev , & rlen , rbuf );
	if ( st != 0 )
	{
		//error
		ICerror = 201;
		return -1;
	}
	
	//判断卡类型
	gCardType = IC_GetCardType(rbuf);
	if (gCardType < 0)
	{
		//error
		ICerror = 201;
		return -3;
	}
	
	if (gCardType == 0)
	{
		//三、对卡进行个人密码认证
		//byte[] keyleft[] { 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 };
		//byte[] keyright=new byte[] { 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 };
		byte defCtlkey []= { 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
            255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 };
		byte serdata[8];
		//默认PIN为序列号
		iret = IC_GetChipID(serdata);
		if (iret != 0)
		{
			return -1;
		}
		//默认CTLkey为全FF
		iret = IC_VerifyPIN(defCtlkey, serdata);
		if (iret != 0)
		{
			iret = IC_ClearPIN();
			if (iret != 0)
			{
				return -3;
			}
			st = IC_CpuReset(icdev, & rlen, rbuf);
			if (st != 0)
			{
				//error
				ICerror = 201;
				return -1;
			}
			//默认CTLkey为全FF
			iret = IC_VerifyPIN(defCtlkey, serdata);
		}
		
		//写入唯一标识  'B' 'K' 0X00 0X01
		byte defver[]= { (byte)'B' , (byte)'K' , 0x00 , 0x01 ,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
		iret = IC_UpdateData(0, 4   14, 18,defver);
		if (iret != 0)
		{
			return -1;
		}
		
		//修改PIN
		iret = IC_ChangePIN(defCtlkey, serdata, gstrPIN);
		if (iret != 0)
		{
			return -1;
		}
		
		//默认CTLkey为全FF
		iret = IC_VerifyPIN(defCtlkey, gstrPIN);
		if (iret != 0)
		{
			return -1;
		}
	}
	else if(gCardType==1)
	{
		byte pintype[] ={ 0x1 };
		//先打开密码验证功能
		st = IC_EnablePIN(pintype[0], gdefPIN1);
		if (st != 0)
		{
			//error
			ICerror = 301;
			return -1;
		}
		pintype[0] = 2;
		st = IC_EnablePIN(pintype[0], gdefPIN2);
		if (st != 0)
		{
			//error
			ICerror = 301;
			return -1;
		}
		
		st = IC_CpuReset(icdev, & rlen, rbuf);
		if (st != 0)
		{
			//error
			ICerror = 201;
			return -1;
		}
		
		//三、对卡进行个人密码认证
		pintype[0] = 1;
		st = IC_VerifyPIN(pintype, gdefPIN1);
		if (st != 0)
		{
			if (st != 0)
			{
				st = IC_ClearPIN();
				if (st != 0)
				{
					return -3;
				}
			}
			
		}
		pintype[0] = 2;
		st = IC_VerifyPIN(pintype, gdefPIN2);
		if (st != 0)
		{
			//error
			ICerror = 301;
			return -1;
		}
		
		//改密码
		pintype[0] = 1;
		st = IC_ChangePIN(pintype, gdefPIN1,gstrPIN1);
		if (st != 0)
		{
			//error
			ICerror = 301;
			return -1;
		}
		pintype[0] = 2;
		st = IC_ChangePIN(pintype, gdefPIN2, gstrPIN2);
		if (st != 0)
		{
			//error
			ICerror = 301;
			return -1;
		}
		
		pintype[0] = 1;
		st = IC_VerifyPIN(pintype, gstrPIN2);
		if (st != 0)
		{
			//error
			ICerror = 301;
			return -1;
		}
		pintype[0] = 2;
		st = IC_VerifyPIN(pintype, gstrPIN2);
		if (st != 0)
		{
			//error
			ICerror = 301;
			return -1;
		}
		
		//写入唯一标识  'B' 'K' 0X00 0X01
		byte defver []= { (byte)'B' , (byte)'K' , 0x00 , 0x01 ,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
		iret = IC_UpdateData(0, 4   14,18, defver);
		if (iret != 0)
		{
			return -1;
		}
		
		
	}
	return 0;
}
/// <summary>
/// 重置IC卡密钥
/// </summary>
/// <returns></returns>
short CICcard::IC_ClearPIN()
{
	//重置密钥
	
	if (gCardType == 0)
	{
		byte defCtlkey[]= { 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
			255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 };
		byte serdata [8];
		//默认PIN为序列号
		short iret = IC_GetChipID(serdata);
		if (iret != 0)
		{
			return -1;
		}
		iret = IC_ResetPIN(defCtlkey, serdata);
		if (iret != 0)
		{
			return -1;
		}
	}
	else if (gCardType == 1)
	{
		byte defpuk[]= { 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30};
		byte gdefPIN1[] ={ 0x31, 0x32, 0x33, 0x34, 0xFF, 0xFF, 0xFF, 0xFF };
		byte gdefPIN2[] ={ 0x35, 0x36, 0x37, 0x38, 0xFF, 0xFF, 0xFF, 0xFF };
		//默认PIN为序列号
		short iret = IC_UnblockPIN(0, defpuk, gdefPIN1);
		if (iret != 0)
		{
			return -1;
		}
		iret =  IC_UnblockPIN(2,defpuk, gdefPIN2);
		if (iret != 0)
		{
			return -1;
		}
		
	}
	return 0;
}

short CICcard::Close()
{
	short st;
	st = IC_Down( icdev );
	if ( st != 0 )
	{
		//error
		ICerror = 401;
		return -1;
	}
	st = IC_ExitComm( icdev );
	if ( st != 0 )
	{
		//error
		ICerror = 402;
		return -1;
	}
	return 0;
}
/// <summary>
/// 响蜂鸣器
/// </summary>
/// <param name="time">蜂鸣器响时长 毫秒</param>
/// <returns>0 成功 -1 失败</returns>
short CICcard::Beep(int time)
{
	return IC_Beep( icdev , time , 1 );
}
/// <summary>
/// 写用户数据
/// </summary>
/// <param name="type">数据类型</param>
/// <param name="length">数据长度</param>
/// <param name="byteArray">输入缓存</param>
/// <returns></returns>

short CICcard::WriteData(int type , unsigned short length , byte* byteArray)
{
	short ret=0;
	unsigned short reallen=0;
	byte lenarray[]= { 0x00,0x00};
	
	//长度判断
	if ( length==0 )
	{
		return 0;
	}
	//要写的长度比实际输入缓存要大,返回错误
	if ( length>strlen((char*)byteArray ))
	{
		return -1;
	}
	if ( ( type>MAX_TYPE )||( type<1 ) )
	{
		return -1;
	}
	
	//先将对应域长度清空
	ret = IC_UpdateData( (unsigned short)(2 2*type) , 2 , 2,lenarray );
	if ( ret!=0 )
	{
		return -1;
	}
	
	switch ( type )
	{
		//PARA112_TYPE
	case 1:
		if (length > PARA112_LEN)
		{
			reallen = PARA112_LEN;
		}
		else
		{
			reallen=length;
		}
		ret = IC_UpdateData(PARA112_OFFSET, reallen,length, byteArray);
		break;
	case 2:
		if (length > PARA512_LEN)
		{
			reallen = PARA512_LEN;
		}
		else
		{
			reallen = length;
		}
		ret = IC_UpdateData(PARA512_OFFSET, reallen,length, byteArray);
		break;
		//PERSON_TYPE =3
	case 3:
		if ( length>PERSON_LEN )
		{
			reallen = PERSON_LEN;
		}
		else
		{
			reallen=length;
		}
		ret = IC_UpdateData( PERSON_OFFSET , reallen ,length, byteArray );
		break;
		//FINGER_TYPE = 4
	case 4:
		if ( length>( FINGER_LEN ) )
		{
			reallen = FINGER_LEN;
		}
		else
		{
			reallen=length;
		}
		ret = IC_UpdateData( FINGER_OFFSET , reallen ,length, byteArray );
		break;
		//PHOTO_TYPE = 5
	case 5:
		if ( length>( PHOTO_LEN ) )
		{
			reallen = PHOTO_LEN;
		}
		else
		{
			reallen=length;
		}
		ret = IC_UpdateData( PHOTO_OFFSET , reallen ,length, byteArray );
		break;
		
	default:
		return -1;
	}
	if ( ret!=0 )
	{
		return -1;
	}
	//更新对应域实际长度
	lenarray[0]=(byte)( ( reallen )&0xFF );
	lenarray[1]=(byte)( ( ( ( reallen ) )>>8 )&0xFF );
	ret = IC_UpdateData( (unsigned short)(2 2*type) , 2 ,2, lenarray );
	if ( ret!=0 )
	{
		return -1;
	}
	return ret;
}

/// <summary>
/// 更新用户数据
/// </summary>
/// <param name="type">数据类型 </param>
/// <param name="databuf">用户数据信息</param>
/// <returns></returns>
short CICcard::WriteDatastr(int type , CString databuf)
{
	short ret=0;
	//长度判断
	if ( databuf.GetLength()==0 )
	{
		return 0;
	}
	
	ret=this->WriteData( type , (unsigned short)(databuf.GetLength()) , (byte*)databuf.GetBuffer(databuf.GetLength()) );
	return ret;
}
/// <summary>
/// 写个人基本信息
/// </summary>
/// <param name="datastr">个人信息</param>
/// <returns></returns>
short CICcard::WritePerson(CString datastr)
{
	short ret=0;
	ret = WriteDatastr(PERSON_TYPE,datastr);
	return ret;
}
/// <summary>
/// 写指纹信息
/// </summary>
/// <param name="index">指纹编号 1~4</param>
/// <param name="datastr">指纹信息</param>
/// <returns>若编号输入有误,则返回-1</returns>
short CICcard::WriteFinger(CString datastr)
{
	short ret=0;
	
	ret = WriteDatastr((FINGER_TYPE),datastr);
	return ret;
}

short CICcard::WritePhoto(int len, byte* databuf)
{
	short ret=0;
	ret=this->WriteData( PHOTO_TYPE , len , databuf );
	return ret;
}
/// <summary>
/// 读备用参数值
/// </summary>
/// <param name="type">备用参数数据byte[]</param>
/// <returns>0 成功 -1 失败</returns>
short CICcard::WritePara112(int len, byte* databuf)
{
	short ret=0;
	if(len>112)
		return -1;
	ret=this->WriteData( PARA112_TYPE , len , databuf );
	return ret;
}
/// <summary>
/// 读备用参数值
/// </summary>
/// <param name="type">备用参数数据byte[]</param>
/// <returns>0 成功 -1 失败</returns>
short CICcard::WritePara512(int len, byte* databuf)
{
	short ret=0;
	if(len>512)
		return -1;
	ret=this->WriteData( PARA512_TYPE , len , databuf );
	return ret;
}
/// <summary>
/// 读用户信息
/// </summary>
/// <param name="type">数据类型 1~7(其他值返回-1)</param>
/// <param name="type">数据长度 </param>
/// <param name="databuf">用户数据信息</param>
/// <returns>0 成功 -1 失败 输入数据长度为0,返回成功 输入数据长度大于databuf可容纳长度,返回-1</returns>
short CICcard::ReadData(int type , unsigned short length , byte* databuf )
{
	short ret=0;
	unsigned short reallen=0;
	byte lenarray[]={ 0x00 , 0x00 };
	
	///清空
	memset(databuf,0,length);
	
	if ( length==0 )
	{
		return 0;
	}
	
	if ( ( type>MAX_TYPE )||( type<1 ) )
	{
		return -1;
	}
	//先将对应域实际长度读出
	ret = IC_ReadData( (unsigned short)(2 2*type), 2 , lenarray );
	if ( ret!=0 )
	{
		return -1;
	}
	//实际长度
	reallen=(unsigned short)(lenarray[0] lenarray[1]*256);
	
	if(reallen==0)
	{
		return 0;
	}
	
	//由于在写入时,已经判断了长度必须在有效范围内,所以读取的时候不需再判断
	//读小余实际长度的情况
	if ( length<reallen )
	{
		reallen=length;
	}
	
	switch ( type )
	{
		
		//备用参数信息
	case 1:
		ret = IC_ReadData(PARA112_OFFSET, reallen, databuf);
		break;
		//备用参数信息
	case 2:
		ret = IC_ReadData(PARA512_OFFSET, reallen, databuf);
		break;
		//基本信息
	case 3:
		ret = IC_ReadData((PERSON_OFFSET), reallen, databuf);
		break;
		//指纹信息
	case 4:
		ret = IC_ReadData((FINGER_OFFSET), reallen, databuf);
		break;
		//图片
	case 5:
		ret = IC_ReadData((PHOTO_OFFSET), reallen, databuf);
		break;                
	default:
		return -1;
		
	}
	return ret;
	
}

short CICcard::ReadPerson(unsigned short bufferlen, byte* databuf )
{
	
	return ReadData( PERSON_TYPE ,bufferlen, databuf );
}
short CICcard::ReadFinger(unsigned short bufferlen, byte* databuf )
{
	
	return ReadData( FINGER_TYPE ,bufferlen, databuf );
}
short CICcard::ReadPhoto(unsigned short bufferlen, byte* databuf )
{
	
	return ReadData( PHOTO_TYPE ,bufferlen, databuf );
}
short CICcard::ReadPara112(unsigned short bufferlen, byte* databuf )
{
	
	return ReadData( PARA112_TYPE ,bufferlen, databuf );
}
short CICcard::ReadPara512(unsigned short bufferlen, byte* databuf )
{
	
	return ReadData( PARA512_TYPE ,bufferlen, databuf );
}


标签: IC卡 发卡机

实例下载地址

CRT-571-V10 IC卡发卡机软件

不能下载?内容有错? 点击这里报错 + 投诉 + 提问

好例子网口号:伸出你的我的手 — 分享

网友评论

发表评论

(您的评论需要经过审核才能显示)

查看所有0条评论>>

小贴士

感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。

  • 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
  • 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
  • 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
  • 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。

关于好例子网

本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明

;
报警