C#实现低耦合读卡

news2024/11/24 8:47:29

我们经常要给用户实现读卡查询。有很多种读卡器,每个厂商的接口也不同。归纳为两类,一类是感应式读卡,卡片接触上去就读出数据。一种是触发式的,程序调用读卡方法,硬件再进入读卡轮询。对应触发式的只能加按钮触发了,对于感应式的可以模拟条码枪实现扫码效果。这样任意实现回车查询的界面都能用读卡程序。

首先抽取读卡接口,任何人只要实现该接口把实现类配置到读卡程序就可以实现读卡,主程序通过配置反射得到实现类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ReadCardService
{
	///<summary  NoteObject="Class">
	/// [功能描述:读卡接口] <para/>
	/// [创建者:zlz] <para/>
	/// [创建时间:2018年09月26日] <para/>
	///<说明>
	///  [说明:读卡接口返回1-就诊卡,2-医保卡,3-身份证]<para/>
	///</说明>
	///<修改记录>
	///    [修改时间:本次修改时间]<para/>
	///    [修改内容:本次修改内容]<para/>
	///</修改记录>
	///<修改记录>
	///    [修改时间:本次修改时间]<para/>
	///    [修改内容:本次修改内容]<para/>
	///</修改记录>
	///</summary>
    public interface IReadCard
    {
        string Read(string type);
    }
}

实现实例1:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ReadCardService;
using System.Runtime.InteropServices;

namespace SYYDReadCard
{

    /// <summary>
    /// 读卡服务
    /// </summary>
    public class ReadCard : IReadCard
    {
        /// <summary>
        /// 读身份证
        /// </summary>
        /// <returns></returns>
        [DllImport("DHCCardInfo.dll")]
        [return: MarshalAs(UnmanagedType.BStr)]
        public static extern string ReadIDCardNo();

        /// <summary>
        /// 读银行卡
        /// </summary>
        /// <returns></returns>
        [DllImport("DHCCardInfo.dll")]
        [return: MarshalAs(UnmanagedType.BStr)]
        public static extern string ReadBankCardNo();

        /// <summary>
        /// 读居民健康卡
        /// </summary>
        /// <returns></returns>
        [DllImport("DHCCardInfo.dll")]
        [return: MarshalAs(UnmanagedType.LPTStr)]
        public static extern string ReadMHCCardNo();

        /// <summary>
        /// 读居民健康卡
        /// </summary>
        /// <returns></returns>
        [DllImport("DHCCardInfo.dll")]
        [return: MarshalAs(UnmanagedType.LPTStr)]
        public static extern string ReadMHCCard();
        

        /// <summary>
        /// 读卡
        /// </summary>
        /// <returns></returns>
        public string Read(string type)
        {
            if (type == "1")
            {
                return "";
            }
            else if (type == "2")
            {
                string ret = ReadMHCCardNo();
                string[] retArr = ret.Split('^');
                if (retArr.Length > 1)
                {
                    return type + "-" + retArr[1];
                }
                return ret;
            }
            else if (type == "3")
            {
                string ret = ReadIDCardNo();
                string[] retArr = ret.Split('^');
                if (retArr.Length > 1)
                {
                    return type+"-"+retArr[1];
                }
                return ret;
            }
            else if (type == "4")
            {
                string ret = ReadBankCardNo();
                string[] retArr = ret.Split('^');
                if (retArr.Length > 1)
                {
                    return type + "-" + retArr[1];
                }
                return ret;
            }
            else if(type!="")
            {
                return "未支持的卡类型";
            }
            return "";
        }
    }
}

实现示例2:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using ReadCardService;

