一 身份证阅读器SDK使用手册

1. 定义

应用函数开发包含下列文件:
termb.dll API函数的动态联接库
sdtapi.dll 安全模块通讯函数
UnPack.dll 身份证相片解码库
适用操作系统:
Windows NT: 需要NT 3.1版或以后版本
Windows: 需要 Windows 98、Windows 2000或以后版本
适用开发语言:
Visual C++ 5.0 及以后版本
Visual Basic 5.0 及以后版本
Delphi 3.0 及以后版本
PowerBuilder 6.0 及以后版本

2. 函数列表

//以下为主要API函数
int CVR_InitComm(int Port) 初始化连接;
int CVR_Authenticate() 卡认证;
int CVR_Read_Content(int active) 读卡操作。
int CVR_CloseComm() 关闭连接;

//以下为可选API函数,方便二次开发
int GetPeopleName(char *strTmp, int *strLen) 得到姓名信息
int GetPeopleSex(char *strTmp, int *strLen) 得到性别信息
int GetPeopleNation(char *strTmp, int *strLen) 得到民族信息
int GetPeopleBirthday(char *strTmp, int *strLen) 得到出生日期
int GetPeopleAddress(char *strTmp, int *strLen) 得到地址信息
int GetPeopleIDCode(char *strTmp, int *strLen) 得到身份证号信息
int GetDepartment(char *strTmp, int *strLen) 得到发证机关信息
int GetStartDate(char *strTmp, int *strLen) 得到有效开始日期
int GetEndDate(char *strTmp, int *strLen) 得到有效截止日期
int CVR_GetSAMID(char *SAMID) 得到安全模块号

3. 函数说明

初始化连接

原 型:int CVR_InitComm (int Port)
说 明:本函数用于PC与华视电子第二代居民身份证阅读器的连接。
参 数:Port:连接串口(COM1COM16)或USB口(10011016)
值 意义
1 串口1
2 串口2
3 串口3
4 串口4
1001 USB口1
1002 USB口2
1003 USB口3
1004 USB口4

返 回 值:
值 意义
1 正确
2 端口打开失败
0 动态库加载失败

关闭串口

原 型:
int CVR_CloseComm(void)
说 明:本函数用于关闭PC到阅读器的连接。
参 数:无
返 回 值:
值 意义
1 正确
0 错误

卡认证

原 型:int CVR_Authenticate (void)
说 明:本函数用于读卡器和卡片之间的合法身份确认。卡认证循环间隔大于300ms。
参 数:
返 回 值:
值 意义 说明
1 正确 卡片认证成功
2 错误 寻卡失败
3 错误 选卡失败
0 错误 初始化失败
注意:若卡片放置后发生认证错误时,应移走卡片重新放置。

读卡操作

原 型:int CVR_Read_Content(int active);
说 明:本函数用于通过阅读器从第二代居民身份证中读取相应信息。卡认证成功以后才可做读卡操作,读卡完毕若继续读卡应移走二代证卡片重新放置做卡认证。
参 数:active:兼容以前版本,无实际意义

返 回 值:
返回值 意义
1 正确
0 错误
99 异常
说明:
读卡成功后在termb.dll文件所在路径下生成wz.txt(文字信息)和zp.bmp(照片信息)
wz.txt内容示例如下:
张红叶


1988-11-18
河北省邯郸市临漳县称勾镇称勾东村复兴路25号
130423198811184328
临漳县公安局
2011.03.30-2021.03.30

读各项文字信息到自定义内存缓冲

原 型:
int GetPeopleName(char *strTmp, int *strLen) //得到姓名信息
int GetPeopleSex(char *strTmp, int *strLen) //得到性别信息
int GetPeopleNation(char *strTmp, int *strLen) //得到民族信息
int GetPeopleBirthday(char *strTmp, int *strLen) //得到出生日期
int GetPeopleAddress(char *strTmp, int *strLen) //得到地址信息
int GetPeopleIDCode(char *strTmp, int *strLen) //得到卡号信息
int GetDepartment(char *strTmp, int *strLen) //得到发证机关信息
int GetStartDate(char *strTmp, int *strLen) //得到有效开始日期
int GetEndDate(char *strTmp, int *strLen) //得到有效截止日期
int CVR_GetSAMID(char * SAMID) //得到安全模块号码
参数:
*strTmp 返回的信息缓存指针。
*strLen 返回的信息长度指针。
返 回 值:
返回值 意义
1 正确
0 错误

注意:若采用查询方式自动判断卡片是否放置,则间隔时间建议大于300ms。

二 开始对接

主要做的功能就是使用身份证刷卡登录系统

大致流程是这样的:
前端是定时请求后台
后台流程就是

  1. 初始化连接
  2. 卡认证
  3. 读卡操作
  4. 得到身份证号信息

然后拿到这个身份证号后与数据库的用户对应身份证对比一下 如果相同 就调转到主页 完成登录

jnative 使用套路的话就是把用到的dll文件放到jdk的bin目录下面

动态链接库编译时选择的平台。如果通过x86平台编译,那么只能使用32位jdk环境加载,如果要使用64位jdk,必须使用x64平台编译。

那么怎么看dll文件是32位还是64位呢 可以装一个Visual Studio 自带工具dumpbin.exe

