Browse Source

Add hardwarekey

+ Add a hardware key register check
- Modify the function of filter and evaluation to fit the hardware key
ZhuYifan 5 years ago
parent
commit
4a01a1ee26

+ 28 - 3
WpfTest1/MainWindow.xaml.cs

@@ -28,6 +28,7 @@ namespace WpfTest1
         //double lowBp;                                         //BP界面低压
         DateTime lastSettingLogin;                              //上一次在系统设置界面登陆的时间
         public Toolkits.Config cfg;                //从数据库取配置的类
+        DogOperator dop = new DogOperator(Constants.registerPid, Constants.registerUid);
 
         Patient filterPatient;
         Patient evaluationPatient;
@@ -66,7 +67,7 @@ namespace WpfTest1
 
         //初始化全部组件后需要先输入医生密码才能进入
         private void MetroWindow_Loaded(object sender, RoutedEventArgs e)
-        {   
+        {
             //之后测试登陆
             SmallDialogs.LoginWindow lw = new SmallDialogs.LoginWindow(this);
             lw.ShowDialog();
@@ -74,18 +75,26 @@ namespace WpfTest1
             {
                 this.Close();
             }
+
+            bool registerFlag = dop.checkSoftwareRegister();
+            if (!registerFlag && Constants.productionEnvironment)
+            {
+                MessageBox.Show("未找到硬件授权Key,请确认插入后重试", "错误");
+                this.Close();
+            }
+
             //显示医生姓名
             if (loginDoctor != null)
             {
                 loginedDoctorName.Content = "欢迎您, " + loginDoctor.name;
                 return;
             }
+            
             loadQuestionaire(filterQuestionaire, "filter");
             loadQuestionaire(evaluationQuestionaire, "evaluation");
             labelHomepageCversion.Content = "编译日期:" + Toolkits.Constants.compileDate;
             labelSoftwareName.Content = String.Format("欢迎使用{0}", Constants.softwareName);
-
-
+            
         }
 
         private void loadQuestionaire(List<QuestionAnswerPair> oneQuestionaire, string type = "filter")
@@ -494,6 +503,13 @@ namespace WpfTest1
         /// <param name="e">默认</param>
         private void buttonSubmitFilter_Click(object sender, RoutedEventArgs e)
         {
+            int[] timesLimit =  dop.getTimesCount();
+            if(Constants.productionEnvironment && timesLimit[1] > timesLimit[0])
+            {
+                MessageBox.Show("此功能已超过Key授权次数,请使用一个新的Key进行操作。", "提示");
+                return;
+            }
+
             int inserted_r_id;
             resultsFilter = JsonMapper.ToJson(filterUserSelection);
             //MessageBox.Show(results);
@@ -507,6 +523,7 @@ namespace WpfTest1
                 MessageBox.Show("储存筛查报告错误\r\n调试信息:" + err.Message + "\r\n" + err.StackTrace, "错误");
                 return;
             }
+            dop.addOneCount();
             MessageBoxResult dr = MessageBox.Show("保存筛查结果成功,是否生成报告?", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Question);
             if (dr == MessageBoxResult.OK)
             {
@@ -832,6 +849,13 @@ namespace WpfTest1
         /// <param name="e">默认</param>
         private void buttonSubmitEvaluation_Click(object sender, RoutedEventArgs e)
         {
+            int[] timesLimit = dop.getTimesCount();
+            if (Constants.productionEnvironment && timesLimit[1] > timesLimit[0])
+            {
+                MessageBox.Show("此功能已超过Key授权次数,请使用一个新的Key进行操作。", "提示");
+                return;
+            }
+
             int inserted_r_id;
             resultsFilter = JsonMapper.ToJson(filterUserSelection);
             resultsEvaluation = JsonMapper.ToJson(evaluationUserSelection);
@@ -855,6 +879,7 @@ namespace WpfTest1
                 MessageBox.Show("储存筛查报告错误\r\n调试信息:" + err.Message + "\r\n" + err.StackTrace, "错误");
                 return;
             }
+            dop.addOneCount();
             MessageBoxResult dr = MessageBox.Show("保存成功,是否生成报告?", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Question);
             if (dr == MessageBoxResult.OK)
             {

+ 0 - 51
WpfTest1/Toolkits/Config.cs

@@ -33,61 +33,10 @@ namespace WpfTest1.Toolkits
                     case "organization_pw":
                         organization_pw = middle[key];
                         break;
-                    case "organization_active_code":
-                        organization_active_code = middle[key];
-                        break;
                     default:
                         break;
                 }
             }
         }