namespace JLGZLGWYYReadCard
{
    /// <summary>
    /// 读卡
    /// </summary>
    public class ReadCard : IReadCard
    {
        [DllImport("dcrf32.dll")]
        public static extern int dc_init(Int16 port, long baud);  //初试化
        [DllImport("dcrf32.dll")]
        public static extern short dc_exit(int icdev);
        [DllImport("dcrf32.dll")]
        public static extern short dc_reset(int icdev, uint sec);
        [DllImport("dcrf32.dll")]
        public static extern short dc_request(int icdev, char _Mode, ref uint TagType);
        [DllImport("dcrf32.dll")]
        public static extern short dc_card(int icdev, char _Mode, ref ulong Snr);
        [DllImport("dcrf32.dll")]
        public static extern short dc_halt(int icdev);
        [DllImport("dcrf32.dll")]
        public static extern short dc_anticoll(int icdev, char _Bcnt, ref ulong IcCardNo);
        [DllImport("dcrf32.dll")]
        public static extern short dc_beep(int icdev, uint _Msec);
        [DllImport("dcrf32.dll")]
        public static extern short dc_authentication(int icdev, int _Mode, int _SecNr);
        [DllImport("dcrf32.dll")]
        public static extern short dc_authentication_passaddr(int icdev, int _Mode, int _Addr, byte[] nkey);

        [DllImport("dcrf32.dll")]
        public static extern short dc_load_key(int icdev, int mode, int secnr, [In] byte[] nkey);  //密码装载到读写模块中
        [DllImport("dcrf32.dll")]
        public static extern short dc_load_key_hex(int icdev, int mode, int secnr, string nkey);  //密码装载到读写模块中

        [DllImport("dcrf32.dll")]
        public static extern short dc_write(int icdev, int adr, [In] byte[] sdata);  //向卡中写入数据
        [DllImport("dcrf32.dll")]
        public static extern short dc_write(int icdev, int adr, [In] string sdata);  //向卡中写入数据
        [DllImport("dcrf32.dll")]
        public static extern short dc_write_hex(int icdev, int adr, [In] string sdata);  //向卡中写入数据(转换为16进制)

        [DllImport("dcrf32.dll")]
        public static extern short dc_read(int icdev, int adr, [Out] byte[] sdata);

        [DllImport("dcrf32.dll")]
        public static extern short dc_read(int icdev, int adr, [MarshalAs(UnmanagedType.LPStr)] StringBuilder sdata);  //从卡中读数据
        [DllImport("dcrf32.dll")]
        public static extern short dc_read_hex(int icdev, int adr, [MarshalAs(UnmanagedType.LPStr)] StringBuilder sdata);  //从卡中读数据(转换为16进制)
        [DllImport("dcrf32.dll")]
        public static extern int a_hex(string oldValue, ref string newValue, Int16 len);  //普通字符转换成十六进制字符
        [DllImport("dcrf32.dll")]
        public static extern void hex_a(ref string oldValue, ref string newValue, int len);  //十六进制字符转换成普通字符


        /// <summary>
        /// 读卡
        /// </summary>
        /// <returns></returns>
        public string Read(string type)
        {
            int _icdev = 0;
            try
            {
                if (_icdev <= 0)
                {
                    _icdev = dc_init(100, 115200);
                    if (_icdev < 0)
                    {
                        LIS.Core.Util.LogUtils.WriteDebugLog("-1^初始化失败!");
                        return "";
                    }
                }
                uint ss = 0;
                ulong icCardNo = 0;
                char tt = (char)0;
                float st = dc_reset(_icdev, ss);
                st = dc_card(_icdev, tt, ref icCardNo);
                if (icCardNo == 0)
                {
                    LIS.Core.Util.LogUtils.WriteDebugLog("-1^寻卡失败!");
                    return "";
                }
                //核对密码
                st = dc_beep(_icdev, 10);
                string retStr = "";
                if (icCardNo!=0)
                {
                    retStr = "" + icCardNo;
                    if(retStr.Length<12)
                    {
                        int cha = 12 - retStr.Length;
                        for(int i=0;i<cha;i++)
                        {
                            retStr = "0" + retStr;
                        }
                    }
                }
                return retStr;
            }
            catch (Exception ex)
            {
                return "-1^" + ex.Message;
            }
            finally
            {
                if (_icdev > 0)
                {
                    dc_exit((Int16)_icdev);
                }
            }
            return "";
        }
    }


}

配置实现类:
在这里插入图片描述

