尝试读取或写入受保护的内存。这通常指示其他内存已损坏 ,新中二代身份证读取 Syn_ReadMsg,Syn_R

最近在做一个项目,其中涉及到身份证的读取问题,用的是新中二代身份证的读卡器,厂商有发送过来DLL,可是一调用,开始时读取信息很成功,但是,没几次程序就崩毁了,有时候直接就关闭,有时候就跳出错误提示:尝试读取或写入受保护的内存。这通常指示其他内存已损坏,出错的函数是Syn_ReadMsg,

    原型:

    [DllImport("SynIDCardAPI.dll", EntryPoint = "Syn_ReadMsg", CharSet = CharSet.Ansi)]        

    public static extern int Syn_ReadMsg(int iPortID, int iIfOpen, ref IDCardData pIDCardData); 

   被这个几乎要弄到吐血,网上搜答案看到很多同学都遇到过这样的问题。给我启发最大的是一个说New 一个Image,但是Syn_ReadMsg()里面没有new Image 的啊,百思不得其解。,然后继续找,最后有一个方案说是用Syn_ReadBaseMsg代替Syn_ReadMsg,我用这个方案,果然不会报错。

附上源码:这个是使用Syn_ReadBaseMsg来读取身份证信息,读取到的信息文字跟图片是分别存放在两个指针里的,如果要获取图片信息,得另行处理。如果只是仅仅想读取身份证的文字信息的话,可以使用下面的函数

int port;//端口号	   
    string baut;//波特率
    string passporInfo;//读身份证后返回的信息
     
    /// <summary>
    /// 获取身份证信息
    /// </summary>	 
    public string GetPassPortInfo()
    {
      passporInfo = null;

      #region 自动寻找读卡器
      
      int i, nRet;
      uint[] iBaud = new uint[1];
      i = Syn_FindReader(); //自动寻找读卡器 返回值:0未找到 其他	串口1~16 USB:1001~1016

      if (i > 0)
      {
        port = i;
        if (port < 1000)
        {
          System.Threading.Thread.Sleep(200);
          nRet = Syn_GetCOMBaud(port, ref iBaud[0]);//该函数只用于SAM采用RS232串口的情形,如果采用USB接口则不支持该API,此处端口号必须为1-16,表示串口。								  
          baut = Convert.ToString(iBaud[0]);
        }
      }
      else
      {
        //stmp = Convert.ToString(System.DateTime.Now) + "  没有找到身份证读卡器";
         // MessageBox.Show(stmp);
        return;
      }
      #endregion

      IDCardData CardMsg = new IDCardData();
      int Ret;
      byte[] pucIIN = new byte[4];
      byte[] pucSN = new byte[8];
      string errStr;

      if (Syn_OpenPort(port) == 0)
      {
        if (Syn_SetMaxRFByte(port, 80, 0) == 0)
        {
          Ret = Syn_StartFindIDCard(port, ref pucIIN[0], 0); //开始找卡 iIfOpen:0表示不在该函数内部打开和关闭串口,此时确保之前调用了Syn_OpenPort来打开端口
          Ret = Syn_SelectIDCard(port, ref pucSN[0], 0);//选卡

          string cardMsg = new string(' ', 256);  //身份证基本信息返回长度为256
          string imgMsg = new string(' ', 1024);  //身份证图片信息返回长度为1024
          IntPtr msg = Marshal.StringToHGlobalAnsi(cardMsg);  //无符号字符指针,指向读到的文字信息。
          uint mLen = 0; // 无符号整型数指针,指向读到的文字信息长度。
          IntPtr img = Marshal.StringToHGlobalAnsi(imgMsg);   //身份证图片
          uint iLen = 0;//无符号整型数指针,指向读到的照片信息长度。
          try
          {
            Ret = Syn_ReadBaseMsg(port, msg, ref mLen, img, ref iLen, 0);
            if (Ret == 0)
            {
              string card = Marshal.PtrToStringUni(msg);
               
              //MessageBox.Show(card);
              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);						  
            }
            else
            {
              //MessageBox.Show("读取信息失败");
              return;
            }
          }
          catch (Exception e) { errStr = e.Message; }
          finally
          {
            Marshal.FreeHGlobal(msg);
            Marshal.FreeHGlobal(img);
          }
        }
        else
        {
          return ;
        }
      }
      else
      {
         // MessageBox.Show("打开端口失败");
        return ;
      }
    }
        虽然用Syn_ReadBaseMsg不会报错,但是没过多久新的问题又来了,因为后来又提出了新的需求,那就是需要获得身份证的图片信息,因为需要鉴定是不是本人。Syn_ReadBaseMsg获得的信息,文字跟图片是分开的,,返回的图片指针,得自己处理,好吧,我又跑去处理了,可是,可是,竟然给我出来一推错误(其实我也不知道为什么是错误,总之从哪个指针里读想转化为图片转化不了,还想过先将指针转化为二进制再由二进制转化为Image,还尝试过用OPenCV里面的将指针转化为Image的功能,还是不行),当我使用 Syn_GetBmp这个函数想要获得图片的时候,好吧,我无语了,又出现了“尝试读取或写入受保护的内存。这通常指示其他内存已损坏”这个错误提示。

       折腾了半天,好吧,我再去看看Syn_ReadMsg这个函数,这个函数能够直接就获得图片,如果他不会崩溃或者跳出 尝试读取或写入受保护的内存。这通常指示其他内存已损坏这个错误,那么就很符合我的要求。可是为什么一直会出现尝试读取或写入受保护的内存。这通常指示其他内存已损坏这个错误呢,折腾了很久,估计是这样的原因:程序第一次读到了身份证的图片信息,便将其命名并放到指定文件夹(新中的命名方式有 四种)当第二次读取同一张身份证的时候,又会以同样的名称方式存放到同样的文件夹下,因为同名,所以第二次读到的图片需要覆盖第一次的图片,但是第一次读到的图片可能还没被释放,这时,错误就出现了。

     怎么解决这个问题呢,我想了一个很笨的方法,每次读取到的图片放在不同的文件夹,这样就不用覆盖上一次读到的图片,我拖了一个timer让它自己读了一百次,没什么问题,估计后面再多读应该也没什么问题的吧。

