公安部已经大规模在全国范围内推广第二代居民身份证的换发工作,目前,许多地区二代证换发工作已经进行了很久。但是,相对应于二代证的推广,社会上许许多多的应用系统都还没有对二代证读卡开发相应的接口,为此,我写了一个通用的二代证机具读卡类,希望能对各位在各自的系统中开发这样的接口提供帮助。
    本类仅仅提供读卡的用法,写卡的方式我并没有写在里面,但是,相应的写调用我已经声明在里面,希望各位大侠能独自研究应用。
    该类接口具有如下特点:
    1、通用于目前市场上各个机具厂商的二代证读(写)机具。(想想,为不同厂商开发不同的接口确实令人头疼的,且由于接口不兼容,容易被客户骂死!)
    2、自动适应串口、USB口的各种机具
    3、能读文字信息,但是,要想正确读照片,必须需要机具厂商的授权文件Termb.Lic,且授权文件必须放在C盘根目录下。(我总不能不照顾机具厂商的利益吧)
    4、除了上面第三条之外,您甚至不用安装机具的驱动程序,接上二代证机具即可使用。
    
    废话少说,下面看实现方法:

using System;
 using System.Drawing;
 using System.Collections;
 using System.ComponentModel;
 using System.Windows.Forms;
 using System.Runtime.InteropServices;
 using System.Reflection ;
 using System.IO; namespace ICCard
 {
     public class clsICCard
     {
         //首先,声明通用接口
         [DllImport("sdtapi.dll")]
         public static extern int SDT_OpenPort(int iPortID);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_ClosePort(int iPortID);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_PowerManagerBegin(int iPortID, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_AddSAMUser(int iPortID, string pcUserName, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_SAMLogin(int iPortID, string pcUserName, string pcPasswd, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_SAMLogout(int iPortID, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_UserManagerOK(int iPortID, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_ChangeOwnPwd(int iPortID, string pcOldPasswd, string pcNewPasswd, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_ChangeOtherPwd(int iPortID, string pcUserName, string pcNewPasswd, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_DeleteSAMUser(int iPortID, string pcUserName, int iIfOpen);        [DllImport("sdtapi.dll")]
         public static extern int SDT_StartFindIDCard(int iPortID, ref int pucIIN, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_SelectIDCard(int iPortID, ref int pucSN, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_ReadBaseMsg(int iPortID, string pucCHMsg, ref int puiCHMsgLen, string pucPHMsg, ref int puiPHMsgLen, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_ReadBaseMsgToFile(int iPortID, string fileName1, ref int puiCHMsgLen, string fileName2, ref int puiPHMsgLen, int iIfOpen);        [DllImport("sdtapi.dll")]
         public static extern int SDT_WriteAppMsg(int iPortID, ref byte pucSendData, int uiSendLen, ref byte pucRecvData, ref int puiRecvLen, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_WriteAppMsgOK(int iPortID, ref byte pucData, int uiLen, int iIfOpen);        [DllImport("sdtapi.dll")]
         public static extern int SDT_CancelWriteAppMsg(int iPortID, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_ReadNewAppMsg(int iPortID, ref byte pucAppMsg, ref int puiAppMsgLen, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_ReadAllAppMsg(int iPortID, ref byte pucAppMsg, ref int puiAppMsgLen, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_UsableAppMsg(int iPortID, ref byte ucByte, int iIfOpen);        [DllImport("sdtapi.dll")]
         public static extern int SDT_GetUnlockMsg(int iPortID, ref byte strMsg, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_GetSAMID(int iPortID, ref byte StrSAMID, int iIfOpen);        [DllImport("sdtapi.dll")]
         public static extern int SDT_SetMaxRFByte(int iPortID, byte ucByte, int iIfOpen);
         [DllImport("sdtapi.dll")]
         public static extern int SDT_ResetSAM(int iPortID, int iIfOpen);        [DllImport("WltRS.dll")]
         public static extern int GetBmp(string file_name, int intf);        public delegate void De_ReadICCardComplete(clsEDZ objEDZ);
         public event De_ReadICCardComplete ReadICCardComplete;
         private clsEDZ objEDZ = new clsEDZ();
         private int EdziIfOpen = 1;               //自动开关串口
         int EdziPortID;        
         public clsICCard()
         {        }
         public bool ReadICCard()
         {           
             bool bUsbPort = false;
             int intOpenPortRtn = 0;
             int rtnTemp = 0;
             int pucIIN = 0;
             int pucSN = 0;
             int puiCHMsgLen = 0;
             int puiPHMsgLen = 0;            objEDZ = new clsEDZ();
             //检测usb口的机具连接,必须先检测usb
             for (int iPort = 1001; iPort <= 1016; iPort++)
             {
                 intOpenPortRtn = SDT_OpenPort(iPort);
                 if (intOpenPortRtn == 144)
                 {
                     EdziPortID = iPort;
                     bUsbPort = true;
                     break;
                 }
             }
             //检测串口的机具连接
             if (!bUsbPort)
             {
                 for (int iPort = 1; iPort <= 2; iPort++)
                 {
                     intOpenPortRtn = SDT_OpenPort(iPort);
                     if (intOpenPortRtn == 144)
                     {
                         EdziPortID = iPort;
                         bUsbPort = false;
                         break;
                     }
                 }
             }
             if (intOpenPortRtn != 144)
             {                             
                 MessageBox.Show("端口打开失败,请检测相应的端口或者重新连接读卡器!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                 return false;
             }
             //在这里,如果您想下一次不用再耗费检查端口的检查的过程,您可以把 EdziPortID 保存下来,可以保存在注册表中,也可以保存在配置文件中,我就不多写了,但是,
             //您要考虑机具连接端口被用户改变的情况哦            //下面找卡
             rtnTemp = SDT_StartFindIDCard(EdziPortID, ref pucIIN, EdziIfOpen);
             if (rtnTemp != 159)
             {
                 rtnTemp = SDT_StartFindIDCard(EdziPortID, ref pucIIN, EdziIfOpen);  //再找卡
                 if (rtnTemp != 159)
                 {                                   
                     rtnTemp = SDT_ClosePort(EdziPortID);
                     MessageBox.Show("未放卡或者卡未放好,请重新放卡!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                     return false;
                 }
             }
             //选卡
             rtnTemp = SDT_SelectIDCard(EdziPortID, ref pucSN, EdziIfOpen);
             if (rtnTemp != 144)
             {
                 rtnTemp = SDT_SelectIDCard(EdziPortID, ref pucSN, EdziIfOpen);  //再选卡
                 if (rtnTemp != 144)
                 {                                      
                     rtnTemp = SDT_ClosePort(EdziPortID);
                     MessageBox.Show("读卡失败!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                     return false;
                 }
             }
             //注意,在这里,用户必须有应用程序当前目录的读写权限
             FileInfo objFile = new FileInfo("wz.txt");
             if (objFile.Exists)
             {
                 objFile.Attributes = FileAttributes.Normal;
                 objFile.Delete();
             }
             objFile = new FileInfo("zp.bmp");
             if (objFile.Exists)
             {
                 objFile.Attributes = FileAttributes.Normal;
                 objFile.Delete();
             }
             objFile = new FileInfo("zp.wlt");
             if (objFile.Exists)
             {
                 objFile.Attributes = FileAttributes.Normal;
                 objFile.Delete();
             }
             rtnTemp = SDT_ReadBaseMsgToFile(EdziPortID, "wz.txt", ref puiCHMsgLen, "zp.wlt", ref puiPHMsgLen, EdziIfOpen);
             if (rtnTemp != 144)
             {                        
                 rtnTemp = SDT_ClosePort(EdziPortID);
                 MessageBox.Show("读卡失败!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                 return false;
             }
             //下面解析照片,注意,如果在C盘根目录下没有机具厂商的授权文件Termb.Lic,照片解析将会失败
             if (bUsbPort)
                 rtnTemp = GetBmp("zp.wlt", 2);
             else
                 rtnTemp = GetBmp("zp.wlt", 1);
             switch (rtnTemp)
             {
                 case 0:
                     MessageBox.Show("调用sdtapi.dll错误!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                     break;
                 case 1:   //正常
                     break;
                 case -1:
                     MessageBox.Show("相片解码错误!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                     break;
                 case -2:
                     MessageBox.Show("wlt文件后缀错误!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                     break;
                 case -3:
                     MessageBox.Show("wlt文件打开错误!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                     break;
                 case -4:
                     MessageBox.Show("wlt文件格式错误!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                     break;
                 case -5:
                     MessageBox.Show("软件未授权!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                     break;
                 case -6:
                     MessageBox.Show("设备连接错误!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                     break;
             }
             rtnTemp = SDT_ClosePort(EdziPortID);
             FileInfo f = new FileInfo("wz.txt");
             FileStream fs = f.OpenRead();
             byte[] bt = new byte[fs.Length];
             fs.Read(bt, 0, (int)fs.Length);
             fs.Close();            string str = System.Text.UnicodeEncoding.Unicode.GetString(bt);
             = System.Text.UnicodeEncoding.Unicode.GetString(bt, 0, 30).Trim();
             objEDZ.Sex_Code = System.Text.UnicodeEncoding.Unicode.GetString(bt, 30, 2).Trim();
             objEDZ.NATION_Code = System.Text.UnicodeEncoding.Unicode.GetString(bt, 32, 4).Trim();
             string strBird = System.Text.UnicodeEncoding.Unicode.GetString(bt, 36, 16).Trim();
             objEDZ.BIRTH = Convert.ToDateTime(strBird.Substring(0, 4) + "年" + strBird.Substring(4, 2) + "月" + strBird.Substring(6) + "日");
             objEDZ.ADDRESS = System.Text.UnicodeEncoding.Unicode.GetString(bt, 52, 70).Trim();
             objEDZ.IDC = System.Text.UnicodeEncoding.Unicode.GetString(bt, 122, 36).Trim();
             objEDZ.REGORG = System.Text.UnicodeEncoding.Unicode.GetString(bt, 158, 30).Trim();
             string strTem = System.Text.UnicodeEncoding.Unicode.GetString(bt, 188, bt.GetLength(0) - 188).Trim();
             objEDZ.STARTDATE = Convert.ToDateTime(strTem.Substring(0, 4) + "年" + strTem.Substring(4, 2) + "月" + strTem.Substring(6, 2) + "日");
             strTem = strTem.Substring(8);
             if (strTem.Trim() != "长期")
             {
                 objEDZ.ENDDATE = Convert.ToDateTime(strTem.Substring(0, 4) + "年" + strTem.Substring(4, 2) + "月" + strTem.Substring(6, 2) + "日");
             }
             else
             {
                 objEDZ.ENDDATE = DateTime.MaxValue;
             }
             objFile = new FileInfo("zp.bmp");
             if (objFile.Exists)
             {
                 Image img = Image.FromFile("zp.bmp");
                 objEDZ.PIC_Image=(Image)img.Clone();
                 System.IO.MemoryStream m = new MemoryStream();
                 img.Save(m, System.Drawing.Imaging.ImageFormat.Jpeg);
                 objEDZ.PIC_Byte = m.ToArray();
                 img.Dispose();
                 img = null;
             }
             ReadICCardComplete(objEDZ);           
             return true;
         }     }
     public class clsEDZ
     {
         private System.Collections.SortedList lstMZ = new SortedList();
         private string _Name;   //姓名
         private string _Sex_Code;   //性别代码
         private string _Sex_CName;   //性别
         private string _IDC;      //身份证号码
         private string _NATION_Code;   //民族代码
         private string _NATION_CName;   //民族
         private DateTime _BIRTH;     //出生日期
         private string _ADDRESS;    //住址
         private string _REGORG;     //签发机关
         private DateTime _STARTDATE;    //身份证有效起始日期
         private DateTime _ENDDATE;    //身份证有效截至日期
         private string _Period_Of_Validity_Code;   //有效期限代码,许多原来系统上面为了一代证考虑,常常存在这样的字段,二代证中已经没有了
         private string _Period_Of_Validity_CName;   //有效期限
         private byte[] _PIC_Byte;    //照片二进制
         private Image _PIC_Image;   //照片        public clsEDZ()
         {
             lstMZ.Add("01", "汉族");
             lstMZ.Add("02", "蒙古族");
             lstMZ.Add("03", "回族");
             lstMZ.Add("04", "藏族");
             lstMZ.Add("05", "维吾尔族");
             lstMZ.Add("06", "苗族");
             lstMZ.Add("07", "彝族");
             lstMZ.Add("08", "壮族");
             lstMZ.Add("09", "布依族");
             lstMZ.Add("10", "朝鲜族");
             lstMZ.Add("11", "满族");
             lstMZ.Add("12", "侗族");
             lstMZ.Add("13", "瑶族");
             lstMZ.Add("14", "白族");
             lstMZ.Add("15", "土家族");
             lstMZ.Add("16", "哈尼族");
             lstMZ.Add("17", "哈萨克族");
             lstMZ.Add("18", "傣族");
             lstMZ.Add("19", "黎族");
             lstMZ.Add("20", "傈僳族");
             lstMZ.Add("21", "佤族");
             lstMZ.Add("22", "畲族");
             lstMZ.Add("23", "高山族");
             lstMZ.Add("24", "拉祜族");
             lstMZ.Add("25", "水族");
             lstMZ.Add("26", "东乡族");
             lstMZ.Add("27", "纳西族");
             lstMZ.Add("28", "景颇族");
             lstMZ.Add("29", "柯尔克孜族");
             lstMZ.Add("30", "土族");
             lstMZ.Add("31", "达翰尔族");
             lstMZ.Add("32", "仫佬族");
             lstMZ.Add("33", "羌族");
             lstMZ.Add("34", "布朗族");
             lstMZ.Add("35", "撒拉族");
             lstMZ.Add("36", "毛南族");
             lstMZ.Add("37", "仡佬族");
             lstMZ.Add("38", "锡伯族");
             lstMZ.Add("39", "阿昌族");
             lstMZ.Add("40", "普米族");
             lstMZ.Add("41", "塔吉克族");
             lstMZ.Add("42", "怒族");
             lstMZ.Add("43", "乌孜别克族");
             lstMZ.Add("44", "俄罗斯族");
             lstMZ.Add("45", "鄂温克族");
             lstMZ.Add("46", "德昂族");
             lstMZ.Add("47", "保安族");
             lstMZ.Add("48", "裕固族");
             lstMZ.Add("49", "京族");
             lstMZ.Add("50", "塔塔尔族");
             lstMZ.Add("51", "独龙族");
             lstMZ.Add("52", "鄂伦春族");
             lstMZ.Add("53", "赫哲族");
             lstMZ.Add("54", "门巴族");
             lstMZ.Add("55", "珞巴族");
             lstMZ.Add("56", "基诺族");
             lstMZ.Add("57", "其它");
             lstMZ.Add("98", "外国人入籍");
         }        public string Name
         {
             get { return _Name; }
             set { _Name = value; }
         }
         public string Sex_Code
         {
             get { return _Sex_Code; }
             set
             {
                 _Sex_Code = value;
                 switch (value)
                 {
                     case "1":
                         Sex_CName = "男";
                         break;
                     case "2":
                         Sex_CName = "女";
                         break;
                 }
             }
         }
         public string Sex_CName
         {
             get { return _Sex_CName; }
             set { _Sex_CName = value; }
         }
         public string IDC
         {
             get { return _IDC; }
             set { _IDC = value; }
         }
         public string NATION_Code
         {
             get { return _NATION_Code; }
             set
             {
                 _NATION_Code = value;
                 if (lstMZ.Contains(value))
                     NATION_CName = lstMZ[value].ToString();
             }
         }
         public string NATION_CName
         {
             get { return _NATION_CName; }
             set { _NATION_CName = value; }
         }
         public DateTime BIRTH
         {
             get { return _BIRTH; }
             set { _BIRTH = value; }
         }
         public string ADDRESS
         {
             get { return _ADDRESS; }
             set { _ADDRESS = value; }
         }
         public string REGORG
         {
             get { return _REGORG; }
             set { _REGORG = value; }
         }
         public DateTime STARTDATE
         {
             get { return _STARTDATE; }
             set { _STARTDATE = value; }
         }
         public DateTime ENDDATE
         {
             get { return _ENDDATE; }
             set
             {
                 _ENDDATE = value;
                 if (_ENDDATE == DateTime.MaxValue)
                 {
                     _Period_Of_Validity_Code = "3";
                     _Period_Of_Validity_CName = "长期";
                 }
                 else
                 {
                     if (_STARTDATE != DateTime.MinValue)
                     {
                         switch (value.AddDays(1).Year - _STARTDATE.Year)
                         {
                             case 5:
                                 _Period_Of_Validity_Code = "4";
                                 _Period_Of_Validity_CName = "5年";
                                 break;
                             case 10:
                                 _Period_Of_Validity_Code = "1";
                                 _Period_Of_Validity_CName = "10年";
                                 break;
                             case 20:
                                 _Period_Of_Validity_Code = "2";
                                 _Period_Of_Validity_CName = "20年";
                                 break;
                         }
                     }
                 }            }
         }
         public string Period_Of_Validity_Code
         {
             get { return _Period_Of_Validity_Code; }
             set { _Period_Of_Validity_Code = value; }
         }
         public string Period_Of_Validity_CName
         {
             get { return _Period_Of_Validity_CName; }
             set { _Period_Of_Validity_CName = value; }
         }
         public byte[] PIC_Byte
         {
             get { return _PIC_Byte; }
             set { _PIC_Byte = value; }
         }
         public Image PIC_Image
         {
             get { return _PIC_Image; }
             set { _PIC_Image = value; }
         }    }
 }


   类中使用到了两个dll文件(sdtapi.dll和WltRS.dll),