C#模拟条码枪

 [DllImport("user32.dll", SetLastError = true)]
        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
        public static void PressKey(Keys key, bool up)
        {
            const int KEYEVENTF_EXTENDEDKEY = 0x1;
            const int KEYEVENTF_KEYUP = 0x2;
            if (up)
            {

                keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, (UIntPtr)0);

            }
            else
            {

                keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);

            }
        }


        char preChar;
        /// <summary>
        /// 发送字符串
        /// </summary>
        /// <param name="str"></param>
        private void SendStr(string str)
        {
            foreach(var c in str)
            {
                if(c==preChar)
                {
                    System.Threading.Thread.Sleep(300);
                }
                else
                {
                    System.Threading.Thread.Sleep(50);
                }
                bool isUp = false;
                if(c>='A'&&c<='Z')
                {
                    isUp = true;
                }
                Keys k1 = (Keys)c;
                PressKey(k1, isUp);
                preChar = c;
            }
        }

主程序活动读卡实现类轮训调用模拟扫码即可:

/// <summary>
        /// 开始监听
        /// </summary>
        public void StartMonitor()
        {
            try
            {
                //前面日志之类的底阿妈
                //获取读卡服务实现对象**********************
                IReadCard service = LIS.Core.Context.ObjectContainer.GetObject<IReadCard>();
                if (service != null)
                {
                    string cardType = "";
					//调用读卡
                    string cardNo = service.Read(cardType);
                    if(cardNo.StartsWith("-1^"))
                    {
                        LIS.Core.Util.LogUtils.WriteDebugLog(cardNo);
                        cardNo = "";
                    }
                    if (cardType != "" && cardNo!="")
                    {
                        if (AddCardType == "1")
                        {
                            cardNo = cardType + "-" + cardNo;
                        }
                    }
					//判断变化**********************
                    if ((cardNo!="")&&(cardNo != PreCardNo || ReadModel == "1" || cardType!=""))
                    {
                        LIS.Core.Util.LogUtils.WriteDebugLog("监听读取到卡号,卡号:" + cardNo);
                        LogDto dt = new LogDto();
                        dt.Address = "读取到卡号";
                        dt.Time = DateTime.Now.ToString();
                        dt.Result = cardNo;
                        //窗口是打开状态才绑数据
                        if (this.WindowState != FormWindowState.Minimized)
                        {
                            ManagedAsyncUtilsWithReport<LogDto>.InitUtil(new BackgroundWorker());
                            //通知界面改变
                            ManagedAsyncUtilsWithReport<LogDto>.Report(dt, null);
                        }
                        //读取的卡号变化了且不为空就通知服务
                        if (cardNo != "")
                        {
                            //模拟条码枪********************************
                            if (VirtuaBarGun == "1")
                            {
                                LIS.Core.Util.LogUtils.WriteDebugLog("模拟键盘输入:" + cardNo);
                                SendStr(cardNo);
                                //SendKeys.SendWait(cardNo);
                                System.Threading.Thread.Sleep(200);
                                PressKey(Keys.Enter, false);
                                //SendKeys.SendWait("{ENTER}");
                            }
                            //调自助打印
                            else
                            {
                                LIS.Core.Util.LogUtils.WriteDebugLog("调用自助打印程序服务,确保自助程序配置开启了服务。卡号:" + cardNo);
                                SendCardServiceReference.PrintClient client = new SendCardServiceReference.PrintClient();
                                client.Print(cardNo, "");
                                LIS.Core.Util.LogUtils.WriteDebugLog("调用自助打印程序服务结束");
                            }
                        }
                        else 
                        {
                            //条码枪模式,没有读到卡号也添加回车事件
                            if (VirtuaBarGun == "1" && AddEnterEvent == "1")
                            {
                                PressKey(Keys.Enter,false);
                            }
                        }
                    }
                    PreCardNo = cardNo;
                }
                else
                {
                    LIS.Core.Util.LogUtils.WriteDebugLog("未获取到读卡接口实现。。。");
                }
                LIS.Core.Util.LogUtils.WriteDebugLog("监听读卡结束。。。");
                //阻塞进程
                System.Threading.Thread.Sleep(WaitTime);
                //有数据改变为活动图标
                ChangeIcon(1);
            }
            catch (Exception ex)
            {
                LIS.Core.Util.LogUtils.WriteDebugLog("监听读卡过程发生错误:"+ex.Message);
            }
        }   