-
-        public bool CheckRegisterCode(string o_name, string o_pw,string o_code)
-        {
-            if (o_name == "" || o_pw == "" || o_code == "")
-            {
-                return false;
-            }
-            string pubkey;
-            try
-            {
-                XmlDocument xdoc = new XmlDocument();
-                string file = Toolkits.Constants.pubkeyPath;
-                xdoc.Load(file);
-                pubkey = xdoc.InnerXml;
-            }
-            catch (Exception err)
-            {
-                throw new Exception("pubkey file is error!",err);
-            }
-            
-            string result = o_name + o_pw;
-            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024);
-            rsa.FromXmlString(pubkey);
-            RSAPKCS1SignatureDeformatter f = new RSAPKCS1SignatureDeformatter(rsa);
-            f.SetHashAlgorithm("SHA1");
-
-            try
-            {
-                byte[] key = Convert.FromBase64String(o_code);
-
-                SHA1Managed sha = new SHA1Managed();
-                byte[] name = sha.ComputeHash(ASCIIEncoding.ASCII.GetBytes(result));
-                if (f.VerifySignature(name, key))
-                    return true;
-                else
-                    return false;
-            }
-            catch (Exception)
-            {
-                return false;
-            }
-            
-        }
-
-        public bool CheckRegisterCode()
-        {
-            return CheckRegisterCode(organization_name, organization_pw, organization_active_code);
-        }
     }
 }

+ 6 - 4
WpfTest1/Toolkits/Constants.cs

@@ -15,16 +15,18 @@ namespace WpfTest1.Toolkits
         public static string version = "0.1.0.0";
         //编译日期
         public static string compileDate = "20200301";
+        //加密狗验证所使用的pid
+        public static string registerPid = "3DE6BA91";
+        //加密狗验证所使用的uid
+        public static string registerUid = "587E770BB077E785";
+        //是否是生产环境
+        public static bool productionEnvironment = false;
         //数据库物理地址
         public static string dbPath = System.Environment.CurrentDirectory + "\\Junde.db3";
         //数据库连接直接实用的连接字符串
         public static string Connstr = @"Data Source=" + System.Environment.CurrentDirectory + "\\Junde.db3";
-        //默认的公钥位置
-        public static string pubkeyPath = System.Environment.CurrentDirectory + "\\pubkey.xml";
         //报告存放目录
         public static string reportPath = System.Environment.CurrentDirectory + "\\reports";
-        //报告生成所需要临时存放素材的目录
-        public static string tmpPath = System.Environment.CurrentDirectory + "\\tmp";
         //各种静态素材
         public static string imgPath = System.Environment.CurrentDirectory + "\\image";
         //报告页眉的医院图标

+ 300 - 0
WpfTest1/Toolkits/DogOperator.cs