直接附上源码:

/// <summary>
    /// 设置身份证的保存位置
    /// </summary>
    /// <param name="photoPath"></param>
    /// <returns></returns>
    public bool SetPhotoInfo(string photoPath)
    {
      int path, name;
      byte[] cPath = new byte[255];

      if (!System.IO.Directory.Exists(photoPath))
        System.IO.Directory.CreateDirectory(photoPath);//如果目录不存在,创建目录

      cPath = System.Text.Encoding.Default.GetBytes(photoPath);
      path = Syn_SetPhotoPath(2, ref cPath[0]);//设置照片文件指定的存储的路径
      name = Syn_SetPhotoName(3); //设置照片文件的文件名:姓名_身份证号
      if (path == 0 && name == 0)
      {
        return true;
      }
      else
      {
        return false;
      }
    }

    /// <summary>
    /// 获取身份证信息
    /// </summary>
    /// <param name="photoPath">身份证图片保存位置</param>
    /// <param name="CardMsg">读取到的身份证信息</param>
    /// <returns></returns>
    public bool GetPassPortInfo(string photoPath, out IDCardData CardMsg)
    {
      CardMsg = new IDCardData();
      bool flag = false;
      int port;

      int i;

      uint[] iBaud = new uint[1];
      i = Syn_FindReader();
      if (i > 0)
      {
        port = i;
      }
      else
      {
        return false;
      }

      if (!SetPhotoInfo(photoPath))
      {
        return false;
      }

      int nRet;
      byte[] pucIIN = new byte[4];
      byte[] pucSN = new byte[8];


      if (Syn_OpenPort(port) == 0)
      {
        if (Syn_SetMaxRFByte(port, 80, 0) == 0)
        {
          nRet = Syn_StartFindIDCard(port, ref pucIIN[0], 0);
          nRet = Syn_SelectIDCard(port, ref pucSN[0], 0);
          nRet = Syn_ReadMsg(port, 0, ref CardMsg);
          if (nRet == 0)
          {
            flag = true;
          }
        }
      }
      return flag;
    }
       总结:这个问题折腾了我很久,其实现在想想原因还是明了的,另外我做测试的时候,一直都是拿一张身份证在反复地读(我比较懒,对于要重复跑的程序都是拖个时间控件让他自己跑),这样反复的读同一张身份证,那么一只获取到的是同样命名放在同样路径下的图片,那么就会出现有可能同一张图片要覆盖正在使用的图片,当然会报错(就像你想删除一个正在打开的文件。直接拿新中二代身份证读卡器配套的软件来读同一张身份证,读了十几次,那个软件也自己崩溃掉了,汗。),我猜想如果用不同的身份证做测试,命名不一样,估计Syn_ReadMsg这个函数就不会有错误了(话说我也没有那么多身份证拿来测试,这仅是我的猜想啊)。 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值