这样就可以对感应式读卡做到扫条码枪的体验。对非感应式的主程序和BS界面交互。读卡实现者只要实现读卡接口,配置实现类就可。从而稳定BS界面和读卡主程序。读卡实现人也不需要关心庞大的主体程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/721582.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

技术分享 | app自动化测试(Android)-- 特殊控件 Toast 识别

Toast 是 Android 系统中的一种消息框类型&#xff0c;它属于一种轻量级的消息提示&#xff0c;常常以小弹框的形式出现&#xff0c;一般出现 1 到 2 秒会自动消失&#xff0c;可以出现在屏幕上中下任意位置。它不同于 Dialog&#xff0c;它没有焦点。Toast 的设计思想是尽可能…

不要再纠结了!看完这篇,你就能秒懂webpack、vite、rollup三者间差异!

前端打包工具webpack、vite、rollup的区别及使用 webpack、vite、rollup的区别webpack、vite的区别为什么vite比webpack打包快&#xff1f;为什么有人会说vite慢&#xff1f;首屏问题懒加载问题解决方案注意点 webpackwebpack打包过程webpack打包原理第一次冷启动慢的原因热更新…

在yolov5源码中添加注意力机制

yolov5源码中添加注意力机制 1 项目环境配置1.1 yolov5 源码下载1.2 创建虚拟环境1.3 安装依赖 2 常用的注意力机制2.1 SE 注意力机制2.2 CBAM 注意力机制2.3 ECA 注意力机制2.4 CA 注意力机制 3 添加方式3.1 修改 common.py 文件3.2 修改 yolo.py 文件3.3 修改 yolov5s.yaml 文…

易查分如何导入数据?这个最关键的要点别忽略

我们在使用易查分制作查询系统时&#xff0c;偶尔会遇到Excel文件没有办法正常上传的情况。这个问题困扰着许多老师&#xff0c;他们不知道该如何解决。今天我想和大家讨论一下&#xff0c;易查分导入数据时最常出现错误的原因&#xff0c;其中这个要点最关键&#xff0c;但很多…

谷歌Bard入门指南

文章目录 谷歌Bard入门指南一、简介二、使用指南三、中文化3.1 中文提问3.2 中文回答 四、Hello Game五、亮点 谷歌Bard入门指南 一、简介 Bard 是一个大型语言模型&#xff0c;也称为对话式 AI 或聊天机器人&#xff0c;经过训练&#xff0c;内容丰富且全面。Bard 接受过大量…

Mysql——》哈希索引

推荐链接&#xff1a; 总结——》【Java】 总结——》【Mysql】 总结——》【Redis】 总结——》【Kafka】 总结——》【Spring】 总结——》【SpringBoot】 总结——》【MyBatis、MyBatis-Plus】 总结——》【Linux】 总结——》【MongoD…

接口测试-postman,JMeter与LoadRunner比较

目录 JMeter与LoadRunner比较 JMeter缺点 一.创建测试用例集、子集 二.创建测试用例 三.设置变量 四.添加响应处理 五.批量执行测试用例 总结&#xff1a; postman是一个谷歌出的轻量级的专门测试接口的小工具~&#xff08;PS&#xff1a;postman包括两种&#xff1a;C…

PostgreSQL如何根据执行计划进行性能调优?

EXPLAIN命令 PG中EXPLAIN命令语法格式如下&#xff1a; EXPLAIN [(option[,...])] statement EXPLAIN [ANALYZE] [VERBOSE] statement该命令的options如下&#xff1a; ANALYZE [boolean]VERBOSE [boolean]COSTS [boolean]BUFFERS [boolean]FORMAT {TEXT | XML | JSON | YAM…

【UnityDOTS 十】DynamicBufferComponent介绍

DynamicBufferComponent 前言 DynamicBufferComponent 作为一种特殊的组件存在&#xff0c;可以作为一种非托管内存下可动态调整带下的数组容器组件。 一、DynamicBufferComponent是什么&#xff1f; DynamicBufferComponent也是组件的一种。 需要关注的是内部指针&#xf…

spring使用01

① 导入 Spring 开发的基本包坐标 ② 编写 Dao 接口和实现类 ③ 创建 Spring 核心配置文件 ④ 在 Spring 配置文件中配置 UserDaoImpl ⑤ 使用 Spring 的 API 获得 Bean 实例 第一步&#xff1a;创建maven的web骨架 然后&#xff0c;导入 Spring 开发的基本包坐标 <depe…