@@ -0,0 +1,300 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Runtime.InteropServices;
+
+namespace WpfTest1.Toolkits
+{
+    class DogOperator
+    {
+        private IntPtr hHandle;
+        private string activeDevicePid = "3DE6BA91";
+        private string activeDeviceUid = "587E770BB077E785";
+
+        public DogOperator()
+        {
+
+        }
+
+        public DogOperator(string pid, string uid)
+        {
+            this.activeDevicePid = pid;
+            this.activeDeviceUid = uid;
+        }
+
+        /// <summary>
+        /// 登陆时验证pid与uid时调用,pid和uid在Contraits里面约定
+        /// </summary>
+        /// <returns>true:验证成功;false:验证失败</returns>
+        public bool checkSoftwareRegister()
+        {
+            bool openFlag = openDevice(activeDevicePid);
+            if (!openFlag)
+            {
+                close_device();
+                return false;
+            }
+            int checkFlag = checkUid(this.activeDeviceUid);
+            close_device();
+            if(checkFlag == 1)
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// 获取该电子狗的报告生成阈值与当前已生成数量
+        /// </summary>
+        /// <returns>int[]:[0]为阈值,[1]为已生成数量,当两者为-1时说明出错了</returns>
+        public int[] getTimesCount()
+        {
+            int[] results = new int[] { -1, -1 };
+            bool openFlag = openDevice(activeDevicePid);
+            if (!openFlag)
+            {
+                close_device();
+                return results;
+            }
+
+            int checkFlag = checkUid(this.activeDeviceUid);
+            if (checkFlag != 1)
+            {
+                close_device();
+                return results;
+            }
+
+            readDigits(results);
+            close_device();
+            return results;
+        }
+
+        /// <summary>
+        /// 将当前已生成计数+1存入电子狗
+        /// </summary>
+        /// <returns>true:成功;false:失败</returns>
+        public bool addOneCount()
+        {
+            int[] results = new int[] { -1, -1 };
+            bool openFlag = openDevice(activeDevicePid);
+            if (!openFlag)
+            {
+                close_device();
+                return false;
+            }
+
+            int checkFlag = checkUid(this.activeDeviceUid);
+            if (checkFlag != 1)
+            {
+                close_device();
+                return false;
+            }
+
+            readDigits(results);
+            
+            if(results[0] < 0 || results[1] < 0)
+            {
+                System.Console.WriteLine("加密狗读取失败");
+                System.Console.WriteLine(String.Format("读取阈值为:{0},读取已生成计数为:{1}", results[0], results[1]));
+                close_device();
+                return false;
+            }
+
+            results[1] = results[1] + 1;
+            int writeFlag = writeDigit(results[0], results[1]);
+            if(writeFlag != 1)
+            {
+                return false;
+            }
+            close_device();
+            return true;
+        }
+
+        /// <summary>
+        /// 打开pid对应的设备
+        /// </summary>
+        /// <param name="strPID">需要打开的pid </param>
+        /// <returns>true:打开成功;false:打开失败</returns>
+        public bool openDevice(string strPID)
+        {
+            int index = 1;
+            byte[] bytPID = new byte[8];
+            bytPID = System.Text.Encoding.ASCII.GetBytes(strPID);
+            uint result = ET99_API.et_OpenToken(ref hHandle, bytPID, index);
+            if (result == ET99_API.ET_SUCCESS)
+            {
+                return true;
+            }
+            else
+            {
+                System.Console.WriteLine("打开加密狗失败!请确认您的PID正确。\r\n\r\n错误:" + ET99_API.ShowResultText(result));
+                return false;
+            }
+        }
+
+        /// <summary>
+        ///关闭类中的设备
+        /// </summary>
+        /// <returns>true:关闭成功;false:关闭失败</returns>
+        private bool close_device()
+        {
+            uint result = ET99_API.et_CloseToken(hHandle);
+            if (result == ET99_API.ET_SUCCESS)
+            {
+                //MessageBox.Show("成功关闭第一个加密狗设备!");
+                hHandle = System.IntPtr.Zero;
+                return true;
+            }
+            else
+            {
+                System.Console.WriteLine("关闭加密狗失败!\r\n\r\n错误:" + ET99_API.ShowResultText(result));
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// 验证当前设备的uid和pid是否对应,应所有功能均要使用所以单独摘出
+        /// </summary>
+        /// <param name="idToBeChecked">需要验证的uid </param>
+        /// <returns>-1:设备未正常打开;-2:uid长度不正确;0:验证失败;1:验证成功</returns>
+        private int checkUid(string idToBeChecked)
+        {
+            string strPIN = idToBeChecked;
+            byte[] bytPIN = new byte[16];
+            int flag = ET99_API.ET_VERIFY_SOPIN;
+
+            if (hHandle == System.IntPtr.Zero)
+            {
+                System.Console.WriteLine("请先打开设备!");
+                return -1;
+            }
+
+            if (strPIN.Length != 16)
+            {
+                System.Console.WriteLine("请输入有效的16位密码!");
+                return -2;
+            }
+            flag = ET99_API.ET_VERIFY_USERPIN;
+            bytPIN = System.Text.Encoding.ASCII.GetBytes(strPIN);
+            uint result = ET99_API.et_Verify(hHandle, flag, bytPIN);
+            if (result == ET99_API.ET_SUCCESS)
+            {
+                return 1;
+            }
+            else
+            {
+                System.Console.WriteLine("认证失败!\r\n\r\n错误:" + ET99_API.ShowResultText(result));
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 验证当前设备的uid和pid是否对应,应所有功能均要使用所以单独摘出
+        /// </summary>
+        /// <param name="results">用于存放数据的变量</param>
+        /// <returns>-1:设备未正常打开;-2:硬件错误;-3:权限不够;0:读取失败;1:读取成功</returns>
+        private int readDigits(int[] results)
+        {
+            results[0] = 0;
+            results[1] = 0;
+            ushort len = 0;//偏移
+            if (hHandle == System.IntPtr.Zero)
+            {
+                System.Console.WriteLine("请先打开设备!");
+                return -1;
+            }
+
+            byte[] readlen = new byte[1];
+            byte[] bytThreshold = new byte[4];
+            byte[] bytAlready = new byte[4];
+            byte[] bytReadBuffer = new byte[8];
+
+            uint resultmess = ET99_API.et_Read(hHandle, len, 1, readlen);//先读出第一个字节的数据长度到readlen中
+
+            if (resultmess == ET99_API.ET_HARD_ERROR)
+            {
+                System.Console.WriteLine("硬件错误!");
+                return -2;
+
+            }
+            if (resultmess == ET99_API.ET_ACCESS_DENY)
+            {
+                System.Console.WriteLine("权限不够!");
+                return -3;
+            }
+
+            resultmess = ET99_API.et_Read(hHandle, (ushort)(len + 1), readlen[0], bytReadBuffer);//从第二个字节开始读取数据,读取数据
+            if (resultmess == ET99_API.ET_SUCCESS)
+            {
+                for (int i = 0; i < bytThreshold.Length; ++i)
+                {
+                    bytThreshold[i] = bytReadBuffer[i];
+                    bytAlready[i] = bytReadBuffer[i + bytThreshold.Length];
+                }
+
+                results[0] = BitConverter.ToInt32(bytThreshold, 0);
+                results[1] = BitConverter.ToInt32(bytAlready, 0);
+                return 1;
+            }
+            else
+            {
+                return 0;
+            }
+            
+        }
+
+        /// <summary>
+        /// 写入阈值和当前计数
+        /// </summary>
+        /// <param name="timesThreshold">阈值数</param>
+        /// <param name="timesAlready">已生成计数</param>
+        /// <returns>-1:设备未正常打开;-2:硬件错误;-3:权限不够;0:写入失败;1:写入成功</returns>
+        private int writeDigit(int timesThreshold, int timesAlready)
+        {
+            byte[] bytesThreshold = BitConverter.GetBytes(timesThreshold);//将int32转换为字节数组
+            byte[] bytesAlready = BitConverter.GetBytes(timesAlready);
+            byte[] bTemp = new byte[bytesThreshold.Length + bytesAlready.Length + 1];//一个新的数组,第一个字节存要读取的长度,后面是要写入的数据
+            bTemp[0] = (byte)(bytesThreshold.Length + bytesAlready.Length);
+            for (int i = 0; i < bytesThreshold.Length; ++i)
+            {
+                bTemp[i + 1] = bytesThreshold[i];
+                bTemp[i + 1 + bytesThreshold.Length] = bytesAlready[i];
+            }
+            ushort len = 0;//偏移
+
+            if (hHandle == System.IntPtr.Zero)
+            {
+                System.Console.WriteLine("请先打开设备!");
+                return -1;
+            }
+
+            uint resultmess = ET99_API.et_Write(hHandle, len, bTemp.Length, bTemp);// 传入值
+
+            if (resultmess == ET99_API.ET_SUCCESS)
+            {
+                //MessageBox.Show("写入用户名成功!");
+                return 1;
+            }
+
+            if (resultmess == ET99_API.ET_HARD_ERROR)
+            {
+                System.Console.WriteLine("硬件错误!");
+                return -2;
+
+            }
+            if (resultmess == ET99_API.ET_ACCESS_DENY)
+            {
+                System.Console.WriteLine("权限不够!");
+                return -3;
+
+            }
+            return 0;
+        }
+
+    }
+}

+ 359 - 0
WpfTest1/Toolkits/ET99_API.cs

@@ -0,0 +1,359 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WpfTest1.Toolkits
+{
+    public static class ET99_API
+    {
+        #region 常量
+
+        /// <summary>
+        /// 函数执行成功 
+        /// </summary>
+        internal const int ET_SUCCESS = 0x00;
+
+        /// <summary>
+        /// 访问被拒绝,权限不够 
+        /// </summary>
+        internal const int ET_ACCESS_DENY = 0x01;
+
+        /// <summary>
+        /// 通讯错误,没有打开设备 
+        /// </summary>
+        internal const int ET_COMMUNICATIONS_ERROR = 0x02;
+
+        /// <summary>
+        /// 无效的参数,参数出错 
+        /// </summary>
+        internal const int ET_INVALID_PARAMETER = 0x03;
+
+        /// <summary>
+        /// 没有设置 PID 
+        /// </summary>
+        internal const int ET_NOT_SET_PID = 0x04;
+
+        /// <summary>
+        /// 打开指定的设备失败 
+        /// </summary>
+        internal const int ET_UNIT_NOT_FOUND = 0x05;
+
+        /// <summary>
+        /// 硬件错误 
+        /// </summary>
+        internal const int ET_HARD_ERROR = 0x06;
+
+        /// <summary>
+        /// 未知错误 
+        /// </summary>
+        internal const int ET_UNKNOWN_ERROR = 0x07;
+
+        /// <summary>
+        /// 验证 PIN码掩码 
+        /// </summary>
+        internal const int ET_PIN_ERR_MASK = 0x0F;
+
+        /// <summary>
+        /// 验证 PIN码,设备被锁定
+        /// </summary>
+        internal const int ET_PIN_ERR_LOCKED = 0xF0;
+
+        /// <summary>
+        /// 验证 PIN码错误且永远不锁死 
+        /// </summary>
+        internal const int ET_PIN_ERR_MAX = 0xFF;
+
+        /// <summary>
+        /// 表示验证普通用户 pin 
+        /// </summary>
+        internal const int ET_VERIFY_USERPIN = 0;
+
+        /// <summary>
+        /// 表示验证超级用户 pin 
+        /// </summary>
+        internal const int ET_VERIFY_SOPIN = 1;
+
+        /// <summary>
+        /// 表示数据区可读写 
+        /// </summary>
+        internal const int ET_USER_WRITE_READ = 0;
+
+        /// <summary>
+        /// 表示数据区只允许读
+        /// </summary>
+        internal const int ET_USER_READ_ONLY = 1;
+
+        /// <summary>
+        /// 常量 PID,默认的产品PID
+        /// </summary>
+        internal const string CONST_PID = "ffffffff";
+
+
+        #endregion 
+
+        /// <summary>
+        /// 根据错误码显示错误提示内容
+        /// </summary>
+        /// <param name="result"></param>
+        public static string ShowResultText(uint result)
+        {
+            switch (result)
+            {
+                case (ET_SUCCESS):
+                    {
+                        return "操作成功!";
+                    }
+                case (ET_ACCESS_DENY):
+                    {
+                        return "访问被拒绝,权限不够!";
+                    }
+                case (ET_COMMUNICATIONS_ERROR):
+                    {
+                        return "通讯错误,没有打开设备 !";
+                    }
+                case (ET_INVALID_PARAMETER):
+                    {
+                        return "无效的参数,参数出错 !";
+                    }
+                case (ET_NOT_SET_PID):
+                    {
+                        return "没有设置 PID !";
+                    }
+                case (ET_UNIT_NOT_FOUND):
+                    {
+                        return "打开指定的设备失败!";
+                    }
+                case (ET_HARD_ERROR):
+                    {
+                        return "硬件错误!";
+                    }
+                case (ET_UNKNOWN_ERROR):
+                    {
+                        return "未知错误!";
+                    }
+                case (ET_PIN_ERR_MAX):
+                    {
+                        return "PIN码错误!请核实。";
+                    }
+                case (ET_PIN_ERR_LOCKED):
+                    {
+                        return "PIN码错误!设备已经被锁死。";
+                    }
+            }
+
+            //输出剩余PIN验证次数
+            if (result > ET_PIN_ERR_LOCKED && result < ET_PIN_ERR_MAX)
+            {
+                return "PIN码验证错误!剩余重试次数:" + (result - ET_PIN_ERR_LOCKED).ToString();
+            }
+
+            return "未知代码!";
+        }
+
+        /// <summary>
+        /// 查找计算机上指定 pid 的 ET99 个数。
+        /// </summary>
+        /// <param name="pid">[in]产品标识,  为固定长度 8 个字节的字符串; </param>
+        /// <param name="count">[out]还回的设备个数;</param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_FindToken(byte[] pid, out int count);
+
+        /// <summary>
+        /// 打开指定 PID的硬件,由 index 指定打开硬件的索引, index 应该小于等于找到的 Token 数目。进入匿名用户状态。
+        /// </summary>
+        /// <param name="hHandle">[out]打开设备的句柄,返回给用户,供以后的函数调用;</param>
+        /// <param name="pid">[in]输入的硬件设备的 pid,  为固定长度 8 个字节的字符串;</param>
+        /// <param name="index">[in]打开第 index 个硬件设备。 </param>
+        /// <returns>ET_SUCCESS:执行成功。 ET_UNIT_NOT_FOUND:打开指定的设备失败。</returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_OpenToken(ref IntPtr hHandle, byte[] pid, int index);
+
+        /// <summary>
+        /// 关闭指定的设备。 
+        /// </summary>
+        /// <param name="hHandle">[in] 设备句柄。</param>
+        /// <returns>ET_SUCCESS:关闭成功。  ET_COMMUNICATIONS_ERROR:没有打开设备。</returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_CloseToken(IntPtr hHandle);
+
+        /// <summary>
+        /// 从指定的位置,读取指定的数据到指定的 BUFFER 中。此函数调用需要有User权限,且调用以后不改变安全状态。
+        /// </summary>
+        /// <param name="hHandle">:[in]设备句柄</param>
+        /// <param name="offset">[in]偏移量 </param>
+        /// <param name="len">[in]长度,不能超过 60,如果超过则需要读多次。</param>
+        /// <param name="pucReadBuf">[out]读出的数据存放此缓存区中,调用者保证缓冲区大小至少是 Len,否则可能产生系统存取异常。 </param>
+        /// <returns>第二章 API接口函数 ET_COMMUNICATIONS_ERROR:没有打开设备。ET_SUCCESS:表示成功。 ET_INVALID_PARAMETER:无效的参数。 ET_NOT_SET_PID:没有设置 PID。 ET_ACCESS_DENY:权限不够。 </returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_Read(IntPtr hHandle, ushort offset, int len, byte[] pucReadBuf);
+
+        /// <summary>
+        /// 将 buf 中,Length 长的数据写到指定的偏移。有存取权限控制。匿名状态不可用,且在普通用户状态时还需要检查设备的配置。不改变安全状态。
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄;</param>
+        /// <param name="offset">[in]偏移;</param>
+        /// <param name="len">[in]长度,不能超过 60,如果超过则需要写多次; </param>
+        /// <param name="pucReadBuf">[in]等写入的数据缓存区指针; </param>
+        /// <returns>ET_SUCCESS:表示成功。 ET_HARD_ERROR:硬件错误 ET_INVALID_PARAMETER:无效的参数。 ET_NOT_SET_PID:没有设置 PID。 ET_ACCESS_DENY:权限不够。 ET_COMMUNICATIONS_ERROR:没有打开设备。 </returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_Write(IntPtr hHandle, ushort offset, int len, byte[] pucWriteBuf);
+
+        /// <summary>
+        /// 根据参数中指定的种子,产生产品标识。种子长度不能超过 51 个字节。必须在超级用户状态下才能用,调用以后不改变安全状态。 
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄; </param>
+        /// <param name="seedlen">[in]种子; </param>
+        /// <param name="pucseed">[in]种子长度,小于等于 51; </param>
+        /// <param name="pid">[out]产生的产品标识,  为固定长度 8 个字节的字符串; </param>
+        /// <returns>ET_SUCCESS:表示成功; ET_HARD_ERROR:硬件错误 ET_INVALID_PARAMETER:无效的参数; ET_ACCESS_DENY:权限不够,需要先验证 SOPIN。 ET_COMMUNICATIONS_ERROR:没有打开设备。 </returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_GenPID(IntPtr hHandle, int seedlen, byte[] pucseed, StringBuilder pid);
+
+        /// <summary>
+        /// 产生 16 字节的随机数,放到参数指定的 BUF中。调用者需要保护 BUF至少16 字节,否则会产生系统的存取异常。该函数在匿名状态不可用,且在函数调用以后,安全状态不变。 
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄 </param>
+        /// <param name="pucRandBuf">[out]等写入的数据缓存区指针 </param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_GenRandom(IntPtr hHandle, ref byte[] pucRandBuf);
+
+        /// <summary>
+        /// 产生超级用户 PIN 码 
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄 </param>
+        /// <param name="seedlen">[in]产生超级用户密码需要的种子。 </param>
+        /// <param name="pucseed">[in]种子长度,小于等于 51 </param>
+        /// <param name="pucNewSoPin">:[out]用于存放产生的超级用户密码的缓冲区指针,至少可容纳 16 字节。 </param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_GenSOPIN(IntPtr hHandle, int seedlen, byte[] pucseed, byte[] pucNewSoPin);
+
+
+        /// <summary>
+        /// 重新设置普通用户密码为 16 个‘F’,相当于解锁。命令执行成功后,当前安全状态变成超级用户状态。 
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄 </param>
+        /// <param name="pucSoPin">[in]超级用户密码,16 字节。</param>
+        /// <returns>如果验证超级PIN码错误,并且错误值在0xF0和ET_PIN_ERR_MAX (0xFF)之间,我们可以通过错误码&ET_PIN_ERR_MASK(0x0F)得到剩余重试次数。如果还回 0xF0 表示已经被锁死,如果还回 0xFF 表示验证出错,且 pin 永远不被锁死</returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_ResetPIN(IntPtr hHandle, byte[] pucSoPin);
+
+
+        /// <summary>
+        /// 更新参数指定的密钥,此密钥是用于计算 HMAC-MD5 的。其中 KEY的获得,是通过一个纯软件接口 HMAC_MD5(),参见相应说明。匿名状态不可用,且在普通用户状态时还需要检查设备配置。不改变安全状态。
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄 </param>
+        /// <param name="Keyid">[in]密钥指示,取值范围(1—8) </param>
+        /// <param name="pucKeyBuf">[in]KEY缓存区指针, KEY固定为 32 字节。 </param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_SetKey(IntPtr hHandle, int Keyid, byte[] pucKeyBuf);
+
+        /// <summary>
+        /// 标准 HMAC_MD5 的软件实现,参照 RFC2104 标准。
+        /// </summary>
+        /// <param name="pucText">[in]等处理的数据缓存区指针,大于 0 小于等于 51 个字节 </param>
+        /// <param name="ulText_Len">[in]数据长度,大于 0 小于等于 51 </param>
+        /// <param name="pucKey">[in]密钥,按标准 RFC2104,长度可以任意 </param>
+        /// <param name="ulKey_Len">[in]密钥长度 </param>
+        /// <param name="pucToenKey">[out]硬件计算需要的 KEY,固定 32 字节。 </param>
+        /// <param name="pucDigest">[out]计算结果,固定 16 字节。 </param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint MD5_HMAC(byte[] pucText, byte ulText_Len, byte[] pucKey, byte ulKey_Len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 32)]byte[] pucToenKey, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 16)]byte[] pucDigest);
+
+
+        /// <summary>
+        /// 利用硬件计算 HMAC-MD5  ,pid 为出厂时,还回错误。权限等同于 KEY的读权限。不改变安全状态。
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄 </param>
+        /// <param name="Keyid">[in]密钥指示,范围(1—8)</param>
+        /// <param name="textLen">[in]待计算的数据,大于 0 小于等于 51 个字节 </param>
+        /// <param name="pucText">[in]数据长度,大于 0 小于等于 51 </param>
+        /// <param name="digest">[out]散列结果的数据指针,固定长度 16 个字节。 </param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_HMAC_MD5(IntPtr hHandle, int Keyid, int textLen, byte[] pucText, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 16)]byte[] digest);
+
+        /// <summary>
+        /// 验证密码,以获得相应的安全状态,不受安全状态限制,验证成功以后,进入相应的安全状态。ET_VERIFY_USER_PIN = 验证的是普通用户PIN码,如果验证通过,则进入普通用户状态。
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄;</param>
+        /// <param name="Flags">[in]验证 PIN的类型,见下表; </param>
+        /// <param name="pucPIN">[in] PIN 码,固定长度 16 个字节。 </param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_Verify(IntPtr hHandle, int Flags, byte[] pucPIN);
+
+
+        /// <summary>
+        ///   修改普通用户密码,从 pucOldPIN,改为 pucNewPIN。普通用户密码长度固定为 16 字节。此命令可以在匿名状态下进行,命令执行成功后,进入普通用户状态。 
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄</param>
+        /// <param name="pucOldPIN">[in]原来的密码,长度固定为 16 字节 </param>
+        /// <param name="pucNewPIN">[in]新密码,长度固定为 16 字节 </param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_ChangeUserPIN(IntPtr hHandle, byte[] pucOldPIN, byte[] pucNewPIN);
+
+        /// <summary>
+        /// 重置安全状态,回到匿名用户状态。 
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄 </param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_ResetSecurityState(IntPtr hHandle);
+
+
+        /// <summary>
+        /// 获得硬件序列号。可以在匿名状态下进行。不改变安全状态。
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄 </param>
+        /// <param name="pucSN">[out]用于存放获得的序列号,长度固定为 8 字节 </param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_GetSN(IntPtr hHandle, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 32)]byte[] pucSN);
+
+
+        /// <summary>
+        /// 对硬件进行配置。必须在超级用户状态下进行。不改变安全状态。 
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄 </param>
+        /// <param name="bSoPINRetries">[in]超级 PIN 码的重试次数,范围 0—15,0 表示永远不被锁死;</param>
+        /// <param name="bUserPINRetries">:[in]用户 PIN 码的重试次数,范围 0—15,0 表示永远不被锁死; </param>
+        /// <param name="bUserReadOnly">[in]读写/只读标注,如下表; </param>
+        /// <param name="bBack">[in]保留字,必须为 0。</param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_SetupToken(IntPtr hHandle, byte bSoPINRetries, byte bUserPINRetries, byte bUserReadOnly, byte bBack);
+
+        /// <summary>
+        /// 打开 LED灯,使其变亮。匿名状态不可用,不改变安全状态。设备加电后,LED灯是常亮的
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄 </param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_TurnOnLED(IntPtr hHandle);
+
+        /// <summary>
+        /// 关闭 LED灯,使其变亮。匿名状态不可用,不改变安全状态。设备加电后,LED灯是常亮的
+        /// </summary>
+        /// <param name="hHandle">[in]设备句柄 </param>
+        /// <returns></returns>
+        [DllImport("FT_ET99_API.dll")]
+        public static extern uint et_TurnOffLED(IntPtr hHandle);
+
+
+
+
+        internal static void et_Write()
+        {
+            throw new Exception("The method or operation is not implemented.");
+        }
+    }
+}

+ 2 - 0
WpfTest1/WpTest.csproj

@@ -205,6 +205,8 @@
     <Compile Include="Exceptions\ExpressionCalculateExpression.cs" />
     <Compile Include="Exceptions\ExpressionFindFailedException.cs" />
     <Compile Include="Exceptions\ExpressionUnformattedException.cs" />
+    <Compile Include="Toolkits\DogOperator.cs" />
+    <Compile Include="Toolkits\ET99_API.cs" />
     <Compile Include="Toolkits\ReportGenerater.cs" />
     <Compile Include="SmallDialogs\AddDoctor.xaml.cs">
       <DependentUpon>AddDoctor.xaml</DependentUpon>