执行dumpbin.exe /headers 文件路径

像这样:

java 华视读卡 华视电子读卡器驱动_阅读器


jnative 用法:

JNative n = null;
		try
		{
			n = new JNative("Termb.dll", "CVR_InitComm");
			n.setRetVal(Type.INT); // 指定返回参数的类型
			n.setParameter(0, Port);//设置参数
			n.invoke(); // 调用方法
			return Integer.parseInt(n.getRetVal());//得到返回值
		}
		finally
		{

		}

实例:

引入jar包

<dependency>
          <groupId>org.apache</groupId>
          <artifactId>JNative</artifactId>
          <version>1.0.0</version>
      </dependency>

后台代码:

//1.打开端口
		int portReturnCode =1001;
		try
		{
			portReturnCode = CVR_InitComm(Integer.parseInt(intport));
			logger.info("打开端口返回值:" + String.valueOf(portReturnCode));
			if (portReturnCode!=1) {
				return null;
			}
		}
		catch(Exception ex)
		{
			logger.error("打开端口调用异常!"+ ex.getMessage());
		}

		// 2. 认证
		int authReturnCode = 0;
		try
		{
			authReturnCode = CVR_Authenticate();
			logger.info("认证返回值:" + String.valueOf(authReturnCode));
			if (authReturnCode!=1) {
				return null;
			}
		}
		catch(Exception ex)
		{
			logger.error("认证调用异常!"+ ex.getMessage());
		}

		//3. 读卡
		int readReturnCode = 0;
		try
		{
			readReturnCode = CVR_Read_Content(4);
			logger.info("读卡返回值:" + String.valueOf(readReturnCode));
			if (authReturnCode!=1) {
				return null;
			}
		}
		catch(Exception ex)
		{
			logger.error("读卡调用异常!"+ ex.getMessage());
		}

		//4. 读取身份证号码
		int readIdReturnCode = 0;
		try
		{
			readIdReturnCode = GetPeopleIDCode();
			logger.info("读取身份证号码返回值:" + String.valueOf(readIdReturnCode));
			if(readIdReturnCode == 1)
			{
				logger.info("身份号码:" + strTmp.trim());

			}
		}
		catch(Exception ex)
		{
			logger.error("调用异常!"+ ex.getMessage());
		}
		return strTmp.trim();
	}

调用动态库的方法:

/**
	 * 身份证阅读机打开端口
	 * @param Port
	 * @return
	 * @throws NativeException
	 * @throws IllegalAccessException
	 * @throws UnsupportedEncodingException
	 */
	private  int CVR_InitComm(int Port) throws NativeException, IllegalAccessException, UnsupportedEncodingException
	{
		JNative n = null;
		try
		{
			n = new JNative("Termb.dll", "CVR_InitComm");
			n.setRetVal(Type.INT); // 指定返回参数的类型
			n.setParameter(0, Port);
			n.invoke(); // 调用方法
			return Integer.parseInt(n.getRetVal());
		}
		finally
		{

		}
	}

	/**
	 * 身份证阅读机认证
	 * @return
	 * @throws NativeException
	 * @throws IllegalAccessException
	 */
	private  int CVR_Authenticate() throws NativeException, IllegalAccessException
	{
		JNative n = null;
		try
		{
			n = new JNative("Termb.dll", "CVR_Authenticate");
			n.setRetVal(Type.INT); // 指定返回参数的类型
			n.invoke(); // 调用方法
			return Integer.parseInt(n.getRetVal());
		}
		finally
		{

		}
	}

	/**
	 * 身份证阅读机读卡
	 * @return
	 * @throws NativeException
	 * @throws IllegalAccessException
	 */
	private  int CVR_Read_Content(int Active) throws NativeException, IllegalAccessException
	{
		JNative n = null;
		try
		{
			n = new JNative("Termb.dll", "CVR_Read_Content");
			n.setRetVal(Type.INT); // 指定返回参数的类型
			n.setParameter(0, Active);
			n.invoke(); // 调用方法
			return Integer.parseInt(n.getRetVal());
		}
		finally
		{

		}
	}

	/**
	 * 身份证阅读机获取身份证号
	 * @return
	 * @throws NativeException
	 * @throws IllegalAccessException
	 */
	private  int GetPeopleIDCode() throws NativeException, IllegalAccessException
	{
		JNative n = null;
		try
		{
			n = new JNative("Termb.dll", "GetPeopleIDCode");
			n.setRetVal(Type.INT); // 指定返回参数的类型
			Pointer a = new Pointer(MemoryBlockFactory.createMemoryBlock(4*10));
			Pointer b = new Pointer(MemoryBlockFactory.createMemoryBlock(4*30));
			n.setParameter(0,b);
			n.setParameter(1,a);
			n.invoke();
			byte[] by = new byte[120];
			by = b.getMemory();
			try
			{
				strTmp = new String(by,"gb2312");
			}
			catch (UnsupportedEncodingException ex)
			{
				logger.error("获取身份信息异常:",ex);
			}

			int asInt = a.getAsInt(0);

			a.dispose();
			b.dispose();
			return Integer.parseInt(n.getRetVal());
		}
		finally
		{

		}
	}

附上一个demo:
https://github.com/xiepanpan/CVR100Demo