需要用到dll和文件:
其中3個dll文件是需要調用的dll,license.dat文件為解壓圖片的授權文件
以下是需要用到的dll里面的方法:

/************************端口類API *************************/ [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_SetMaxRFByte", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_SetMaxRFByte(int iPort, byte ucByte, int iIfOpen); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_GetCOMBaud", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_GetCOMBaud(int iPort, ref uint puiBaudRate); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_SetCOMBaud", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_SetCOMBaud(int iPort, uint uiCurrBaud, uint uiSetBaud); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_OpenPort", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_OpenPort(int iPort); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_ClosePort", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_ClosePort(int iPort); /**************************SAM類函數 **************************/ [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_ResetSAM", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_ResetSAM(int iPort, int iIfOpen); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_GetSAMStatus", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_GetSAMStatus(int iPort, int iIfOpen); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_GetSAMID", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_GetSAMID(int iPort, ref byte pucSAMID, int iIfOpen); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_GetSAMIDToStr", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_GetSAMIDToStr(int iPort, ref byte pcSAMID, int iIfOpen); /*************************身份證卡類函數 ***************************/ [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_StartFindIDCard", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_StartFindIDCard(int iPort, ref byte pucIIN, int iIfOpen); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_SelectIDCard", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_SelectIDCard(int iPort, ref byte pucSN, int iIfOpen); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_ReadBaseMsg", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_ReadBaseMsg(int iPort, IntPtr pucCHMsg, ref uint puiCHMsgLen, IntPtr pucPHMsg, ref uint puiPHMsgLen, int iIfOpen); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_ReadIINSNDN", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_ReadIINSNDN(int iPort, ref byte pucIINSNDN, int iIfOpen); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_ReadBaseMsgToFile", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_ReadBaseMsgToFile(int iPort, ref byte pcCHMsgFileName, ref uint puiCHMsgFileLen, ref byte pcPHMsgFileName, ref uint puiPHMsgFileLen, int iIfOpen); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_ReadIINSNDNToASCII", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_ReadIINSNDNToASCII(int iPort, ref byte pucIINSNDN, int iIfOpen); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_ReadNewAppMsg", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_ReadNewAppMsg(int iPort, ref byte pucAppMsg, ref uint puiAppMsgLen, int iIfOpen); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_GetBmp", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_GetBmp(string Wlt_File, int iPort); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_ReadMsg", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_ReadMsg(int iPortID, int iIfOpen, ref IDCardData pIDCardData); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_FindReader", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_FindReader(); /***********************設置附加功能函數 ************************/ [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_SetPhotoPath", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_SetPhotoPath(int iOption, ref byte cPhotoPath); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_SetPhotoType", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_SetPhotoType(int iType); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_SetPhotoName", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_SetPhotoName(int iType); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_SetSexType", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_SetSexType(int iType); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_SetNationType", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_SetNationType(int iType); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_SetBornType", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_SetBornType(int iType); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_SetUserLifeBType", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_SetUserLifeBType(int iType); [DllImport("idCardDll\\SynIDCardAPI.dll", EntryPoint = "Syn_SetUserLifeEType", CharSet = CharSet.Ansi, SetLastError = true)] public static extern int Syn_SetUserLifeEType(int iType, int iOption); [DllImport("idCardDll\\WltRS.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)] static extern int GetBmp(string pucPHMsg, int intf);
讀取身份證信息分兩個階段,第一個階段是獲取基本信息,第二個階段是獲取圖片信息
獲取基本信息很簡單,直接調用dll的方法就可以完成,部分代碼如下:

int status = 1;//默認為找不到身份證 try { //先查找讀卡器 int i, nRet; i = Syn_FindReader(); //只支持usb if (i > 1000) { var nPort = i; if (Syn_OpenPort(nPort) == 0) { Thread.Sleep(5); if (Syn_SetMaxRFByte(nPort, 80, 0) == 0) { Thread.Sleep(5); byte[] pucIIN = new byte[4]; byte[] pucSN = new byte[8]; IDCardData cardMsg = new IDCardData(); nRet = Syn_StartFindIDCard(nPort, ref pucIIN[0], 0); //找卡 nRet = Syn_SelectIDCard(nPort, ref pucSN[0], 0); //選卡 string cardStr = new string(' ', 256); //身份證基本信息返回長度為256 string imgMsg = new string(' ', 1024); //身份證圖片信息返回長度為1024 IntPtr msg = Marshal.StringToHGlobalAnsi(cardStr); //身份證基本信息 IntPtr img = Marshal.StringToHGlobalAnsi(imgMsg); //身份證圖片 uint mLen = 0; uint iLen = 0; nRet = Syn_ReadBaseMsg(nPort, msg, ref mLen, img, ref iLen, 0); if (nRet == 0) { Syn_ClosePort(nPort); string card = Marshal.PtrToStringUni(msg); char[] cartb = card.ToCharArray(); cardMsg.Name = (new string(cartb, 0, 15)).Trim(); cardMsg.Sex = new string(cartb, 15, 1); cardMsg.Nation = new string(cartb, 16, 2); cardMsg.Born = new string(cartb, 18, 8); cardMsg.Address = (new string(cartb, 26, 35)).Trim(); cardMsg.IDCardNo = new string(cartb, 61, 18); cardMsg.GrantDept = (new string(cartb, 79, 15)).Trim(); cardMsg.UserLifeBegin = new string(cartb, 94, 8); cardMsg.UserLifeEnd = new string(cartb, 102, 8);
獲取圖片方法有點麻煩,首先通過Syn_ReadBaseMsg方法返回的圖片指針和長度獲取的字節信息:

byte[] data=new byte[iLen]; Marshal.Copy(img,data,0,data.Length);
將這個獲取到的字節信息保存為文件,注意,這里的文件不是圖片文件,而是一個wlt類型文件,如果需要獲取圖片,那么還需要通過GetBmp方法做轉換

private static string GetImageBase64Str(byte[] data, string idCardNo) { if (!CheckLicense()) return string.Empty;//license.dat文件失敗,那么就不能去獲取文件 var wltFileName = Path.Combine(_imageDirPath, string.Format("{0}.wlt", idCardNo)); if (File.Exists(wltFileName)) { File.Delete(wltFileName); } using (FileStream fs = new FileStream(wltFileName, FileMode.Create)) { fs.Write(data, 0, data.Length); fs.Close(); } var nRet = GetBmp(wltFileName, 2); if (nRet == 1) { // Thread.Sleep(200); string bmpFileName = Path.Combine(_imageDirPath, string.Format("{0}.bmp", idCardNo)); if (File.Exists(bmpFileName)) { var str = GetFileBase64Str(bmpFileName); // File.Delete(bmpFileName); return str; } } return string.Empty; }
代碼中將圖片信息轉換為了base64字符串。
注意:
1.由於GetBmp調用了sdtapi.dll中的方法,所以在之前要先要關閉讀取的端口,不然會報錯。(這是網上用戶提醒的,我沒有測試過不關閉的情況)
2.GetBmp方法會在wlt文件的當前目錄下生成一個同名的bmp文件,這個文件就是身份證圖片文件
3.獲取圖片方法需要廠家的授權文件,我用的dll和授權文件都是新中新的,其中授權文件為license.dat,這個文件必須存放在C盤根目錄下,並且不能改名,不然讀取會出錯

//檢測授權文件 private static bool CheckLicense() { var licenceFile = @"c:\license.dat"; var localFile = @"idCardDll\license.dat"; try { if (!File.Exists(licenceFile)) { //不存在,拷貝文件過去 File.Copy(localFile,licenceFile,true); return true; } //文件存在,需要判斷數據是否一致 string local = string.Empty; string license = string.Empty; using (FileStream fs = new FileStream(localFile, FileMode.Open, FileAccess.Read)) { using (StreamReader sr = new StreamReader(fs)) { local = sr.ReadToEnd(); } } using (FileStream fs = new FileStream(licenceFile, FileMode.Open, FileAccess.Read)) { using (StreamReader sr = new StreamReader(fs)) { license = sr.ReadToEnd(); } } if (local == license) { return true; } else { File.Copy(localFile, licenceFile, true); return true; } } catch (Exception ex) { //"判斷license失敗,不能去獲取圖片"; return false; } }
在轉換圖片之前先判斷授權文件,成功在執行轉換操作。
最終結果是將信息存儲IDCardData結構體中,圖片信息轉換為base64str。

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] public struct IDCardData { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string Name; //姓名 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)] public string Sex; //性別 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] public string Nation; //名族 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 18)] public string Born; //出生日期 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 72)] public string Address; //住址 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 38)] public string IDCardNo; //身份證號 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string GrantDept; //發證機關 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 18)] public string UserLifeBegin; // 有效開始日期 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 18)] public string UserLifeEnd; // 有效截止日期 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 38)] public string reserved; // 保留 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] public string PhotoBase64Str; // 照片路徑 }
WltRS.dll一定要新一點的,我以前用的是2007年的,在轉換頭像的時候總是報錯,找了一個新的,是2012年的,就好了。
以下是我寫的一個demo,可以直接調用獲取,包含了32位和64的驅動
https://gitee.com/sczmzx/IdCardReaderHelper/tree/master/IdCardReaderHelper