工资10K,副业20K,这届程序员搞副业真野

最近刚完成了一个远程外包项目工作&#xff0c;钱刚到账&#xff0c;小金库又添了一笔&#xff1a; 从一开始的15K死工资&#xff0c;到现在的主业副业一共25K收入&#xff0c;最近的经济压力小了很多&#xff0c;终于也有闲钱和老婆去旅旅游&#xff0c;升级一下外设&#xff…

平板电脑的触控笔有必要买吗?平价电容笔排行榜

伴随着ipad的流行&#xff0c;部分学习党开始从传统的纸笔教学向无纸化教学转变。于是&#xff0c;原本属于苹果专利的电容笔&#xff0c;一下子就火了起来&#xff0c;不少人都对这个价格接近一千块钱的电容笔产生了浓厚的兴趣。我想&#xff0c;苹果电容笔特有的的“重力压感…

MySQL数据库基础(二):DDL,DML,DQL

六、DDL数据库操作 1、MySQL的组成结构 注&#xff1a;我们平常说的MySQL&#xff0c;其实主要指的是MySQL数据库管理软件。 一个MySQL DBMS可以同时存放多个数据库&#xff0c;理论上一个项目就对应一个数据库。如博客项目blzhujianog数据库、商城项目shop数据库、微信项目wec…

OpenCV创建一张类型为CV_8UC3的3通道彩色图像

#include <iostream> #include <opencv2/imgcodecs.hpp> #include <opencv2/opencv.hpp> #include <opencv2/highgui.hpp>int

[MySQL]MySQL库的操作

[MySQL]MySQL库的操作 文章目录 [MySQL]MySQL库的操作1. 创建数据库2. 字符集和校验规则2.1. 基本概念2.2. 查看系统默认字符集以及校验规则2.3. 查看数据库支持的字符集2.4 查看数据库支持的校验规则2.5 指明字符集和校验规则创建数据库2.6 校验规则对数据库的影响 3. 删除数据…

经典轻量级神经网络(1)MobileNet V1及其在Fashion-MNIST数据集上的应用

经典轻量级神经网络(1)MobileNet V1及其在Fashion-MNIST数据集上的应用 1 MobileNet V1的简述 自从2017年由谷歌公司提出&#xff0c;MobileNet可谓是轻量级网络中的Inception&#xff0c;经历了一代又一代的更新。 MobileNet 应用了Depthwise 深度可分离卷积来代替常规卷积…

【hadoop】Google的基本思想

Google的基本思想 三架马车GFS分布式文件系统的核心架构和原理机架感知 MapReduce计算模型PageRank问题MapReduce BigTable 三架马车 Google的基本思想主要有三个&#xff0c;称之为三架马车&#xff0c;分别是GFS&#xff08;Google File System&#xff09;、MapReduce计算模…

gitlab/gerrit

gitlab/gerrit 1. gitlab2. gerrit2.1 环境准备2.2 下载软件2.3 创建启动账户2.4 安装gerrit2.5 创建登录账户2.6 启动服务2.7 修改配置文件2.8 配置反向代理(nginx)2.9 gerrit主页 3. gitlabgerrit3.1 配置gerrit replication功能&#xff08;用于复制具体项目&#xff09;3.2…

深入浅出讲解Stable Diffusion原理,新手也能看明白

说明 最近一段时间对多模态很感兴趣&#xff0c;尤其是Stable Diffusion&#xff0c;安装了环境&#xff0c;圆了自己艺术家的梦想。看了这方面的一些论文&#xff0c;也给人讲过一些这方面的原理&#xff0c;写了一些文章&#xff0c;具体可以参考我的文章&#xff1a; 北方…

51单片机驱动 mg996r金属舵机 STC89C52单片机直接驱动金属大舵机

/*无论是大舵机&#xff0c;还是小舵机&#xff0c;控制方法都一样会区别在 大舵机只能接P0口&#xff08;此口外接上拉&#xff0c;驱动电流最大&#xff09;小舵机任意口 */ //#include<reg51.h> //#define uint unsigned int //#define uchar unsigned char //sbit S…