分类 CSharp 下的文章

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Helper
{
    public class CV300EHelper
    {

        #region 指纹特征提取函数接口
        /// <summary>
        /// 版本信息获取
        /// 函数原型:int __stdcall FP_GetVersion(unsigned char code[4])
        /// </summary>
        /// <param name="code">unsigned char code[4] 版本信息格式为XXYY,XX为开发者代码,YY为版本号。如“1201” 则code的填写方式为:,code[0]=‘1’ code[1]=,‘2’ code[3]=,‘0’ code[4]=,‘1’。输出参数。</param>
        /// <returns>调用成功,返回1;否则返回错误代码,错误代码值应符合B.4的要求。输出参数。</returns>
        [DllImport("ID_Fpr.dll", EntryPoint = "FP_GetVersion", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int FP_GetVersion(System.IntPtr code);
        /// <summary>
        /// 初始化操作
        /// 函数原型:int __stdcall FP_Begin() 
        /// </summary>
        /// <returns>调用成功返回 1。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合 B.4 的要求。</returns>
        [DllImport("ID_Fpr.dll", EntryPoint = "FP_Begin", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int FP_Begin();
        /// <summary>
        /// 指纹图像特征提取
        /// 函数原型:int __stdcall FP_FeatureExtract(unsigned char cScannerType,unsigned char cFingerCode,unsigned char * pFingerImgBuf,unsigned char * pFeatureData)
        /// </summary>
        /// <param name="cScannerType">unsigned char cScannerType 指纹采集器代码。输入参数。</param>
        /// <param name="cFingerCode">unsigned char cFingerCode 指位代码。输入参数。</param>
        /// <param name="pFingerImgBuf">unsigned char * pFingerImgBuf 指纹图像数据指针,指纹图像为RAW格式。输入参数。</param>
        /// <param name="pFeatureData">unsigned char * pFeatureData 指纹特征数据指针,存储生成的指纹特征数据,由调用者分配内存空间,输出参数。</param>
        /// <returns>调用成功,返回1;否则返回错误代码,错误代码值应符合B.4的要求</returns>
        [DllImport("ID_Fpr.dll", EntryPoint = "FP_FeatureExtract", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int FP_FeatureExtract(byte cScannerType, byte cFingerCode, System.IntPtr pFingerImgBuf, System.IntPtr pFeatureData);
        /// <summary>
        /// 指纹图像数据与指纹特征数据比对
        /// 函数原型:int __stdcall FP_FeatureMatch(unsigned char * pFeatureData1,unsigned char* pFeatureData2,float * pfSimilarity)
        /// 对两个指纹特征数据进行比对,得到相似度值
        /// </summary>
        /// <param name="pFeatureData1">unsigned char * pFeatureData1 指纹特征数据指针1。输入参数。</param>
        /// <param name="pFeatureData2">unsigned char * pFeatureData2 指纹特征数据指针2。输入参数。</param>
        /// <param name="pfSimilarity">float * pfSimilarity 相似度,取值范围为0.00 ~ 1.00,值0.00表示不匹配,值1.00 表示完全匹配。输出参数。</param>
        /// <returns>调用成功,返回1;否则返回错误代码,错误代码值应符合B.4的要求</returns>
        [DllImport("ID_Fpr.dll", EntryPoint = "FP_FeatureMatch", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int FP_FeatureMatch(System.IntPtr pFeatureData1, System.IntPtr pFeatureData2, ref float pfSimilarity);
        /// <summary>
        /// 指纹图像数据与指纹特征数据比对
        /// 函数原型:int __stdcall FP_ImageMatch(unsigned char * pFingerImgBuf,unsigned char *pFeatureData,float * pfSimilarity)。
        /// 对指纹图像数据与指纹特征数据进行比对,得到相似度值。
        /// </summary>
        /// <param name="pFingerImgBuf">unsigned char * pFingerImgBuf 指纹图像数据指针,指纹图像为RAW格式。输入参数。</param>
        /// <param name="pFeatureData">unsigned char * pFeatureData 指纹特征数据指针。输入参数。</param>
        /// <param name="pfSimilarity">float * pfSimilarity 相似度,取值范围为0.00 ~ 1.00,值0.00表示不匹配,值1.00 表示完全匹配。输出参数。</param>
        /// <returns>调用成功,返回1;否则返回错误代码,错误代码值应符合B.4的要求</returns>
        [DllImport("ID_Fpr.dll", EntryPoint = "FP_ImageMatch", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int FP_ImageMatch(System.IntPtr pFingerImgBuf, System.IntPtr pFeatureData, ref float pfSimilarity);
        /// <summary>
        /// 指纹图像数据压缩
        /// 函数原型:int __stdcall FP_Compress(unsigned char cScannerType, unsigned char cEnrolResult,unsigned char cFingerCode, unsigned char* pFingerImgBuf,int nCompressRatio, unsigned char* pCompressedImgBuf, unsigned char strBuf[256])。
        /// 对指纹图像数据进行压缩。
        /// </summary>
        /// <param name="cScannerType">unsigned char cScannerType 指纹采集器代码。输入参数。</param>
        /// <param name="cEnrolResult">unsigned char cEnrolResult 注册结果代码。输入参数。</param>
        /// <param name="cFingerCode">unsigned char cFingerCode 指位代码。输入参数。</param>
        /// <param name="pFingerImgBuf">unsigned char * pFingerImgBuf 指纹图像数据指针,指纹图像为RAW格式。输入参数。</param>
        /// <param name="nCompressRatio">int nCompressRatio 指纹图像数据压缩倍数。输入参数。</param>
        /// <param name="pCompressedImgBuf">unsigned char * pCompressedImgBuf 指纹压缩图像数据指针,调用者在调用此函数前,应当分配不小于20 480字节的内存,指纹压缩图像数据文件结构应符合附录A要求。输出参数。</param>
        /// <param name="strBuf">unsigned char strBuf[256] 错误信息,如果压缩图像发生错误,并且返回值为-9的情况下,strBuf填写错误信息。错误信息为以数值0结尾的字符串,采用GB 13000中规定的字符。输出参数。</param>
        /// <returns>调用成功,返回1;否则返回错误代码,错误代码值应符合B.4的要求。</returns>
        [DllImport("ID_Fpr.dll", EntryPoint = "FP_Compress", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int FP_Compress(byte cScannerType, byte cEnrolResult, byte cFingerCode, System.IntPtr pFingerImgBuf,
                                             int nCompressRatio, System.IntPtr pCompressedImgBuf, byte[] strBuf);
        /// <summary>
        /// 指纹图像数据复现
        /// 函数原型:int __stdcall FP_Decompress(unsigned char * pCompressedImgBuf,unsigned char* pFingerImgBuf,unsigned char strBuf[256])。
        /// 对指纹原始图像数据进行复现。
        /// </summary>
        /// <param name="pCompressedImgBuf">unsigned char * pCompressedImgBuf 指纹压缩图像数据指针,压缩图像数据长度不大 于20 480字节。输入参数。</param>
        /// <param name="pFingerImgBuf">unsigned char * pFingerImgBuf 指纹复现图像数据指针,指纹图像为RAW格式,调用者在调用此函数前,应当分配92 160字节的内存。输出参数。</param>
        /// <param name="strBuf">unsigned char strBuf[256] 错误信息,如果压缩图像发生错误,并且返回值为-9的情况下,strBuf填写错误信息。错误信息为以数值0结尾的字符串,采用GB 13000中规定的 字符。输出参数。</param>
        /// <returns>调用成功,返回1;否则返回错误代码,错误代码值应符合B.4的要求</returns>
        [DllImport("ID_Fpr.dll", EntryPoint = "FP_Decompress", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int FP_Decompress(System.IntPtr pCompressedImgBuf, System.IntPtr pFingerImgBuf, byte[] strBuf);
        /// <summary>
        /// 指纹图像质量值获取
        /// 函数原型:int __stdcall FP_GetQualityScore(unsigned char * pFingerImgBuf,unsigned char* pnScore)。
        /// 获取指纹图像的质量值
        /// </summary>
        /// <param name="pFingerImgBuf">unsigned char * pFingerImgBuf 指纹图像数据指针,指纹图像为RAW格式。输入参数。</param>
        /// <param name="pnScore">unsigned char * pnScore 指纹图像质量值指针,指纹图像质量值取值范围为00H ~ 64H,值01H表示最低质量,值64H表示最高质量,值00H表示未知。</param>
        /// <returns>调用成功,返回1;否则返回错误代码,错误代码值应符合B.4的要求。</returns>
        [DllImport("ID_Fpr.dll", EntryPoint = "FP_GetQualityScore", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int FP_GetQualityScore(System.IntPtr pFingerImgBuf, ref int pnScore);
        /// <summary>
        /// 生成“注册失败”指纹特征数据
        /// 函数原型:int __stdcall FP_GenFeatureFromEmpty1(unsigned char cScannerType,unsigned char cFingerCode,unsigned char * pFeatureData)
        /// 本函数针对“注册失败”手指的情况,生成“注册失败”指纹特征数据。其中,字段5设置为02H;字段9、字段10均设置为00H。
        /// </summary>
        /// <param name="cScannerType">unsigned char cScannerType 指纹采集器代码。输入参数。</param>
        /// <param name="cFingerCode">unsigned char cFingerCode 指位代码。输入参数。</param>
        /// <param name="pFeatureData">unsigned char * pFeatureData 指纹特征数据指针,存储生成的指纹特征数据,由调用者分配内存空间,输出参数。</param>
        /// <returns>调用成功,返回1;否则返回错误代码,错误代码值应符合B.4的要求</returns>
        [DllImport("ID_Fpr.dll", EntryPoint = "FP_GenFeatureFromEmpty1", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int FP_GenFeatureFromEmpty1(byte cScannerType, byte cFingerCode, System.IntPtr pFeatureData);
        /// <summary>
        /// 生成“未注册”指纹特征数据
        /// 函数原型:int __stdcall FP_GenFeatureFromEmpty2(unsigned char cFingerCode,unsigned   char * pFeatureData)
        /// 本函数针对“未注册”手指的情况,生成“未注册”指纹特征数据。其中,字段5设置为03H;字段6设置为61H、62H或63H;字段7、字段9、字段10均设置为00H。
        /// </summary>
        /// <param name="cFingerCode">unsigned char cFingerCode 指位代码。输入参数。</param>
        /// <param name="pFeatureData">unsigned char * pFeatureData 指纹特征数据指针,存储生成的指纹特征数据,由调用者分配内存空间,输出参数。</param>
        /// <returns>调用成功,返回1;否则返回错误代码,错误代码值应符合B.4的要求。</returns>
        [DllImport("ID_Fpr.dll", EntryPoint = "FP_GenFeatureFromEmpty2", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int FP_Decompress(byte cFingerCode, System.IntPtr pFeatureData);
        /// <summary>
        /// 结束操作
        /// 函数原型:int __stdcall FP_End()
        /// </summary>
        /// <returns>调用成功,返回1;否则返回错误代码,错误代码值应符合B.4的要求。</returns>
        [DllImport("ID_Fpr.dll", EntryPoint = "FP_End", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int FP_End();

        #endregion

        #region 指纹仪函数接口

        /// <summary>
        /// 初始化采集器
        /// 函数原型:int _stdcall LIVESCAN_Init()。
        /// 初始化采集器,分配相应的资源。
        /// 在所有接口函数中,通常首先调用此函数。只需要调用一次,允许重复调用,其结果与一次调用相同。
        /// </summary>
        /// <returns>调用成功返回1。否则返回错误代码,调用LIVESCAN_GetErrInfo函数获取错误信息。错误代码值符合A.4的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_Init", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_Init();

        /// <summary>
        /// 释放采集器
        /// 函数原型:int _stdcall LIVESCAN_Close()。
        /// 关闭指纹采集器,释放分配的资源。
        /// 调用此函数后,在没有调用 LIVESCAN_Init 函数之前,仅可调用 LIVESCAN_GetVersion、LIVESCAN_GetDesc 和 LIVESCAN_GetErrorInfo 函数。
        /// 调用此函数后,应重新调用 LIVESCAN_Init 来初始化采集器。
        /// </summary>
        /// <returns>调用成功返回 1。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合 A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_Close", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_Close();

        /// <summary>
        /// 获得采集器通道数量
        /// 函数原型:int _stdcall LIVESCAN_GetChannelCount()。
        /// 获得采集器可以使用的通道数量及通道号。
        /// </summary>
        /// <returns>调用成功返回通道数量(>0)。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合 A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_GetChannelCount", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_GetChannelCount();

        /// <summary>
        /// 获得采集器采集图像的宽度、高度的最大值
        /// 函数原型:int _stdcall LIVESCAN_GetMaxImageSize(int nChannel,int * pnWidth, int * pnHeight)。
        /// 获得采集器可采集图像的宽度、高度的最大值。
        /// </summary>
        /// <param name="nChannel">int nChannel 通道号。输入参数。</param>
        /// <param name="pnWidth">int * pnWidth 存放图像宽度的整形指针。输出参数。</param>
        /// <param name="pnHeight">int * pnHeight 存放图像高度的整形指针。输出参数。</param>
        /// <returns>调用成功返回 1。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合 A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_GetMaxImageSize", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_GetMaxImageSize(int nChannel, ref int pnWidth, ref int pnHeight);

        /// <summary>
        /// 获得采集器当前的亮度
        /// 函数原型:int _stdcall LIVESCAN_GetBright(int nChannel,int * pnBright)。
        /// 获得采集器当前亮度。
        /// </summary>
        /// <param name="nChannel">int nChannel 通道号。输入参数。</param>
        /// <param name="pnBright">int * pnBright 存放当前亮度的整形指针。输出参数。</param>
        /// <returns>调用成功返回 1。否则返回错误代码 ,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合 A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_GetBright", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_GetBright(int nChannel, ref int pnBright);

        /// <summary>
        /// 设置采集器当前的亮度
        /// 函数原型:int _stdcall LIVESCAN_SetBright(int nChannel, int nBright)。
        /// 设置采集器当前亮度
        /// </summary>
        /// <param name="nChannel">int nChannel 通道号。输入参数。</param>
        /// <param name="nBright">int nBright 亮度,范围为 0~255,输入参数。</param>
        /// <returns>调用成功返回 1。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合 A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_SetBright", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_SetBright(int nChannel, int nBright);

        /// <summary>
        /// 获得采集器当前对比度
        /// 函数原型:int _stdcall LIVESCAN_GetContrast(int nChannel,int * pnContrast)。
        /// 获得采集器当前对比度。
        /// </summary>
        /// <param name="nChannel">int nChannel 通道号。输入参数。</param>
        /// <param name="pnContrast">int * pnContrast 存放当前对比度的整型指针。输出参数。</param>
        /// <returns>调用成功返回 1。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合 A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_GetContrast", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_GetContrast(int nChannel, ref int pnContrast);

        /// <summary>
        /// 设置采集器当前对比度
        /// 函数原型:int _stdcall LIVESCAN_SetContrast(int nChannel,int Contrast)。
        /// 设置采集器当前对比度。
        /// </summary>
        /// <param name="nChannel">int nChannel    通道号。输入参数。</param>
        /// <param name="nContrast">int nContrast 对比度, 范围0~255。输入参数。</param>
        /// <returns>调用成功返回1。否则返回错误代码,调用LIVESCAN_GetErrInfo函数获取错误信息。错误代码值符合A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_SetContrast", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_SetContrast(int nChannel, int nContrast);

        /// <summary>
        /// 获得当前图像的采集位置、宽度和高度
        /// 函数原型:int _stdcall LIVESCAN_GetCaptWindow(int nChannel,int * pnOriginX, int * pnOriginY,int * pnWidth, int * pnHeight)。
        /// 获得采集器当前图像的采集位置、宽度和高度。当前图像宽度初始值为 256,高度初始值为360。
        /// </summary>
        /// <param name="nChannel">int nChannel 通道号。输入参数。</param>
        /// <param name="pnOriginX">int *pnOriginX 存放图像采集窗口的采集原点坐标X值的整型指针。输出参数。</param>
        /// <param name="pnOriginY">int *pnOriginY 存放图像采集窗口的采集原点坐标Y值的整型指针。输出参数。</param>
        /// <param name="pnWidth">int *pnWidth 存放采集图像宽度的整形指针。输出参数。</param>
        /// <param name="pnHeight">int *pnHeight 存放采集图像高度的整形指针。输出参数。</param>
        /// <returns>调用成功返回 1。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合 A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_GetCaptWindow", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_GetCaptWindow(int nChannel, ref int pnOriginX, ref int pnOriginY, ref int pnWidth, ref int pnHeight);

        /// <summary>
        /// 设置当前图像的采集位置、宽度和高度
        /// 函数原型:int _stdcall LIVESCAN_SetCaptWindow(int nChannel,int nOriginX, int  nOriginY,int nWidth,int nHeight)。
        /// 设置采集器当前图像的采集位置、宽度和高度。
        /// </summary>
        /// <param name="nChannel">int nChannel 通道号。输入参数。</param>
        /// <param name="nOriginX">int nOriginX 图像采集窗口的采集原点坐标 X 值。输入参数。</param>
        /// <param name="nOriginY">int nOriginY 图像采集窗口的采集原点坐标 Y 值。输入参数。</param>
        /// <param name="nWidth">int nWidth 采集图像的宽度。对于居民身份证用单指指纹采集,应大于等于 256。否则应返回参数错误代码。输入参数。</param>
        /// <param name="nHeight">int nHeight 采集图像的高度。对于居民身份证用单指指纹采集,应大于等于 360。否则应返回参数错误代码。输入参数。</param>
        /// <returns>调用成功返回 1。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合 A.4的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_SetCaptWindow", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_SetCaptWindow(int nChannel, int nOriginX, int nOriginY, int nWidth, int nHeight);

        /// <summary>
        /// 准备采集一帧图像
        /// 函数原型:int _stdcall LIVESCAN_BeginCapture(int nChannel)。
        /// 采集图像的一个前缀函数,使得采集器有机会进行另外一个采集之前的初始化工作。
        /// </summary>
        /// <param name="nChannel">int nChannel    通道号。输入参数。</param>
        /// <returns>调用成功返回 1。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合 A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_BeginCapture", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_BeginCapture(int nChannel);

        /// <summary>
        /// 结束采集一帧图像
        /// 函数原型:int _stdcall LIVESCAN_EndCapture(int nChannel)。
        /// 结束采集一帧图像或预览图像。
        /// </summary>
        /// <param name="nChannel">int nChannel 通道号。输入参数。</param>
        /// <returns>调用成功返回1。否则返回错误代码,调用LIVESCAN_GetErrInfo函数获取错误信息。错误代码值符合A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_EndCapture", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_EndCapture(int nChannel);

        /// <summary>
        /// 采集一帧图像
        /// 函数原型:int _stdcall LIVESCAN_GetFPRawData(int nChannel,unsigned char *pRawData)。
        /// </summary>
        /// <param name="nChannel">int nChannel通道号。输入参数。</param>
        /// <param name="pRawData">unsigned char* pRawData指向存放采集数据的内存块,调用者分配。 返回图像数据,大小应为:当前图像采集宽度×当前图像采集高度。输出参数。</param>
        /// <returns>调用成功返回1。否则返回错误代码,调用LIVESCAN_GetErrInfo函数获取错误信息。错误代码值符合 A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_GetFPRawData", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_GetFPRawData(int nChannel, System.IntPtr pRawData);

        /// <summary>
        /// 采集一帧BMP格式图像数据
        /// 函数原型:int _stdcall LIVESCAN_GetFPBmpData(int nChannel, unsigned char * pBmpData)。
        /// 采集一帧8位灰度 BMP 格式图像。
        /// </summary>
        /// <param name="nChannel">int nChannel通道号。输入参数。</param>
        /// <param name="pBmpData">unsigned char*  pBmpData  指向存放8位灰度BMP格式采集数据的内存块,调用者分配。返回8位灰度BMP格式图像数据。大小应为:当前图像采集宽度×当前图像采集高度+1078。输出参数。</param>
        /// <returns>调用成功,返回 1。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合 A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_GetFPBmpData", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_GetFPBmpData(int nChannel, System.IntPtr pBmpData);

        /// <summary>
        /// 调用采集器的属性设置对话框
        /// 函数原型:int _stdcall LIVESCAN_Setup()。
        /// 此函数弹出一个模式对话框,用户可以设置除去对比度、亮度、采集窗口参数外的其它参数,如GAMMA值等,使得设置适合采集器本身的特点。
        /// </summary>
        /// <returns>调用成功返回 1。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合 A.4 的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_Setup", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_Setup();

        /// <summary>
        /// 采集器是否支持设置对话框
        /// 函数原型:int _stdcall LIVESCAN_IsSupportSetup()。
        /// 此函数用来确认是否支持设置对话框。
        /// </summary>
        /// <returns>若采集接口支持LIVESCAN_setup,则返回1,否则返回0。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合A.4的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_IsSupportSetup", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_IsSupportSetup();

        /// <summary>
        /// 取得接口规范的版本
        /// 函数原型:int ¬_stdcall LIVESCAN_GetVersion()。
        /// 获得接口版本号。
        /// </summary>
        /// <returns>获得接口规范的版本。当前版本为1.00,返回值为100。若以后扩展接口,则需要修改此版本号。否则返回错误代码,调用LIVESCAN_GetErrorInfo函数获取错误信息。错误代码值应符合 A.4的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_GetVersion", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_GetVersion();

        /// <summary>
        /// 获得接口规范的说明
        /// 函数原型:int _stdcall LIVESCAN_GetDesc(char pszDesc[1024])。
        /// 获得接口说明,不需要初始化就可以调用。pszDesc以数值0结尾的字符串,采用GB13000 中规定的字符。
        /// </summary>
        /// <param name="pszDesc">char pszDesc[1024]存放接口说明,其中pszDesc[0]用于存储采集器代码,缺省为FFH。 输出参数。</param>
        /// <returns>调用成功返回1。否则返回错误代码,调用LIVESCAN_GetErrorInfo函数获取错误信息。错误代码值应符合 A.4的要求</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_GetDesc", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_GetDesc(System.IntPtr pszDesc);

        /// <summary>
        /// 设置存放采集数据的内存块为空
        /// 函数原型:int _stdcall LIVESCAN_SetBufferEmpty(unsigned char * pImageData, long imageLength)。
        /// 将存放采集数据的内存块中的每一个字节的值置为0x00。
        /// </summary>
        /// <param name="pImageData">unsigned char * pImageData 指向存放采集数据的内存块。输入参数。</param>
        /// <param name="imageLength">long imageLength 存放采集数据的内存块长度。输入参数。</param>
        /// <returns>调用成功返回1。否则返回错误代码,调用 LIVESCAN_GetErrInfo 函数获取错误信息。错误代码值符合A.4的要求。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_SetBufferEmpty", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_SetBufferEmpty(System.IntPtr pImageData, long imageLength);

        /// <summary>
        /// 获得采集接口错误信息
        /// 函数原型:int _stdcall LIVESCAN_GetErrorInfo(int nErrorNo,char pszErrorInfo[256])。
        /// pszErrorInfo 采用GB13000中规定的字符。
        /// </summary>
        /// <param name="nErrorNo">char pszErrorInfo[256]用来存放错误信息的内存块,错误信息的长度不能超过 256 个字节。输出参数。</param>
        /// <param name="pszErrorInfo">int nErrorNo 错误代码(<0)。输入参数。</param>
        /// <returns>若为合法的错误代码返回 1,pszErrorInfo中为错误信息。若 nErrorNo 为非法的错误代码,则返回-6,同时设置 pszErrorInfo为“非法错误号”错误。</returns>
        [DllImport("ID_FprCap.dll", EntryPoint = "LIVESCAN_GetErrorInfo", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int LIVESCAN_GetErrorInfo(int nErrorNo, System.IntPtr pszErrorInfo);

        [DllImport("Kernel32.dll")]
        static extern bool QueryPerformanceCounter(ref long count);
        [DllImport("Kernel32.dll")]
        static extern bool QueryPerformanceFrequency(ref long count);


        #endregion

        #region 二代证接口

        /// <summary>
        /// 初始化连接
        /// 原    型:int CVR_InitComm (int Port)
        /// 本函数用于PC与华视电子第二代居民身份证阅读器的连接。
        /// </summary>
        /// <param name="Port">连接串口(COM1~COM16)或USB口(1001~1016)[1,串口1],[2,串口2],[3,串口3],[4,串口4],[1001,USB口1],[1002,USB口2],[1003,USB口3],[1004,USB口4]</param>
        /// <returns>[1,正确],[2,端口打开失败],[0,动态库加载失败]</returns>
        [DllImport("termb.dll", EntryPoint = "CVR_InitComm", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int CVR_InitComm(int Port);//声明外部的标准动态库, 跟Win32API是一样的

        /// <summary>
        /// 卡认证
        /// 原    型:int CVR_Authenticate (void)
        /// 本函数用于读卡器和卡片之间的合法身份确认。卡认证循环间隔大于300ms。
        /// </summary>
        /// <returns>[值,意义,说明][1,正确,卡片认证成功],[2,错误,寻卡失败],[3,错误,选卡失败],[0,错误,初始化失败]</returns>
        [DllImport("termb.dll", EntryPoint = "CVR_Authenticate", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int CVR_Authenticate();

        /// <summary>
        /// 读卡操作
        /// 原    型:int CVR_Read_Content(int active)
        /// 本函数用于通过阅读器从第二代居民身份证中读取相应信息。卡认证成功以后才可做读卡操作,读卡完毕若继续读卡应移走二代证卡片重新放置做卡认证。
        /// 读卡成功后在termb.dll文件所在路径下生成wz.txt(文字信息)和zp.bmp(照片信息)
        /// wz.txt内容示例如下:
        /// 张红叶
        /// 女
        /// 汉
        /// 1988-11-18
        /// 河北省邯郸市临漳县称勾镇称勾东村复兴路25号
        /// 130423198811184328
        /// 临漳县公安局
        /// 2011.03.30-2021.03.30
        /// </summary>
        /// <param name="Active">active:兼容以前版本,无实际意义</param>
        /// <returns>[1,正确],[2,错误],[99,异常]</returns>
        [DllImport("termb.dll", EntryPoint = "CVR_Read_Content", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int CVR_Read_Content(int Active);

        /// <summary>
        /// 读取文字,照片,指纹,操
        /// 原    型:int   CVR_Read_FPContent ()
        /// 本函数用于通过阅读器从第二代居民身份证中读取相应信息。卡认证成功以后才可做读卡操作,读卡完毕若继续读卡应移走二代证卡片重新放置做卡认证。
        /// 读卡成功后在termb.dll文件所在路径下生成wz.txt(文字信息)和zp.bmp(照片信息)
        /// wz.txt内容示例如下:
        /// 张红叶
        /// 女
        /// 汉
        /// 1988-11-18
        /// 河北省邯郸市临漳县称勾镇称勾东村复兴路25号
        /// 130423198811184328
        /// 临漳县公安局
        /// 2011.03.30-2021.03.30
        /// </summary>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "CVR_Read_FPContent", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int CVR_Read_FPContent();

        /// <summary>
        /// 关闭连接
        /// 原    型:int CVR_CloseComm(void)
        /// </summary>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "CVR_CloseComm", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int CVR_CloseComm();

        /// <summary>
        /// 得到姓名信息
        /// 原  型:int  GetPeopleName(char *strTmp, int *strLen)
        /// </summary>
        /// <param name="strTmp">*strTmp   返回的信息缓存指针。</param>
        /// <param name="strLen">*strLen    返回的信息长度指针。</param>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "GetPeopleName", CharSet = CharSet.Ansi, SetLastError = false)]
        public static extern int GetPeopleName(ref byte strTmp, ref int strLen);

        /// <summary>
        /// 得到民族信息    
        /// </summary>
        /// <param name="strTmp">*strTmp   返回的信息缓存指针。</param>
        /// <param name="strLen">*strLen    返回的信息长度指针。</param>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "GetPeopleNation", CharSet = CharSet.Ansi, SetLastError = false)]
        public static extern int GetPeopleNation(ref byte strTmp, ref int strLen);

        /// <summary>
        /// 得到出生日期
        /// </summary>
        /// <param name="strTmp">*strTmp   返回的信息缓存指针。</param>
        /// <param name="strLen">*strLen    返回的信息长度指针。</param>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "GetPeopleBirthday", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
        public static extern int GetPeopleBirthday(ref byte strTmp, ref int strLen);

        /// <summary>
        /// 得到地址信息
        /// </summary>
        /// <param name="strTmp">*strTmp   返回的信息缓存指针。</param>
        /// <param name="strLen">*strLen    返回的信息长度指针。</param>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "GetPeopleAddress", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
        public static extern int GetPeopleAddress(ref byte strTmp, ref int strLen);

        /// <summary>
        /// 得到身份证号信息
        /// </summary>
        /// <param name="strTmp">*strTmp   返回的信息缓存指针。</param>
        /// <param name="strLen">*strLen    返回的信息长度指针。</param>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "GetPeopleIDCode", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
        public static extern int GetPeopleIDCode(ref byte strTmp, ref int strLen);

        /// <summary>
        /// 得到发证机关信息
        /// </summary>
        /// <param name="strTmp">*strTmp   返回的信息缓存指针。</param>
        /// <param name="strLen">*strLen    返回的信息长度指针。</param>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "GetDepartment", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
        public static extern int GetDepartment(ref byte strTmp, ref int strLen);

        /// <summary>
        /// 得到有效开始日期
        /// </summary>
        /// <param name="strTmp">*strTmp   返回的信息缓存指针。</param>
        /// <param name="strLen">*strLen    返回的信息长度指针。</param>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "GetStartDate", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
        public static extern int GetStartDate(ref byte strTmp, ref int strLen);

        /// <summary>
        /// 得到有效截止日期
        /// </summary>
        /// <param name="strTmp">*strTmp   返回的信息缓存指针。</param>
        /// <param name="strLen">*strLen    返回的信息长度指针。</param>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "GetEndDate", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
        public static extern int GetEndDate(ref byte strTmp, ref int strLen);
        /// <summary>
        /// 得到性别信息
        /// </summary>
        /// <param name="strTmp">*strTmp   返回的信息缓存指针。</param>
        /// <param name="strLen">*strLen    返回的信息长度指针。</param>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "GetPeopleSex", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
        public static extern int GetPeopleSex(ref byte strTmp, ref int strLen);
        /// <summary>
        /// 读取指纹信息
        /// 函数原型:int GetFPDate(unsigned char* pucFPMsgValue,int* nlen)
        /// 本函数用于通过阅读器从第二代居民身份证中读取指纹信息。CVR_Read_FPContent()调用成功以后才可以调用该函数
        /// 以下是指纹信息的相关说明,供调用者参考:
        /// 第一枚指纹信息:
        /// pucFPMsgValue[0] 字段文件头类型,记录字符“C”(43H)
        /// pucFPMsgValue[1] 指纹算法版本号
        /// pucFPMsgValue[2] 指纹采集器代码
        /// pucFPMsgValue[3] 指纹算法开发者代码
        /// pucFPMsgValue[4] 注册结果代码,01H 表示“注册成功”,02H 表示“注册失败”,03H 表示“未注册”,09H 表示“未知”
        /// pucFPMsgValue[5] 指位代码  具体见指位说明
        /// pucFPMsgValue[6]    指纹质量值,以00H~64H来表示,值01H表示最低质量,值64H表示最高质量,值00H表示“未知”
        /// 第二枚指纹信息:
        /// pucFPMsgValue[512] 字段文件头类型,记录字符“C”(43H)
        /// pucFPMsgValue[513] 指纹算法版本号
        /// pucFPMsgValue[514] 指纹采集器代码
        /// pucFPMsgValue[515] 指纹算法开发者代码
        /// pucFPMsgValue[516] 注册结果代码,01H 表示“注册成功”,02H 表示“注册失败”,03H 表示“未注册”,09H 表示“未知”
        /// pucFPMsgValue[517] 指位代码  具体见指位说明
        /// pucFPMsgValue[518]    指纹质量值,以00H~64H来表示,值01H表示最低质量,值64H表示最高质量,值00H表示“未知”
        /// 指位码说明:[pucFPMsgValue[5or517],指位]
        /// [0BH,右手拇指],[0CH,右手食指],[0DH,右手中指],[0EH,右手环指],[0FH,右手小指]
        /// [10H,左手拇指],[11H,左手食指],[12H,左手中指],[13H,左手环指],[14H,左手小指]
        /// [61H,右手不确定指位],[62H,左手不确定指位],[63H,其他不确定指位]
        /// </summary>
        /// <param name="strTmp">pucFPMsgValue 存放指纹信息的内存缓冲,大小由调用者分配1024字节大小。</param>
        /// <param name="strLen">nlen   指纹数据的大小,传出参数,0 表示没有指纹信息,大于0表示 存在指纹信息。一个指纹信息转占512字节大小,身份证中一般存储两个指纹信息。</param>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "GetFPDate", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
        public static extern int GetFPDate(ref byte strTmp, ref int strLen);

        /// <summary>
        /// 得到安全模块号
        /// </summary>
        /// <param name="strTmp">*strTmp   返回的信息缓存指针。</param>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "CVR_GetSAMID", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
        public static extern int CVR_GetSAMID(ref byte strTmp);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="strTmp">*strTmp   返回的信息缓存指针。</param>
        /// <returns>[1,正确],[0,错误]</returns>
        [DllImport("termb.dll", EntryPoint = "GetManuID", CharSet = CharSet.Ansi, SetLastError = false, CallingConvention = CallingConvention.StdCall)]
        public static extern int GetManuID(ref byte strTmp);

        #endregion

        #region 语音提示接口
        /// <summary>
        /// 原    型:int  SendReport (int nIndex)
        /// 本函数用于PC与华视电子第二代居民身份证阅读器的连接。
        /// 参数:nIndex
        /// [1,请将您的身份证放在读卡区域内],[2,读卡成功],[3,读卡失败请重新放卡]
        /// [4,请采集右手拇指指纹],[5,请采集右手无名指指纹],[6,请采集右手中指指纹],[7,请采集右手食指指纹],[8,请采集右手小指指纹]
        /// [9,请采集左手拇指指纹],[10,请采集左手食指指纹],[11,请采集左手中指指纹],[12,请采集左手无名指指纹],[13,请采集左手小指指纹]
        /// [14,指纹采集成功],[15,指纹对比成功],[16,请面对摄像头],[17,照片采集成功]
        /// </summary>
        /// <param name="nIndex">。输入参数</param>
        /// <returns>[1,正确],[0,失败]</returns>
        [DllImport("HIDSENREPORT.dll", EntryPoint = "SendReport", CharSet = CharSet.Auto, SetLastError = false)]
        public static extern int CVR_SendReport(int nIndex);
        #endregion

        #region 整合类

        /// <summary>
        /// 指纹仪初始化,不初始化算法
        /// </summary>
        /// <returns>[1,初始化成功],[-1,初始化失败]</returns>
        public static int HelperZhiWenChuShiHua()
        {
            int ret = LIVESCAN_Init();
            if (ret == 1)
            {
                ret = LIVESCAN_BeginCapture(0);
                if (ret == 1)
                {
                    return 1;
                }
                else
                    return -1;
            }
            else
                return -1;
        }
        /// <summary>
        /// 指纹仪初始化,初始化算法
        /// </summary>
        /// <returns>[1,初始化成功],[-1,初始化失败]</returns>
        public static int HelperZhiWenChuShiHuaAll()
        {
            int ret = HelperZhiWenChuShiHua();
            if (ret == 1)
            {
                ret = FP_Begin();
                if (ret == 1)
                    return 1;
                else
                    return -1;
            }
            else
                return -1;
        }
        /// <summary>
        /// 初始化读卡器
        /// </summary>
        /// <returns>[1,初始化成功],[-1,初始化失败]</returns>
        public static int HelperIDCardChuShiHua()
        {
            int iPort, iRetUSB = 0, iRetCOM = 0;
            for (iPort = 1001; iPort <= 1004; iPort++)
            {
                iRetUSB = CVR_InitComm(iPort);
                if (iRetUSB == 1)
                {
                    break;
                }
            }
            if (iRetUSB != 1)
            {
                for (iPort = 1; iPort <= 4; iPort++)
                {
                    iRetCOM = CVR_InitComm(iPort);
                    if (iRetCOM == 1)
                    {
                        break;
                    }
                }
            }
            if ((iRetCOM == 1) || (iRetUSB == 1))
            {
                return 1;

            }
            else
            {
                return -1;
            }
        }
        /// <summary>
        /// 读取身份证
        /// </summary>
        /// <returns></returns>
        public static PeopleBean HelperGetPeopleBean()
        {
            int authenticate = CVR_Authenticate();
            if (authenticate == 1)
            {
                int readContent = CVR_Read_FPContent();
                if (readContent == 1)
                {
                    PeopleBean people = new PeopleBean();

                    HelperSendReport(EnumSendReport.读卡成功);

                    byte[] name = new byte[30];
                    int length = 30;
                    GetPeopleName(ref name[0], ref length);
                    people.name = Encoding.GetEncoding("GB2312").GetString(name).Replace("\0", "").Trim();

                    byte[] number = new byte[36];
                    length = 36;
                    GetPeopleIDCode(ref number[0], ref length);
                    people.number = Encoding.GetEncoding("GB2312").GetString(number).Replace("\0", "").Trim();

                    byte[] nation = new byte[4];
                    length = 4;
                    GetPeopleNation(ref nation[0], ref length);
                    people.nation = Encoding.GetEncoding("GB2312").GetString(nation).Replace("\0", "").Trim();

                    byte[] validtermOfStart = new byte[30];
                    length = 16;
                    GetStartDate(ref validtermOfStart[0], ref length);
                    people.validtermOfStart = Encoding.GetEncoding("GB2312").GetString(validtermOfStart).Replace("\0", "").Trim();

                    byte[] birthday = new byte[30];
                    length = 16;
                    GetPeopleBirthday(ref birthday[0], ref length);
                    people.birthday = Encoding.GetEncoding("GB2312").GetString(birthday).Replace("\0", "").Trim();

                    byte[] address = new byte[70];
                    length = 70;
                    GetPeopleAddress(ref address[0], ref length);
                    people.address = Encoding.GetEncoding("GB2312").GetString(address).Replace("\0", "").Trim();

                    byte[] validtermOfEnd = new byte[30];
                    length = 16;
                    GetEndDate(ref validtermOfEnd[0], ref length);
                    people.validtermOfEnd = Encoding.GetEncoding("GB2312").GetString(validtermOfEnd).Replace("\0", "").Trim();

                    byte[] signdate = new byte[30];
                    length = 30;
                    GetDepartment(ref signdate[0], ref length);
                    people.signdate = Encoding.GetEncoding("GB2312").GetString(signdate).Replace("\0", "").Trim();

                    byte[] sex = new byte[30];
                    length = 3;
                    GetPeopleSex(ref sex[0], ref length);
                    people.sex = Encoding.GetEncoding("GB2312").GetString(sex).Replace("\0", "").Trim();

                    byte[] samid = new byte[32];
                    CVR_GetSAMID(ref samid[0]);
                    people.samid = Encoding.GetEncoding("GB2312").GetString(samid).Replace("\0", "").Trim();

                    byte[] ICFeatureData = new byte[1024];
                    GetFPDate(ref ICFeatureData[0], ref length);

                    people.listFeatureDataBean = new List<ICFeatureDataBean>();
                    ICFeatureDataBean f1 = new ICFeatureDataBean();
                    Array.Copy(ICFeatureData, 0, f1.buffer, 0, 512);
                    f1.fileHeadType = ICFeatureData[0];
                    f1.version = ICFeatureData[1];
                    f1.collectorCode = ICFeatureData[2];
                    f1.developerCode = ICFeatureData[3];
                    f1.registrationResultCode = (EnumRegistrationResult)ICFeatureData[4];
                    f1.fingerPositionCode = (EnumFingerPosition)ICFeatureData[5];
                    f1.quality = ICFeatureData[6];
                    people.listFeatureDataBean.Add(f1);
                    ICFeatureDataBean f2 = new ICFeatureDataBean();
                    Array.Copy(ICFeatureData, 512, f2.buffer, 0, 512);
                    f2.fileHeadType = ICFeatureData[512];
                    f2.version = ICFeatureData[513];
                    f2.developerCode = ICFeatureData[514];
                    f2.collectorCode = ICFeatureData[515];
                    f2.registrationResultCode = (EnumRegistrationResult)ICFeatureData[516];
                    f2.fingerPositionCode = (EnumFingerPosition)ICFeatureData[517];
                    f2.quality = ICFeatureData[518];
                    people.listFeatureDataBean.Add(f2);

                    FileStream file = new FileStream(System.Windows.Forms.Application.StartupPath + "\\zp.bmp", FileMode.Open);
                    Image img = Image.FromStream(file);
                    file.Close();
                    people.photo = img;

                    return people;
                }
                else
                    return null;
            }
            else
                return null;
        }
        /// <summary>
        /// 获取指纹
        /// </summary>
        /// <returns></returns>
        public static byte[] HelperGetFPRawData()
        {
            System.IntPtr pRawData = Marshal.AllocHGlobal(92160);
            byte[] RawData = new byte[92160];
            int ret = LIVESCAN_GetFPRawData(0, pRawData);
            if (ret == 1)
            {
                Marshal.Copy(pRawData, RawData, 0, 92160);
                Marshal.FreeHGlobal(pRawData);
                return RawData;
            }
            else
                return null;

        }
        /// <summary>
        /// 获取指纹特征
        /// </summary>
        /// <param name="cFingerCode"></param>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public static ICFeatureDataBean HelperGetFPFeatureExtract(EnumFingerPosition cFingerCode,byte[] buffer)
        {
            System.IntPtr pFingerImgBuf1 = Marshal.AllocHGlobal(buffer.Length);
            Marshal.Copy(buffer, 0, pFingerImgBuf1, buffer.Length);
            System.IntPtr pFingerFeatureBuf1 = Marshal.AllocHGlobal(512);
            int ret = FP_FeatureExtract(0, (byte)cFingerCode, pFingerImgBuf1, pFingerFeatureBuf1);
            if (ret == 1)
            {
                byte[] FeatureData = new byte[512];
                Marshal.Copy(pFingerFeatureBuf1, FeatureData, 0, 512);
                Marshal.FreeHGlobal(pFingerImgBuf1);
                Marshal.FreeHGlobal(pFingerFeatureBuf1);

                ICFeatureDataBean f1 = new ICFeatureDataBean();
                f1.buffer = FeatureData;
                f1.fileHeadType = f1.buffer[0];
                f1.version = f1.buffer[1];
                f1.collectorCode = f1.buffer[2];
                f1.developerCode = f1.buffer[3];
                f1.registrationResultCode = (EnumRegistrationResult)f1.buffer[4];
                f1.fingerPositionCode = (EnumFingerPosition)f1.buffer[5];
                f1.quality = f1.buffer[6];


                return f1;
            }
            else
            {
                Marshal.FreeHGlobal(pFingerImgBuf1);
                Marshal.FreeHGlobal(pFingerFeatureBuf1);
                return null;
            }
        }
        /// <summary>
        /// 获取指纹图像
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public static Bitmap HelperGetFPBitmap(byte[] buffer)
        {
            Bitmap bm = new Bitmap(256, 360, PixelFormat.Format8bppIndexed);
            Rectangle dimension = new Rectangle(0, 0, bm.Width, bm.Height);
            BitmapData picData = bm.LockBits(dimension, ImageLockMode.ReadWrite, bm.PixelFormat);
            IntPtr pixelStartAddress = picData.Scan0;
            System.Runtime.InteropServices.Marshal.Copy(buffer, 0, pixelStartAddress, buffer.Length);
            bm.UnlockBits(picData);
            ColorPalette tempPalette;
            using (Bitmap tempBmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
            {
                tempPalette = tempBmp.Palette;
            }
            for (int i = 0; i < 256; i++)
            {
                tempPalette.Entries[i] = Color.FromArgb(i, i, i);
            }
            bm.Palette = tempPalette;
            return bm;
        }
        /// <summary>
        /// 获取指纹质量
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public static int HelperGetFPQuality(byte[] buffer)
        {
            System.IntPtr pFingerImgBuf = Marshal.AllocHGlobal(92160);
            Marshal.Copy(buffer, 0, pFingerImgBuf, buffer.Length);
            int sb = 0;
            int ret = FP_GetQualityScore(pFingerImgBuf, ref sb);
            if (ret == 1)
                return sb;
            else
                return 0;
        }
        /// <summary>
        /// 指纹特征对比
        /// </summary>
        /// <param name="buffer1"></param>
        /// <param name="buffer2"></param>
        /// <returns></returns>
        public static float HelperGetFeatureMatch(byte[] buffer1,byte[] buffer2)
        {
            System.IntPtr pFingerFeatureBuf1 = Marshal.AllocHGlobal(buffer1.Length);
            Marshal.Copy(buffer1, 0, pFingerFeatureBuf1, buffer1.Length);

            System.IntPtr pFingerFeatureBuf2 = Marshal.AllocHGlobal(buffer2.Length);
            Marshal.Copy(buffer2, 0, pFingerFeatureBuf2, buffer2.Length);

            float f = 0;
            int ret = FP_FeatureMatch(pFingerFeatureBuf1, pFingerFeatureBuf2, ref f);

            Marshal.FreeHGlobal(pFingerFeatureBuf1);
            Marshal.FreeHGlobal(pFingerFeatureBuf2);

            return f;
        }
        /// <summary>
        /// 关闭
        /// </summary>
        public static void Close()
        {

           int  ret = LIVESCAN_EndCapture(0);
            ret = FP_End();
        }
        /// <summary>
        /// 发出声音
        /// </summary>
        /// <param name="sendReport"></param>
        public static void HelperSendReport(EnumSendReport sendReport)
        {
            CVR_SendReport((int)sendReport);
        }
        public static void HelperSendReport(EnumFingerPosition figerPostion)
        {
            switch (figerPostion)
            {
                case EnumFingerPosition.右手中指:
                    HelperSendReport(EnumSendReport.请采集右手中指指纹);
                    break;
                case EnumFingerPosition.右手小指:
                    HelperSendReport(EnumSendReport.请采集右手小指指纹);
                    break;
                case EnumFingerPosition.右手拇指:
                    HelperSendReport(EnumSendReport.请采集右手拇指指纹);
                    break;
                case EnumFingerPosition.右手环指:
                    HelperSendReport(EnumSendReport.请采集右手无名指指纹);
                    break;
                case EnumFingerPosition.右手食指:
                    HelperSendReport(EnumSendReport.请采集右手食指指纹);
                    break;
                case EnumFingerPosition.左手中指:
                    HelperSendReport(EnumSendReport.请采集左手中指指纹);
                    break;
                case EnumFingerPosition.左手小指:
                    HelperSendReport(EnumSendReport.请采集左手小指指纹);
                    break;
                case EnumFingerPosition.左手拇指:
                    HelperSendReport(EnumSendReport.请采集左手拇指指纹);
                    break;
                case EnumFingerPosition.左手环指:
                    HelperSendReport(EnumSendReport.请采集左手无名指指纹);
                    break;
                case EnumFingerPosition.左手食指:
                    HelperSendReport(EnumSendReport.请采集左手食指指纹);
                    break;

            }
        }
        #endregion

        #region 附件
        /* *
         * B.4
         * 错误代码 [-1,参数错误],[-2,内存分配失败,没有分配到足够的内存],[-3,功能未实现],[-4,设备不存在],[-5,设备未初始化],[-6,非法错误号],[-9,其他错误]
         * 
         * 
         * */
        #endregion
    }
    public class PeopleBean
    {
        /// <summary>
        /// 姓名
        /// </summary>
        public string name { get; set; }
        /// <summary>
        /// 性别
        /// </summary>
        public string sex { get; set; }
        /// <summary>
        /// 民族
        /// </summary>
        public string nation { get; set; }
        /// <summary>
        /// 出生日期
        /// </summary>
        public string birthday { get; set; }
        /// <summary>
        /// 地址
        /// </summary>
        public string address { get; set; }
        /// <summary>
        /// 身份证号码
        /// </summary>
        public string number { get; set; }
        /// <summary>
        /// 签发机关
        /// </summary>
        public string signdate { get; set; }
        /// <summary>
        /// 起始日期
        /// </summary>
        public string validtermOfStart { get; set; }
        /// <summary>
        /// 截至日期
        /// </summary>
        public string validtermOfEnd { get; set; }
        /// <summary>
        /// 安全模块号
        /// </summary>
        public string samid { get; set;}
        /// <summary>
        /// 指纹
        /// </summary>
        public List<ICFeatureDataBean> listFeatureDataBean { get; set; }
        /// <summary>
        /// 照片
        /// </summary>
        public Image photo { get; set; }
    }
    /// <summary>
    /// 指纹信息
    /// </summary>
    public class ICFeatureDataBean
    {
        /// <summary>
        /// 文件头类型
        /// </summary>
        public int fileHeadType { get; set; }
        /// <summary>
        /// 指纹算法版本号
        /// </summary>
        public int version { get; set; }
        /// <summary>
        /// 指纹采集器代码
        /// </summary>
        public int collectorCode { get; set; }
        /// <summary>
        /// 指纹算法开发者代码
        /// </summary>
        public int developerCode { get; set; }
        /// <summary>
        /// 注册结果代码
        /// 01H 表示“注册成功”,02H 表示“注册失败”,03H 表示“未注册”,09H 表示“未知”
        /// </summary>
        public EnumRegistrationResult registrationResultCode { get; set; }
        /// <summary>
        /// 指位代码
        /// [0BH,右手拇指],[0CH,右手食指],[0DH,右手中指],[0EH,右手环指],[0FH,右手小指]
        /// [10H,左手拇指],[11H,左手食指],[12H,左手中指],[13H,左手环指],[14H,左手小指]
        /// [61H,右手不确定指位],[62H,左手不确定指位],[63H,其他不确定指位]
        /// </summary>
        public EnumFingerPosition fingerPositionCode { get; set; }
        /// <summary>
        /// 质量
        /// 值01H表示最低质量,值64H表示最高质量,值00H表示“未知”
        /// </summary>
        public int quality { get; set; }
        /// <summary>
        /// 指纹数据
        /// </summary>
        public byte[] buffer = new byte[512];
    }
    /// <summary>
    /// 注册结果
    /// </summary>
    public enum EnumRegistrationResult : int
    {
        注册成功=1,
        注册失败=2,
        未注册=3,
        未知=9,
    }
    /// <summary>
    /// 指位
    /// </summary>
    public enum EnumFingerPosition :int
    {
        右手拇指=11,
        右手食指=12,
        右手中指=13,
        右手环指=14,
        右手小指=15,
        左手拇指=16,
        左手食指=17,
        左手中指=18,
        左手环指=19,
        左手小指=20,
        右手不确定指位=97,
        左手不确定指位=98,
        其他不确定指位=99,
    }
    /// <summary>
    /// 声音
    /// </summary>
    public enum EnumSendReport :int
    {
        请将您的身份证放在读卡区域内=1,
        读卡成功=2,
        读卡失败请重新放卡=3,
        请采集右手拇指指纹=4,
        请采集右手无名指指纹=5,
        请采集右手中指指纹=6,
        请采集右手食指指纹=7,
        请采集右手小指指纹=8,
        请采集左手拇指指纹=9,
        请采集左手食指指纹=10,
        请采集左手中指指纹=11,
        请采集左手无名指指纹=12,
        请采集左手小指指纹=13,
        指纹采集成功=14,
        指纹对比成功=15,
        请面对摄像头=16,
        照片采集成功=17,
    }

}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Helper
{
    public class ViKeyAPI
    {
        public const string DefaultUserPassword = "11111111";
        public const string DefaultAdminPassword = "00000000";

        

        // 错误代码
        public const long VIKEY_SUCCESS = 0x00000000; //成功
        public const long VIKEY_ERROR_NO_VIKEY = 0x80000001; //没有找到ViKey加密锁
        public const long VIKEY_ERROR_INVALID_PASSWORD = 0x80000002; //密码错误
        public const long VIKEY_ERROR_NEED_FIND = 0x80000003; //请先查找加密锁
        public const long VIKEY_ERROR_INVALID_INDEX = 0x80000004; //无效的句柄
        public const long VIKEY_ERROR_INVALID_VALUE = 0x80000005; //数值错误
        public const long VIKEY_ERROR_INVALID_KEY = 0x80000006; //秘钥无效
        public const long VIKEY_ERROR_GET_VALUE = 0x80000007; //读取信息错误
        public const long VIKEY_ERROR_SET_VALUE = 0x80000008; //设置信息错误
        public const long VIKEY_ERROR_NO_CHANCE = 0x80000009; //没有机会
        public const long VIKEY_ERROR_NO_TAUTHORITY = 0x8000000A; //权限不足
        public const long VIKEY_ERROR_INVALID_ADDR_OR_SIZE = 0x8000000B; //地址或长度错误
        public const long VIKEY_ERROR_RANDOM = 0x8000000C; //获取随机数错误
        public const long VIKEY_ERROR_SEED = 0x8000000D; //获取种子错误
        public const long VIKEY_ERROR_CONNECTION = 0x8000000E; //通信错误
        public const long VIKEY_ERROR_CALCULATE = 0x8000000F; //算法或计算错误
        public const long VIKEY_ERROR_MODULE = 0x80000010; //计数器错误
        public const long VIKEY_ERROR_GENERATE_NEW_PASSWORD = 0x80000011; //产生密码错误
        public const long VIKEY_ERROR_ENCRYPT_FAILED = 0x80000012; //加密数据错误
        public const long VIKEY_ERROR_DECRYPT_FAILED = 0x80000013; //解密数据错误
        public const long VIKEY_ERROR_ALREADY_LOCKED = 0x80000014; //ViKey加密锁已经被锁定
        public const long VIKEY_ERROR_UNKNOWN_COMMAND = 0x80000015; //无效的命令
        public const long VIKEY_ERROR_UNKNOWN_ERROR = 0xFFFFFFFF; //未知错误

        //ViKey加密狗类型  VikeyGetType返回值代表的类型
        public const uint ViKeyAPP = 0;   //实用型加密狗ViKeyAPP
        public const uint ViKeySTD = 1;   //标准型加密狗ViKeySTD
        public const uint ViKeyNET = 2;   //网络型加密狗ViKeyNET
        public const uint ViKeyPRO = 3;   //专业型加密狗ViKeyPRO     
        public const uint ViKeyWEB = 4;   //身份认证型加密狗ViKeyWEB
        public const uint ViKeyTIME = 5;  //时间型加密狗ViKeyTIME

        #region 翻译
        /// <summary>
        /// 返回加密狗类型
        /// </summary>
        /// <param name="res"></param>
        /// <returns></returns>
        public static string GetTypeName(uint res)
        {
            if (res == ViKeyAPP)
                return "ViKeyApp";
            else if (res == ViKeySTD)
                return "ViKeySTD";
            else if (res == ViKeyNET)
                return "ViKeyNET";
            else if (res == ViKeyPRO)
                return "ViKeyPRO";
            else if (res == ViKeyWEB)
                return "VikeyWEB";
            else if (res == ViKeyTIME)
                return "VikeyTIME";
            else
                return "未知";
        }

        /// <summary>
        /// 获取错误信息
        /// </summary>
        /// <param name="res"></param>
        /// <returns></returns>
        public static string GetErrorMsg(uint res)
        {
            if (res == VIKEY_SUCCESS)
                return "成功!";
            else if (res == VIKEY_ERROR_NO_VIKEY)
                return "没有找到ViKey加密锁";
            else if (res == VIKEY_ERROR_INVALID_PASSWORD)
                return "密码错误";
            else if (res == VIKEY_ERROR_NEED_FIND)
                return "请先查找加密锁";
            else if (res == VIKEY_ERROR_INVALID_INDEX)
                return "无效的句柄";
            else if (res == VIKEY_ERROR_INVALID_VALUE)
                return "数值错误";
            else if (res == VIKEY_ERROR_INVALID_KEY)
                return "秘钥无效";
            else if (res == VIKEY_ERROR_GET_VALUE)
                return "读取信息错误";
            else if (res == VIKEY_ERROR_SET_VALUE)
                return "设置信息错误";
            else if (res == VIKEY_ERROR_NO_CHANCE)
                return "没有机会";
            else if (res == VIKEY_ERROR_NO_TAUTHORITY)
                return "权限不足";
            else if (res == VIKEY_ERROR_INVALID_ADDR_OR_SIZE)
                return "地址或长度错误";
            else if (res == VIKEY_ERROR_RANDOM)
                return "获取随机数错误";
            else if (res == VIKEY_ERROR_SEED)
                return "获取种子错误";
            else if (res == VIKEY_ERROR_CONNECTION)
                return "通信错误";
            else if (res == VIKEY_ERROR_CALCULATE)
                return "算法或计算错误";
            else if (res == VIKEY_ERROR_MODULE)
                return "计数器错误";
            else if (res == VIKEY_ERROR_GENERATE_NEW_PASSWORD)
                return "产生密码错误";
            else if (res == VIKEY_ERROR_ENCRYPT_FAILED)
                return "加密数据错误";
            else if (res == VIKEY_ERROR_DECRYPT_FAILED)
                return "解密数据错误";
            else if (res == VIKEY_ERROR_ALREADY_LOCKED)
                return "加密锁已经被锁定";
            else if (res == VIKEY_ERROR_UNKNOWN_COMMAND)
                return "无效的命令";
            else if (res == VIKEY_ERROR_UNKNOWN_ERROR)
                return "未知错误";
            else
                return "未知!";
        }
        #endregion

        #region 查找加密狗
        // 函数引用声明
        /// <summary>
        /// 查找系统中的ViKey加密狗
        /// 【注意】:程序访问ViKey加密狗前,必须先调用此函数,调用一次就可以。
        /// </summary>
        /// <param name="pdwCount">如果查找到系统中存在加密狗,返回查找到加密狗的个数</param>
        /// <returns>0:表示系统中存在ViKey加密狗 非0:表示系统中没有找到ViKey加密狗</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyFind(ref uint pdwCount);
        #endregion

        #region 登录注销加密狗

        /// <summary>
        /// 用户登陆加密狗,登陆成功后,加密狗的当前权限为用户权限。可以调用VikeyGetLevel获取加密狗的当前权限。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 比如,一共插了2个加密狗,Index=0表示操作第一个加密狗,Index=1表示操作第二个加密狗 </param>
        /// <param name="pUserPassword">【返回】加密狗的用户密码, 8个字母或数字</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义 </returns>
        [DllImport("ViKey")]
        public static extern uint VikeyUserLogin(ushort Index, Byte[] pUserPassword);
        /// <summary>
        /// 管理员登陆加密狗,登陆成功后,加密狗的当前权限为管理员权限。可以调用VikeyGetLevel获取加密狗的当前权限。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 比如,一共插了2个加密狗,Index=0表示操作第一个加密狗,Index=1表示操作第二个加密狗</param>
        /// <param name="pAdminPassword">【返回】加密狗的管理员密码, 8个字母或数字</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义 </returns>
        [DllImport("ViKey")]
        public static extern uint VikeyAdminLogin(ushort Index, Byte[] pAdminPassword);
        /// <summary>
        /// 登出(关闭)加密狗,调用该函数过后,加密狗的当前权限将变为匿名权限。
        /// 当程序不需要对加密狗进行操作时候,调用此函数关闭加密狗,以免其他误操作或者恶意程序对加密狗内部信息进行窃取。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 比如,一共插了2个加密狗,Index=0表示操作第一个加密狗,Index=1表示操作第二个加密狗</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyLogoff(ushort Index);
        #endregion

        #region 读写加密狗的基本信息
        /// <summary>
        /// 获取ViKey加密狗的硬件ID
        /// 长度为4个字节
        /// 一个DWORD
        /// 该硬件ID为ViKey加密狗的唯一标识,类似于人的身份证号码.
        /// 全球唯一,每个加密狗的都有一个全球唯一的硬件ID.
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号  比如,一共插了2个加密狗,Index=0表示操作第一个加密狗,Index=1表示操作第二个加密狗 </param>
        /// <param name="pdwHID">【返回】返回ViKey加密狗的硬件ID</param>
        /// <returns>0:表示函数执行成功  非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyGetHID(ushort Index, ref uint pdwHID);
        /// <summary>
        /// 获取ViKey加密狗的类型。ViKey系列加密狗有很多种类型,可以调用此函数获取当前加密狗的类型。
        /// 0 - ViKeyAPP   实用狗
        /// 1 - ViKeySTD   标准狗
        /// 2 - ViKeyNET   网络狗
        /// 3 - ViKeyPRO  专业狗
        /// 4 - ViKeyWEB 身份认证狗
        /// 5 - ViKeyTIME  时间狗
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 比如,一共插了2个加密狗,Index=0表示操作第一个加密狗,Index=1表示操作第二个加密狗 </param>
        /// <param name="pType">【返回】返回加密狗的产品类型 </param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义  </returns>
        [DllImport("ViKey")]
        public static extern uint VikeyGetType(ushort Index, ref uint pType);
        /// <summary>
        /// 获取ViKey加密狗的当前权限,ViKey加密狗有三级权限,匿名权限、用户权限、管理员权限
        /// 用户登陆(VikeyUserLogin)成功后加密狗的权限自动变为用户权限。
        /// 管理员登陆(VikeyAdminLogin)成功后加密狗的权限自动变为管理员权限。
        /// 每种权限可以对加密狗的操作均有限制,比如说用户权限,只能对数据区进行读取,不可写入,管理员权限对所有数据均有读写权限。
        /// 0 - 匿名权限
        /// 1 - 用户权限
        /// 2 - 管理员权限
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 比如,一共插了2个加密狗,Index=0表示操作第一个加密狗,Index=1表示操作第二个加密狗 </param>
        /// <param name="pLevel">【返回】返回雄狮加密狗的当前权限</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyGetLevel(ushort Index, ref Byte pLevel);
        /// <summary>
        /// 设置ViKey加密狗的设备名称,长度为16个字符或8个汉字,字母或数字
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 比如,一共插了2个加密狗,Index=0表示操作第一个加密狗,Index=1表示操作第二个加密狗</param>
        /// <param name="szName">【返回】ViKey加密狗的设备名称</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeySetPtroductName(ushort Index, Byte[] szName);
        /// <summary>
        /// 获取ViKey加密狗的设备名称,长度为16个字符或8个汉字,字母或数字 
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 比如,一共插了2个加密狗,Index=0表示操作第一个加密狗,Index=1表示操作第二个加密狗</param>
        /// <param name="szName">【返回】ViKey加密狗的设备名称</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyGetPtroductName(ushort Index, Byte[] szName);
        /// <summary>
        /// 设置加密狗的用户密码错误尝试次数,例如设置用户密码错误尝试次数为5,当执行用户登陆时候,如果连续
        /// 输入5次错误的密码,加密狗将被锁定,以后将不能登陆。该机制类似于银行卡密码,连续输入3次错误密码,银行卡将被
        /// 锁定。有效防止暴力破解、穷举密码的方式破解密码。
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 比如,一共插了2个加密狗,Index=0表示操作第一个加密狗,Index=1表示操作第二个加密狗</param>
        /// <param name="cAttempt">【输入】错误密码尝试次数 0:不做限制 非0:限制为指定次数 </param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeySetUserPassWordAttempt(ushort Index, Byte cAttempt);
        /// <summary>
        /// 设置加密狗的管理员密码错误尝试次数,例如设置管理员密码错误尝试次数为5,当执行管理员登陆时候,如果连续
        /// 输入5次错误的密码,加密狗将被锁定,以后将不能登陆。该机制类似于银行卡密码,连续输入3次错误密码,银行卡将被
        /// 锁定。有效防止暴力破解、穷举密码的方式破解密码。
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 比如,一共插了2个加密狗,Index=0表示操作第一个加密狗,Index=1表示操作第二个加密狗</param>
        /// <param name="cAttempt">【输入】错误密码尝试次数 0:不做限制 非0:限制为指定次数 </param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeySetAdminPassWordAttempt(ushort Index, Byte cAttempt);
        /// <summary>
        /// 获取加密狗的用户密码错误尝试次数,例如设置用户密码错误尝试次数为5,当执行用户登陆时候,如果连续
        /// 输入5次错误的密码,加密狗将被锁定,不能登陆。该机制类似于银行卡密码,连续输入3次错误密码,银行卡将被
        /// 锁定。有效防止暴力破解。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="pcCurrentAttempt">【返回】当前剩余的密码尝试次数</param>
        /// <param name="pcMaxAttempt">【返回】最大密码尝试次数,该次数为通过VikeySetUserPassWordAttempt设置的次数</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyGetUserPassWordAttempt(ushort Index, Byte pcCurrentAttempt, Byte pcMaxAttempt);
        /// <summary>
        /// 获取加密狗的管理员密码错误尝试次数,例如设置管理员密码错误尝试次数为5,当执行管理员登陆时候,如果连续
        /// 输入5次错误的密码,加密狗将被锁定,不能登陆。该机制类似于银行卡密码,连续输入3次错误密码,银行卡将被
        /// 锁定。有效防止暴力破解。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="pcCurrentAttempt">【返回】当前剩余的密码尝试次数</param>
        /// <param name="pcMaxAttempt">【返回】最大密码尝试次数,该次数为通过VikeySetAdminPassWordAttempt设置的次数</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyGetAdminPassWordAttempt(ushort Index, Byte pcCurrentAttempt, Byte pcMaxAttempt);
        #endregion

        #region 重置加密狗密码
        /// <summary>
        /// 修改ViKey加密狗的用户密码和管理员
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限,才能修改成功。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="pNewUserPassword">【输入】加密狗新的用户密码</param>
        /// <param name="pNewAdminPassword">【输入】加密狗新的管理员密码</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyResetPassword(ushort Index, Byte[] pNewUserPassword, Byte[] pNewAdminPassword);
        #endregion

        #region 获取随机数
        /// <summary>
        /// 获取4个随机数,在程序中程序员可能需要到随机数,可以调用加密狗的该函数获取加密狗中的随机数,更为安全。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="pReturn1">【返回】获取随机数1(0~65535)</param>
        /// <param name="pReturn2">【返回】获取随机数2(0~65535)</param>
        /// <param name="pReturn3">【返回】获取随机数3(0~65535)</param>
        /// <param name="pReturn4">【返回】获取随机数4(0~65535)</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint ViKeyRandom(ushort Index, ref ushort pReturn1, ref ushort pReturn2, ref ushort pReturn3, ref ushort pReturn4);
        #endregion

        #region 数据读写
        /// <summary>
        /// 设置加密狗的软件ID
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="SoftIDString">【输入】加密狗的软件ID标识, 8个字母或数字</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeySetSoftIDString(ushort Index, Byte[] SoftIDString);
        /// <summary>
        /// 获取加密狗的软件ID
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="SoftIDString">【返回】加密狗的软件ID标识, 8个字母或数字</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyGetSoftIDString(ushort Index, Byte[] SoftIDString);
        /// <summary>
        /// 读取加密狗的数据,加密狗有数据存储区,可供读写
        /// 【注意】:此函数需要用户权限,也就是说调用该函数前必须保证加密狗当前权限要大于用户权限。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 </param>
        /// <param name="pStartAddress">【输入】读取数据的起始地址</param>
        /// <param name="pBufferLength">【输入】读取数据的长度</param>
        /// <param name="pBuffer">【返回】读取到的数据</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyReadData(ushort Index, ushort pStartAddress, ushort pBufferLength, Byte[] pBuffer);
        /// <summary>
        /// 写入数据到加密狗,加密狗有数据存储区,可供读写
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限。 
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 </param>
        /// <param name="pStartAddress">【输入】写入数据的起始地址</param>
        /// <param name="pBufferLength">【输入】写入数据的长度</param>
        /// <param name="pBuffer">【返回】写入数据的指针</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyWriteData(ushort Index, ushort pStartAddress, ushort pBufferLength, Byte[] pBuffer);
        #endregion

        #region 计数器模块
        /// <summary>
        /// 将指定计数器中的数值减一
        /// ViKey加密狗为程序员提供一组计数器,该计数器只能递减,也就是递减计数器,可以设置初始值,调用该函数来实现减一。
        /// 【注意】:此函数需要用户权限,也就是说调用该函数前必须保证加密狗当前权限为用户权限,方可调用成功。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="ModelueIndex">【输入】计数器的序号</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint ViKeyDecraseModule(ushort Index, ushort ModelueIndex);
        /// <summary>
        /// 获取加密狗中计数器的值
        /// ViKey加密狗为程序员提供一组计数器,该计数器只能递减,也就是递减计数器,可以设置初始值,调用该函数来获取计数器中的数值。
        /// 【注意】:此函数需要用户权限,也就是说调用该函数前必须保证加密狗当前权限为用户权限,方可调用成功。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 </param>
        /// <param name="wModuleIndex">【输入】计数器的序号</param>
        /// <param name="pwValue">【返回】计数器中的值</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint ViKeyGetModule(ushort Index, ushort wModuleIndex, ushort pwValue);
        /// <summary>
        /// 设置递减计数器的初始值和模式
        /// ViKey加密狗为程序员提供一组计数器,该计数器只能递减,也就是递减计数器,调用该函数来设置计数值的初始状态。
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限。 
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="ModelueIndex">【输入】计数器的序号</param>
        /// <param name="pValue">【输入】计数器的值</param>
        /// <param name="pDecrease">【输入】计数器的模式   1:允许递减  0:不允许递减</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint ViKeySetModule(ushort Index, ushort ModelueIndex, ushort pValue, ushort pDecrease);
        /// <summary>
        /// 检查计数器的数值是否为零 模式是否允许可以递减
        /// ViKey加密狗为程序员提供一组计数器,该计数器只能递减,也就是递减计数器,调用该函数来检查计数器中的数值是否为0。
        /// 【注意】:此函数需要用户权限,也就是说调用该函数前必须保证加密狗当前权限为用户权限,方可调用成功。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="ModelueIndex">【输入】计数器的序号</param>
        /// <param name="pIsZero">【输入】是否为零</param>
        /// <param name="pCanDecrase">【输入】是否允许递减</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint ViKeyCheckModule(ushort Index, ushort ModelueIndex, ref ushort pIsZero, ref ushort pCanDecrase);
        #endregion

        #region 加解密算法
        /// <summary>
        /// 设置DES算法用到的秘钥Key,Des加解密算法是一种国际标准的加解密算法,安全性高,破解难度大.
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="pMD5key">【输入】秘钥地址,秘钥长度固定为8个字节</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyDesSetKey(ushort Index, Byte[] pMD5key);
        /// <summary>
        /// DES加密数据,加密长度必须为8的倍数
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 </param>
        /// <param name="length">【输入】要加密的数据长度,明文当长度必须为8的倍数</param>
        /// <param name="pText">【输入】明文地址</param>
        /// <param name="pResult">【返回】加密返回密文地址</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyDesEncrypt(ushort Index, ushort length, Byte[] pText, Byte[] pResult);
        /// <summary>
        /// DES解密数据,解密长度必须为8的倍数
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 </param>
        /// <param name="length">【输入】要解密的数据长度,明文当长度必须为8的倍数</param>
        /// <param name="pText">【输入】密文地址</param>
        /// <param name="pResult">【返回】解密返回明文地址</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyDesDecrypt(ushort Index, ushort length, Byte[] pText, Byte[] pResult);
        /// <summary>
        /// 设置3DES算法用到的秘钥Key,3Des加解密算法是一种国际标准的加解密算法,安全性高,破解难度大.
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限。 
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="pMD5key">【输入】秘钥地址</param>
        /// <param name="keyType">【输入】0表示密钥长度为16字节  1表示密钥长度为24字节</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint Vikey3DesSetKey(ushort Index, Byte[] pMD5key, ushort keyType);
        /// <summary>
        /// 3DES加密数据,向量为0,ECB模式 ,加密长度必须为8的倍数
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="length">【输入】要加密的数据长度,明文当长度必须为8的倍数</param>
        /// <param name="pText">【输入】明文地址</param>
        /// <param name="pResult">【返回】加密返回密文地址</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint Vikey3DesEncrypt(ushort Index, ushort length, Byte[] pText, Byte[] pResult);
        /// <summary>
        /// 3DES解密数据,向量为0,ECB模式 ,解密长度必须为8的倍数
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 </param>
        /// <param name="length">【输入】要解密的数据长度,明文当长度必须为8的倍数</param>
        /// <param name="pText">【输入】密文地址</param>
        /// <param name="pResult">【返回】解密返回明文地址</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint Vikey3DesDecrypt(ushort Index, ushort length, Byte[] pText, Byte[] pResult);

        #endregion

        #region 哈希认证算法
        /// <summary>
        /// 进行MD5哈希运算
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="length">【输入】数据长度</param>
        /// <param name="pText">【输入】数据内容</param>
        /// <param name="pResult">【返回】哈希运算结果</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyMD5(ushort Index, ushort length, Byte[] pText, Byte[] pResult);
        /// <summary>
        /// 设置MD5算法秘钥
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="pMD5key">【输入】秘钥内容</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeySetMD5Key(ushort Index, Byte[] pMD5key);
        /// <summary>
        /// 进行HMAC_MD5哈希运算
        /// 【注意】:此函数需要用户权限,也就是说调用该函数前必须保证加密狗当前权限为用户权限,方可调用成功。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号 </param>
        /// <param name="length">【输入】输入内容长度</param>
        /// <param name="pText">【输入】输入内容</param>
        /// <param name="pResult">【返回】计算结果</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyHmacMD5(ushort Index, ushort length, Byte[] pText, Byte[] pResult);
        /// <summary>
        /// 进行SHA1哈希运算
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="length">【输入】数据长度</param>
        /// <param name="pText">【输入】数据内容</param>
        /// <param name="pResult">【返回】哈希运算结果</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeySHA1(ushort Index, ushort length, Byte[] pText, Byte[] pResult);
        /// <summary>
        /// 设置SHA1算法秘钥
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限。 
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="pSHA1key">【输入】秘钥内容</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeySetSHA1Key(ushort Index, Byte[] pSHA1key);
        /// <summary>
        /// 进行HMAC_SHA1哈希运算
        /// 【注意】:此函数需要用户权限,也就是说调用该函数前必须保证加密狗当前权限为用户权限,方可调用成功。 
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="length">【输入】输入内容长度</param>
        /// <param name="pText">【输入】输入内容</param>
        /// <param name="pResult">【返回】计算结果</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyHmacSHA1(ushort Index, ushort length, Byte[] pText, Byte[] pResult);
        #endregion

        #region 时钟功能
        /// <summary>
        /// ViKeyTime时钟型加密狗,内部有独立的电子时钟,可以简单的理解为内部有个和人们带的电子表一样,可以实时获取当前
        /// 日期、时间,但是这个日期、时间无法被篡改。该函数就是获取加密狗内部时钟的时间。
        /// typedef struct _VIKEY_TIME 
        ///{ 
        ///     BYTE cYear; 
        ///     BYTE cMonth; 
        ///     BYTE cDay; 
        ///     BYTE cHour; 
        ///     BYTE cMinute; 
        ///     BYTE cSecond; 
        ///} SVikeyTime, *PVIKEYTIME;
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="pTime">【返回】当前日期、时间,6个字节内容分别是年月日时分秒</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyGetTime(ushort Index, Byte[] pTime);

        #endregion

        #region 网络功能
        /// <summary>
        /// 设置网络狗允许连接的最大客户端数,该函数只针对ViKeyNET网络狗有效
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限。 
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="dwCount">【输入】网络狗允许连接的最大客户端数</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeySetMaxClientCount(ushort Index, ushort dwCount);
        /// <summary>
        /// 获取网络狗允许连接的最大客户端数,该函数只针对ViKeyNET网络狗有效
        /// 【注意】:此函数需要用户权限,也就是说调用该函数前必须保证加密狗当前权限为用户权限,方可调用成功。
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="pdwCount">【返回】网络狗允许连接的最大客户端数</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyGetMaxClientCount(ushort Index, ushort pdwCount);
        #endregion

        #region 自动打开网页
        /// <summary>
        /// 在网页应用中,安装加密狗控件后,通过此接口设置自动打开网页的网址 
        /// 【注意】:此函数需要管理员权限,也就是说调用该函数前必须保证加密狗当前权限为管理员权限。 
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="pUrl">【输入】自动打开网页的网址,以零结尾的字符串</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeySetAutoRunUrl(ushort Index, Byte[] pUrl);
        /// <summary>
        /// 通过此接口获取自动打开网页的网址
        /// </summary>
        /// <param name="Index">【输入】指定加密狗的序号</param>
        /// <param name="pUrl">【返回】自动打开网页的网址</param>
        /// <returns>0:表示函数执行成功 非0:则表示函数失败,错误原因可以参见错误码含义</returns>
        [DllImport("ViKey")]
        public static extern uint VikeyGetAutoRunUrl(ushort Index, Byte[] pUrl);
        #endregion

        [DllImport("ViKey")]
        public static extern uint VikeySeed(ushort Index, ref uint pSeed, ref ushort pReturn1, ref ushort pReturn2, ref ushort pReturn3, ref ushort pReturn4);


        public static byte[] intToBytes(int value)
        {
            byte[] src = new byte[4];
            src[0] = (byte)((value >> 24) & 0xFF);
            src[1] = (byte)((value >> 16) & 0xFF);
            src[2] = (byte)((value >> 8) & 0xFF);
            src[3] = (byte)(value & 0xFF);
            return src;
        }
        public static int bytesToInt(byte[] src, int offset)
        {
            int value;
            value = (int)(((src[offset] & 0xFF) << 24)
                    | ((src[offset + 1] & 0xFF) << 16)
                    | ((src[offset + 2] & 0xFF) << 8)
                    | (src[offset + 3] & 0xFF));
            return value;
        }
    }
}

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

namespace API
{
    public static class ET99_API
    {
        #region 常量

        /// <summary>
        /// 函数执行成功 
        /// </summary>
        public const int ET_SUCCESS = 0x00;

        /// <summary>
        /// 访问被拒绝,权限不够 
        /// </summary>
        public const int ET_ACCESS_DENY = 0x01;

        /// <summary>
        /// 通讯错误,没有打开设备 
        /// </summary>
        public const int ET_COMMUNICATIONS_ERROR = 0x02;

        /// <summary>
        /// 无效的参数,参数出错 
        /// </summary>
        public const int ET_INVALID_PARAMETER = 0x03;

        /// <summary>
        /// 没有设置 PID 
        /// </summary>
        public const int ET_NOT_SET_PID = 0x04;

        /// <summary>
        /// 打开指定的设备失败 
        /// </summary>
        public const int ET_UNIT_NOT_FOUND = 0x05;

        /// <summary>
        /// 硬件错误 
        /// </summary>
        public const int ET_HARD_ERROR = 0x06;

        /// <summary>
        /// 未知错误 
        /// </summary>
        public const int ET_UNKNOWN_ERROR = 0x07;

        /// <summary>
        /// 验证 PIN码掩码 
        /// </summary>
        public const int ET_PIN_ERR_MASK = 0x0F;

        /// <summary>
        /// 验证 PIN码,设备被锁定
        /// </summary>
        public const int ET_PIN_ERR_LOCKED = 0xF0;

        /// <summary>
        /// 验证 PIN码错误且永远不锁死 
        /// </summary>
        public const int ET_PIN_ERR_MAX = 0xFF;

        /// <summary>
        /// 表示验证普通用户 pin 
        /// </summary>
        public const int ET_VERIFY_USERPIN = 0;

        /// <summary>
        /// 表示验证超级用户 pin 
        /// </summary>
        public const int ET_VERIFY_SOPIN = 1;

        /// <summary>
        /// 表示数据区可读写 
        /// </summary>
        public const int ET_USER_WRITE_READ = 0;

        /// <summary>
        /// 表示数据区只允许读
        /// </summary>
        public const int ET_USER_READ_ONLY = 1;

        /// <summary>
        /// 常量 PID,默认的产品PID
        /// </summary>
        public 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, StringBuilder 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.");
        }
    }
}

EmailHelper

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;

namespace Helper
{
    /// <summary>
    /// Author      : yenange
    /// Date        : 2014-02-26
    /// Description : 邮件发送辅助类
    /// </summary>
    public class EmailHelper
    {
        #region [ 属性(发送Email相关) ]
        private string _SmtpHost = string.Empty;
        private int _SmtpPort = -1;
        private string _FromEmailAddress = string.Empty;
        private string _FormEmailPassword = string.Empty;

        /// <summary>
        /// smtp 服务器 
        /// </summary>
        public string SmtpHost
        {
            get
            {
                if (string.IsNullOrEmpty(_SmtpHost))
                {
                    _SmtpHost = ConfigurationManager.AppSettings["SmtpHost"];
                }
                return _SmtpHost;
            }
        }
        /// <summary>
        /// smtp 服务器端口  默认为25
        /// </summary>
        public int SmtpPort
        {
            get
            {
                if (_SmtpPort == -1)
                {
                    if (!int.TryParse(ConfigurationManager.AppSettings["SmtpPort"], out _SmtpPort))
                    {
                        _SmtpPort = 25;
                    }
                }
                return _SmtpPort;
            }
        }
        /// <summary>
        /// 发送者 Eamil 地址
        /// </summary>
        public string FromEmailAddress
        {
            get
            {
                if (string.IsNullOrEmpty(_FromEmailAddress))
                {
                    _FromEmailAddress = ConfigurationManager.AppSettings["FromEmailAddress"];
                }
                return _FromEmailAddress;
            }
        }

        /// <summary>
        /// 发送者 Eamil 密码
        /// </summary>
        public string FormEmailPassword
        {
            get
            {
                if (string.IsNullOrEmpty(_FormEmailPassword))
                {
                    _FormEmailPassword = ConfigurationManager.AppSettings["FormEmailPassword"];
                }
                return _FormEmailPassword;
            }
        }
        #endregion

        #region [ 属性(邮件相关) ]
        /// <summary>
        /// 收件人 Email 列表,多个邮件地址之间用 半角逗号 分开
        /// </summary>
        public string ToList { get; set; }
        /// <summary>
        /// 邮件的抄送者,支持群发,多个邮件地址之间用 半角逗号 分开
        /// </summary>
        public string CCList { get; set; }
        /// <summary>
        /// 邮件的密送者,支持群发,多个邮件地址之间用 半角逗号 分开
        /// </summary>
        public string BccList { get; set; }
        /// <summary>
        /// 邮件标题
        /// </summary>
        public string Subject { get; set; }
        /// <summary>
        /// 邮件正文
        /// </summary>
        public string Body { get; set; }

        private bool _IsBodyHtml = true;
        /// <summary>
        /// 邮件正文是否为Html格式
        /// </summary>
        public bool IsBodyHtml
        {
            get { return _IsBodyHtml; }
            set { _IsBodyHtml = value; }
        }
        /// <summary>
        /// 附件列表
        /// </summary>
        public List<Attachment> AttachmentList { get; set; }
        #endregion

        #region [ 构造函数 ]
        /// <summary>
        /// 构造函数 (body默认为html格式)
        /// </summary>
        /// <param name="toList">收件人列表</param>
        /// <param name="subject">邮件标题</param>
        /// <param name="body">邮件正文</param>
        public EmailHelper(string toList, string subject, string body)
        {
            this.ToList = toList;
            this.Subject = subject;
            this.Body = body;
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="toList">收件人列表</param>
        /// <param name="subject">邮件标题</param>
        /// <param name="isBodyHtml">邮件正文是否为Html格式</param>
        /// <param name="body">邮件正文</param>
        public EmailHelper(string toList, string subject, bool isBodyHtml, string body)
        {
            this.ToList = toList;
            this.Subject = subject;
            this.IsBodyHtml = isBodyHtml;
            this.Body = body;
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="toList">收件人列表</param>
        /// <param name="ccList">抄送人列表</param>
        /// <param name="bccList">密送人列表</param>
        /// <param name="subject">邮件标题</param>
        /// <param name="isBodyHtml">邮件正文是否为Html格式</param>
        /// <param name="body">邮件正文</param>
        public EmailHelper(string toList, string ccList, string bccList, string subject, bool isBodyHtml, string body)
        {
            this.ToList = toList;
            this.CCList = ccList;
            this.BccList = bccList;
            this.Subject = subject;
            this.IsBodyHtml = isBodyHtml;
            this.Body = body;
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="toList">收件人列表</param>
        /// <param name="ccList">抄送人列表</param>
        /// <param name="bccList">密送人列表</param>
        /// <param name="subject">邮件标题</param>
        /// <param name="isBodyHtml">邮件正文是否为Html格式</param>
        /// <param name="body">邮件正文</param>
        /// <param name="attachmentList">附件列表</param>
        public EmailHelper(string toList, string ccList, string bccList, string subject, bool isBodyHtml, string body, List<Attachment> attachmentList)
        {
            this.ToList = toList;
            this.CCList = ccList;
            this.BccList = bccList;
            this.Subject = subject;
            this.IsBodyHtml = isBodyHtml;
            this.Body = body;
            this.AttachmentList = attachmentList;
        }
        #endregion

        #region [ 发送邮件 ]
        /// <summary>
        /// 发送邮件
        /// </summary>
        /// <returns></returns>
        public void Send()
        {
            SmtpClient smtp = new SmtpClient();                 //实例化一个SmtpClient
            smtp.DeliveryMethod = SmtpDeliveryMethod.Network;   //将smtp的出站方式设为 Network
            smtp.EnableSsl = false;                             //smtp服务器是否启用SSL加密
            smtp.Host = this.SmtpHost;                          //指定 smtp 服务器地址
            smtp.Port = this.SmtpPort;                          //指定 smtp 服务器的端口,默认是25,如果采用默认端口,可省去
            smtp.UseDefaultCredentials = true;                  //如果你的SMTP服务器不需要身份认证,则使用下面的方式,不过,目前基本没有不需要认证的了
            smtp.Credentials = new NetworkCredential(this.FromEmailAddress, this.FormEmailPassword);    //如果需要认证,则用下面的方式

            MailMessage mm = new MailMessage(); //实例化一个邮件类
            mm.Priority = MailPriority.Normal; //邮件的优先级,分为 Low, Normal, High,通常用 Normal即可
            mm.From = new MailAddress(this.FromEmailAddress, "管理员", Encoding.GetEncoding(936));

            //收件人
            if (!string.IsNullOrEmpty(this.ToList))
                mm.To.Add(this.ToList);
            //抄送人
            if (!string.IsNullOrEmpty(this.CCList))
                mm.CC.Add(this.CCList);
            //密送人
            if (!string.IsNullOrEmpty(this.BccList))
                mm.Bcc.Add(this.BccList);

            mm.Subject = this.Subject;                      //邮件标题
            mm.SubjectEncoding = Encoding.GetEncoding(936); //这里非常重要,如果你的邮件标题包含中文,这里一定要指定,否则对方收到的极有可能是乱码。
            mm.IsBodyHtml = this.IsBodyHtml;                //邮件正文是否是HTML格式
            mm.BodyEncoding = Encoding.GetEncoding(936);    //邮件正文的编码, 设置不正确, 接收者会收到乱码
            mm.Body = this.Body;                            //邮件正文
            //邮件附件
            if (this.AttachmentList != null && this.AttachmentList.Count > 0)
            {
                foreach (Attachment attachment in this.AttachmentList)
                {
                    mm.Attachments.Add(attachment);
                }
            }
            //发送邮件,如果不返回异常, 则大功告成了。
            smtp.Send(mm);
        }
        #endregion
    }
}

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

namespace Helper
{
    public class FTPHelper
    {
        /// <summary>  
        /// FTP请求对象  
        /// </summary>  
        FtpWebRequest request = null;
        /// <summary>  
        /// FTP响应对象  
        /// </summary>  
        FtpWebResponse response = null;
        /// <summary>  
        /// FTP服务器地址  
        /// </summary>  
        public string ftpURI { get; private set; }
        /// <summary>  
        /// FTP服务器IP  
        /// </summary>  
        public string ftpServerIP { get; private set; }
        /// <summary>  
        /// FTP服务器默认目录  
        /// </summary>  
        public string ftpRemotePath { get; private set; }
        /// <summary>  
        /// FTP服务器登录用户名  
        /// </summary>  
        public string ftpUserID { get; private set; }
        /// <summary>  
        /// FTP服务器登录密码  
        /// </summary>  
        public string ftpPassword { get; private set; }

        /// <summary>    
        /// 初始化  
        /// </summary>    
        /// <param name="FtpServerIP">FTP连接地址</param>    
        /// <param name="FtpRemotePath">指定FTP连接成功后的当前目录, 如果不指定即默认为根目录</param>    
        /// <param name="FtpUserID">用户名</param>    
        /// <param name="FtpPassword">密码</param>    
        public FTPHelper(string ftpServerIP, string ftpRemotePath, string ftpUserID, string ftpPassword)
        {
            this.ftpServerIP = ftpServerIP;
            this.ftpRemotePath = ftpRemotePath;
            this.ftpUserID = ftpUserID;
            this.ftpPassword = ftpPassword;
            this.ftpURI = "ftp://" + ftpServerIP + "/" + ftpRemotePath + "/";
        }
        ~FTPHelper()
        {
            if (response != null)
            {
                response.Close();
                response = null;
            }
            if (request != null)
            {
                request.Abort();
                request = null;
            }
        }
        /// <summary>  
        /// 建立FTP链接,返回响应对象  
        /// </summary>  
        /// <param name="uri">FTP地址</param>  
        /// <param name="ftpMethod">操作命令</param>  
        /// <returns></returns>  
        private FtpWebResponse Open(Uri uri, string ftpMethod)
        {
            request = (FtpWebRequest)FtpWebRequest.Create(uri);
            request.Method = ftpMethod;
            request.UseBinary = true;
            request.KeepAlive = false;
            request.Credentials = new NetworkCredential(this.ftpUserID, this.ftpPassword);
            return (FtpWebResponse)request.GetResponse();
        }

        /// <summary>         
        /// 建立FTP链接,返回请求对象         
        /// </summary>        
        /// <param name="uri">FTP地址</param>         
        /// <param name="ftpMethod">操作命令</param>         
        private FtpWebRequest OpenRequest(Uri uri, string ftpMethod)
        {
            request = (FtpWebRequest)WebRequest.Create(uri);
            request.Method = ftpMethod;
            request.UseBinary = true;
            request.KeepAlive = false;
            request.Credentials = new NetworkCredential(this.ftpUserID, this.ftpPassword);
            return request;
        }
        /// <summary>
        /// 验证登录用户是否合法
        /// </summary>
        /// <param name="ftpAddress">ftp路径</param>
        /// <param name="ftpUserName">ftp用户名</param>
        /// <param name="ftpUserPwd">ftp密码</param>
        /// <returns></returns>
        public bool CheckFtp()
        {
            bool res = false;

            try
            {
                request = (FtpWebRequest)FtpWebRequest.Create(this.ftpURI);
                request.Method = WebRequestMethods.Ftp.ListDirectory;//发送一个请求命令
                request.UseBinary = true;
                request.KeepAlive = false;
                request.Credentials = new NetworkCredential(this.ftpUserID, this.ftpPassword);
                FtpWebResponse ftpResponse = (FtpWebResponse)request.GetResponse();//响应一个请求
                ftpResponse.Close();

                res = true;
            }
            catch
            {
                res = false;
            }

            return res;
        }
        /// <summary>
        /// 验证登录用户是否合法
        /// </summary>
        /// <param name="ftpAddress">ftp路径</param>
        /// <param name="ftpUserName">ftp用户名</param>
        /// <param name="ftpUserPwd">ftp密码</param>
        /// <returns></returns>
        public static bool CheckFtp(string ftpAddress, string ftpUserName, string ftpUserPwd)
        {
            bool res = false;

            try
            {
                FtpWebRequest ftpWebRequest = (FtpWebRequest)WebRequest.Create("ftp://" + ftpAddress);//创建FtpWebRequest对象
                ftpWebRequest.Credentials = new NetworkCredential(ftpUserName, ftpUserPwd);//设置FTP登陆信息
                ftpWebRequest.Method = WebRequestMethods.Ftp.ListDirectory;//发送一个请求命令
                FtpWebResponse ftpResponse = (FtpWebResponse)ftpWebRequest.GetResponse();//响应一个请求
                ftpResponse.Close();//关闭请求
                res = true;
            }
            catch
            {
                res = false;
            }

            return res;
        }
        /// <summary>  
        /// 创建目录  
        /// </summary>  
        /// <param name="remoteDirectoryName">目录名</param>  
        public void CreateDirectory(string remoteDirectoryName)
        {
            response = Open(new Uri(ftpURI + remoteDirectoryName), WebRequestMethods.Ftp.MakeDirectory);
        }
        /// <summary>  
        /// 更改目录或文件名  
        /// </summary>  
        /// <param name="currentName">当前名称</param>  
        /// <param name="newName">修改后新名称</param>  
        public void ReName(string currentName, string newName)
        {
            request = OpenRequest(new Uri(ftpURI + currentName), WebRequestMethods.Ftp.Rename);
            request.RenameTo = newName;
            response = (FtpWebResponse)request.GetResponse();
        }
        /// <summary>    
        /// 切换当前目录    
        /// </summary>    
        /// <param name="IsRoot">true:绝对路径 false:相对路径</param>     
        public void GotoDirectory(string DirectoryName, bool IsRoot)
        {
            if (IsRoot)
                ftpRemotePath = DirectoryName;
            else
                ftpRemotePath += "/" + DirectoryName;

            ftpURI = "ftp://" + ftpServerIP + "/" + ftpRemotePath + "/";
        }
        /// <summary>  
        /// 删除目录(包括下面所有子目录和子文件)  
        /// </summary>  
        /// <param name="remoteDirectoryName">要删除的带路径目录名:如web/test</param>  
        /* 
         * 例:删除test目录 
         FTPHelper helper = new FTPHelper("x.x.x.x", "web", "user", "password");                   
         helper.RemoveDirectory("web/test"); 
         */
        public void RemoveDirectory(string remoteDirectoryName)
        {
            GotoDirectory(remoteDirectoryName, true);
            var listAll = ListFilesAndDirectories();
            foreach (var m in listAll)
            {
                if (m.IsDirectory)
                    RemoveDirectory(m.Path);
                else
                {

                    GotoDirectory(remoteDirectoryName, true);
                    DeleteFile(m.Name);
                }
            }
            GotoDirectory(remoteDirectoryName, true);
            response = Open(new Uri(ftpURI), WebRequestMethods.Ftp.RemoveDirectory);
        }
        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="remoteFilePatch"></param>
        public void RemoveFile(string remoteFilePatch)
        {
            string directoryName = remoteFilePatch.Substring(0, remoteFilePatch.LastIndexOf('/'));
            string fileName = remoteFilePatch.Replace(directoryName, "").Substring(1);
            GotoDirectory(directoryName, true);
            var listAll = ListFilesAndDirectories();
            foreach (var m in listAll)
            {
                if (m.Name == fileName)
                    DeleteFile(m.Name);
            }
        }
        /// <summary>
        /// 删除所有文件
        /// </summary>
        /// <param name="remoteFilePatch"></param>
        public void RemoveAllFile(string remoteFilePatch)
        {
            try
            {

                string directoryName = remoteFilePatch.Substring(0, remoteFilePatch.LastIndexOf('/')) + '/';
                if (System.IO.Directory.Exists(directoryName))//判断文件夹是否存在
                {

                    string[] strFiles = System.IO.Directory.GetFiles(remoteFilePatch);//获取文件数组
                    foreach (var item in strFiles)
                    {
                        System.IO.File.Delete(item);
                    }
                }
            }
            catch (Exception e)
            {

                System.Diagnostics.Debug.Write(e.Message.ToString());
            }

        }
        /// <summary>  
        /// 文件上传  
        /// </summary>  
        /// <param name="localFilePath">本地文件路径</param>  
        public void Upload(string localFilePath)
        {
            FileInfo fileInf = new FileInfo(localFilePath);
            request = OpenRequest(new Uri(ftpURI + fileInf.Name), WebRequestMethods.Ftp.UploadFile);
            request.ContentLength = fileInf.Length;
            int buffLength = 2048;
            byte[] buff = new byte[buffLength];
            int contentLen;
            using (var fs = fileInf.OpenRead())
            {
                using (var strm = request.GetRequestStream())
                {
                    contentLen = fs.Read(buff, 0, buffLength);
                    while (contentLen != 0)
                    {
                        strm.Write(buff, 0, contentLen);
                        contentLen = fs.Read(buff, 0, buffLength);
                    }
                }
            }
        }
        /// <summary>
        /// 上传图片并压缩
        /// </summary>
        /// <param name="img"></param>
        /// <param name="fileFullName"></param>
        public void UploadImg(System.Drawing.Image img, string fileFullName)
        {

            MemoryStream stream = new MemoryStream();
            System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(img);
            stream = ImageHelper.CompressImages(bmp, 30);
            request = OpenRequest(new Uri(ftpURI + fileFullName), WebRequestMethods.Ftp.UploadFile);
            request.ContentLength = stream.Length;
            int buffLength = 2048;
            byte[] buff = new byte[buffLength];
            int contentLen;
            stream.Position = 0;
            using (var strm = request.GetRequestStream())
            {
                contentLen = stream.Read(buff, 0, buffLength);
                while (contentLen != 0)
                {
                    strm.Write(buff, 0, contentLen);
                    contentLen = stream.Read(buff, 0, buffLength);
                }
            }
        }
        /// <summary>    
        /// 删除文件    
        /// </summary>    
        /// <param name="remoteFileName">要删除的文件名</param>  
        public void DeleteFile(string remoteFileName)
        {
            response = Open(new Uri(ftpURI + remoteFileName), WebRequestMethods.Ftp.DeleteFile);
        }

        /// <summary>  
        /// 获取当前目录的文件和一级子目录信息  
        /// </summary>  
        /// <returns></returns>  
        public List<FTPFileStruct> ListFilesAndDirectories()
        {
            var fileList = new List<FTPFileStruct>();
            response = Open(new Uri(ftpURI), WebRequestMethods.Ftp.ListDirectoryDetails);
            using (var stream = response.GetResponseStream())
            {
                using (var sr = new StreamReader(stream))
                {
                    string line = null;
                    while ((line = sr.ReadLine()) != null)
                    {
                        //line的格式如下:  
                        //08-18-13  11:05PM       <DIR>          aspnet_client  
                        //09-22-13  11:39PM                 2946 Default.aspx  
                        DateTime dtDate = DateTime.ParseExact(line.Substring(0, 8), "MM-dd-yy", null);
                        DateTime dtDateTime = DateTime.Parse(dtDate.ToString("yyyy-MM-dd") + line.Substring(8, 9));
                        string[] arrs = line.Split(' ');
                        var model = new FTPFileStruct()
                        {
                            IsDirectory = line.IndexOf("<DIR>") > 0 ? true : false,
                            CreateTime = dtDateTime,
                            Name = arrs[arrs.Length - 1],
                            Path = ftpRemotePath + "/" + arrs[arrs.Length - 1]
                        };
                        fileList.Add(model);
                    }
                }
            }
            return fileList;
        }
        /// <summary>         
        /// 列出当前目录的所有文件         
        /// </summary>         
        public List<FTPFileStruct> ListFiles()
        {
            var listAll = ListFilesAndDirectories();
            var listFile = listAll.Where(m => m.IsDirectory == false).ToList();
            return listFile;
        }
        /// <summary>         
        /// 列出当前目录的所有一级子目录         
        /// </summary>         
        public List<FTPFileStruct> ListDirectories()
        {
            var listAll = ListFilesAndDirectories();
            var listFile = listAll.Where(m => m.IsDirectory == true).ToList();
            return listFile;
        }
        /// <summary>         
        /// 判断当前目录下指定的子目录或文件是否存在         
        /// </summary>         
        /// <param name="remoteName">指定的目录或文件名</param>        
        public bool IsExist(string remoteName)
        {
            var list = ListFilesAndDirectories();
            if (list.Count(m => m.Name == remoteName) > 0)
                return true;
            return false;
        }
        /// <summary>         
        /// 判断当前目录下指定的一级子目录是否存在         
        /// </summary>         
        /// <param name="RemoteDirectoryName">指定的目录名</param>        
        public bool IsDirectoryExist(string remoteDirectoryName)
        {
            var listDir = ListDirectories();
            if (listDir.Count(m => m.Name == remoteDirectoryName) > 0)
                return true;
            return false;
        }
        /// <summary>         
        /// 判断当前目录下指定的子文件是否存在        
        /// </summary>         
        /// <param name="RemoteFileName">远程文件名</param>         
        public bool IsFileExist(string remoteFileName)
        {
            var listFile = ListFiles();
            if (listFile.Count(m => m.Name == remoteFileName) > 0)
                return true;
            return false;
        }

        /// <summary>  
        /// 下载  
        /// </summary>  
        /// <param name="saveFilePath">下载后的保存路径</param>  
        /// <param name="downloadFileName">要下载的文件名</param>  
        public void Download(string saveFilePath, string downloadFileName)
        {
            using (FileStream outputStream = new FileStream(saveFilePath + "\\" + downloadFileName, FileMode.Create))
            {
                response = Open(new Uri(ftpURI + downloadFileName), WebRequestMethods.Ftp.DownloadFile);
                using (Stream ftpStream = response.GetResponseStream())
                {
                    long cl = response.ContentLength;
                    int bufferSize = 2048;
                    int readCount;
                    byte[] buffer = new byte[bufferSize];
                    readCount = ftpStream.Read(buffer, 0, bufferSize);
                    while (readCount > 0)
                    {
                        outputStream.Write(buffer, 0, readCount);
                        readCount = ftpStream.Read(buffer, 0, bufferSize);
                    }
                }
            }
        }
        /// <summary>
        /// 下载文件流
        /// </summary>
        /// <param name="downloadFileName">要下载的文件名</param>
        /// <returns></returns>
        public Stream LoadStream(string downloadFileName)
        {
            response = Open(new Uri(ftpURI + downloadFileName), WebRequestMethods.Ftp.DownloadFile);
            using (Stream ftpStream = response.GetResponseStream())
            {
                return ftpStream;
            }
        }
        /// <summary>
        /// 载入远程图片
        /// </summary>
        /// <param name="downloadFileName">要下载的文件名</param>
        /// <returns></returns>
        public System.Drawing.Image LoadImg(string downloadFileName)
        {
            response = Open(new Uri(ftpURI + downloadFileName), WebRequestMethods.Ftp.DownloadFile);
            using (Stream ftpStream = response.GetResponseStream())
            {
                return System.Drawing.Image.FromStream(ftpStream);
            }
        }

    }

    public class FTPFileStruct
    {
        /// <summary>  
        /// 是否为目录  
        /// </summary>  
        public bool IsDirectory { get; set; }
        /// <summary>  
        /// 创建时间  
        /// </summary>  
        public DateTime CreateTime { get; set; }
        /// <summary>  
        /// 文件或目录名称  
        /// </summary>  
        public string Name { get; set; }
        /// <summary>  
        /// 路径  
        /// </summary>  
        public string Path { get; set; }
    }  
}

package

Install-Package System.Data.SQLite.EF6

Config

<connectionStrings>
    <add name="DB_HES" connectionString="Data Source=|DataDirectory|App_Data\DB_HES.db;Version=3;UseUnicode=true;characterEncoding=UTF-8;" providerName="System.Data.SQLite.EF6" />
</connectionStrings>

SqliteHelper

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;

namespace HES.AddAdmin
{
    /// <summary>
    /// 对SQLite操作的类
    /// 引用:System.Data.SQLite.dll【版本:3.6.23.1(原始文件名:SQlite3.DLL)】
    /// </summary>
    public class SQLiteHelper
    {
        /// <summary>
        /// 所有成员函数都是静态的,构造函数定义为私有
        /// </summary>
        private SQLiteHelper()
        {
        }
        /// <summary>
        /// 连接字符串
        /// </summary>
        public static string ConnectionString
        {//"Data Source=Test.db3;Pooling=true;FailIfMissing=false";
            get
            {
                ////(AppSettings节点下的"SQLiteConnectionString")
                string text = ConfigurationManager.ConnectionStrings["SQLiteConnectionString"].ConnectionString;
                //string str2 = ConfigurationManager.AppSettings["IsEncrypt"];
                //if (str2 == "true")
                //{
                //    text =  DesEncrypt.Decrypt(text);
                //}
                return text;
            }
        }
        private static SQLiteConnection _Conn = null;
        /// <summary>
        /// 连接对象
        /// </summary>
        public static SQLiteConnection Conn
        {
            get
            {
                if (_Conn == null) _Conn = new SQLiteConnection(ConnectionString);
                return SQLiteHelper._Conn;
            }
            set { SQLiteHelper._Conn = value; }
        }


        #region CreateCommand(commandText,SQLiteParameter[])
        /// <summary>
        /// 创建命令
        /// </summary>
        /// <param name="connection">连接</param>
        /// <param name="commandText">语句</param>
        /// <param name="commandParameters">语句参数.</param>
        /// <returns>SQLite Command</returns>
        public static SQLiteCommand CreateCommand(string commandText, params SQLiteParameter[] commandParameters)
        {
            SQLiteCommand cmd = new SQLiteCommand(commandText, Conn);
            if (commandParameters.Length > 0)
            {
                foreach (SQLiteParameter parm in commandParameters)
                    cmd.Parameters.Add(parm);
            }
            return cmd;
        }
        #endregion


        #region CreateParameter(parameterName,parameterType,parameterValue)
        /// <summary>
        /// 创建参数
        /// </summary>
        /// <param name="parameterName">参数名</param>
        /// <param name="parameterType">参数类型</param>
        /// <param name="parameterValue">参数值</param>
        /// <returns>返回创建的参数</returns>
        public static SQLiteParameter CreateParameter(string parameterName, System.Data.DbType parameterType, object parameterValue)
        {
            SQLiteParameter parameter = new SQLiteParameter();
            parameter.DbType = parameterType;
            parameter.ParameterName = parameterName;
            parameter.Value = parameterValue;
            return parameter;
        }
        #endregion

        #region ExecuteDataSet(commandText,paramList[])
        /// <summary>
        /// 查询数据集
        /// </summary>
        /// <param name="cn">连接.</param>
        /// <param name="commandText">查询语句.</param>
        /// <param name="paramList">object参数列表.</param>
        /// <returns></returns>
        public static DataSet ExecuteDataSet(string commandText, params object[] paramList)
        {

            SQLiteCommand cmd = Conn.CreateCommand();
            cmd.CommandText = commandText;
            if (paramList != null)
            {
                AttachParameters(cmd, commandText, paramList);
            }
            DataSet ds = new DataSet();
            if (Conn.State == ConnectionState.Closed)
                Conn.Open();
            SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);
            da.Fill(ds);
            da.Dispose();
            cmd.Dispose();
            Conn.Close();
            return ds;
        }
        #endregion

        #region ExecuteDataSet(SQLiteCommand)
        /// <summary>
        /// 查询数据集
        /// </summary>
        /// <param name="cmd">SQLiteCommand对象</param>
        /// <returns>返回数据集</returns>
        public static DataSet ExecuteDataSet(SQLiteCommand cmd)
        {
            if (cmd.Connection.State == ConnectionState.Closed)
                cmd.Connection.Open();
            DataSet ds = new DataSet();
            SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);
            da.Fill(ds);
            da.Dispose();
            cmd.Connection.Close();
            cmd.Dispose();
            return ds;
        }
        #endregion

        #region ExecuteDataSet(SQLiteTransaction,commandText,params SQLiteParameter[])
        /// <summary>
        /// 查询数据集
        /// </summary>
        /// <param name="transaction">SQLiteTransaction对象. </param>
        /// <param name="commandText">查询语句.</param>
        /// <param name="commandParameters">命令的参数列表.</param>
        /// <returns>DataSet</returns>
        /// <remarks>必须手动执行关闭连接transaction.connection.Close</remarks>
        public static DataSet ExecuteDataSet(SQLiteTransaction transaction, string commandText, params SQLiteParameter[] commandParameters)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rolled back or committed, please provide an open transaction.", "transaction");
            IDbCommand cmd = transaction.Connection.CreateCommand();
            cmd.CommandText = commandText;
            foreach (SQLiteParameter parm in commandParameters)
            {
                cmd.Parameters.Add(parm);
            }
            if (transaction.Connection.State == ConnectionState.Closed)
                transaction.Connection.Open();
            DataSet ds = ExecuteDataSet((SQLiteCommand)cmd);
            return ds;
        }
        #endregion

        #region ExecuteDataSet(SQLiteTransaction,commandText,object[] commandParameters)
        /// <summary>
        /// 查询数据集
        /// </summary>
        /// <param name="transaction">SQLiteTransaction对象 </param>
        /// <param name="commandText">查询语句.</param>
        /// <param name="commandParameters">命令参数列表</param>
        /// <returns>返回数据集</returns>
        /// <remarks>必须手动执行关闭连接transaction.connection.Close</remarks>
        public static DataSet ExecuteDataSet(SQLiteTransaction transaction, string commandText, object[] commandParameters)
        {

            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rolled back or committed,                                                          please provide an open transaction.", "transaction");
            IDbCommand cmd = transaction.Connection.CreateCommand();
            cmd.CommandText = commandText;
            AttachParameters((SQLiteCommand)cmd, cmd.CommandText, commandParameters);
            if (transaction.Connection.State == ConnectionState.Closed)
                transaction.Connection.Open();

            DataSet ds = ExecuteDataSet((SQLiteCommand)cmd);
            return ds;
        }
        #endregion

        #region UpdateDataset(insertCommand,deleteCommand,updateCommand,dataSet,tableName)
        /// <summary>
        /// 更新数据集中数据到数据库
        /// </summary>
        /// <param name="insertCommand">insert语句</param>
        /// <param name="deleteCommand">delete语句</param>
        /// <param name="updateCommand">update语句</param>
        /// <param name="dataSet">要更新的DataSet</param>
        /// <param name="tableName">数据集中要更新的table名</param>
        public static void UpdateDataset(SQLiteCommand insertCommand, SQLiteCommand deleteCommand, SQLiteCommand updateCommand, DataSet dataSet, string tableName)
        {
            if (insertCommand == null) throw new ArgumentNullException("insertCommand");
            if (deleteCommand == null) throw new ArgumentNullException("deleteCommand");
            if (updateCommand == null) throw new ArgumentNullException("updateCommand");
            if (tableName == null || tableName.Length == 0) throw new ArgumentNullException("tableName");

            // Create a SQLiteDataAdapter, and dispose of it after we are done
            using (SQLiteDataAdapter dataAdapter = new SQLiteDataAdapter())
            {
                // Set the data adapter commands

                dataAdapter.UpdateCommand = updateCommand;
                dataAdapter.InsertCommand = insertCommand;
                dataAdapter.DeleteCommand = deleteCommand;
                // Update the dataset changes in the data source
                dataAdapter.Update(dataSet, tableName);

                // Commit all the changes made to the DataSet
                dataSet.AcceptChanges();
            }
        }
        #endregion

        #region ExecuteReader(SQLiteCommand,commandText, object[] paramList)
        /// <summary>
        /// ExecuteReader方法
        /// </summary>
        /// <param name="cmd">查询命令</param>
        /// <param name="commandText">含有类似@colume参数的sql语句</param>
        /// <param name="paramList">语句参数列表</param>
        /// <returns>IDataReader</returns>
        public static IDataReader ExecuteReader(SQLiteCommand cmd, string commandText, object[] paramList)
        {
            if (cmd.Connection == null)
                throw new ArgumentException("没有为命令指定活动的连接.", "cmd");
            cmd.CommandText = commandText;
            AttachParameters(cmd, commandText, paramList);
            if (cmd.Connection.State == ConnectionState.Closed)
                cmd.Connection.Open();
            IDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            return rdr;
        }
        #endregion

        #region ExecuteNonQuery(commandText,paramList)
        /// <summary>
        /// 执行ExecuteNonQuery方法
        /// </summary>
        /// <param name="cn">连接</param>
        /// <param name="commandText">语句</param>
        /// <param name="paramList">参数</param>
        /// <returns></returns>
        public static int ExecuteNonQuery(string commandText, params  object[] paramList)
        {

            SQLiteCommand cmd = Conn.CreateCommand();
            cmd.CommandText = commandText;
            AttachParameters(cmd, commandText, paramList);
            if (Conn.State == ConnectionState.Closed)
                Conn.Open();
            int result = cmd.ExecuteNonQuery();
            cmd.Dispose();
            Conn.Close();

            return result;
        }
        #endregion

        #region ExecuteNonQuery(SQLiteTransaction,commandText,paramList)
        /// <summary>
        /// 执行ExecuteNonQuery方法,带事务
        /// </summary>
        /// <param name="transaction">之前创建好的SQLiteTransaction对象</param>
        /// <param name="commandText">语句.</param>
        /// <param name="paramList">参数.</param>
        /// <returns>返回影响的行数</returns>
        /// <remarks>
        /// 定义事务  DbTransaction trans = conn.BeginTransaction();
        ///     或者:SQLiteTransaction trans = Conn.BeginTransaction();
        /// 操作代码示例:
        /// try
        ///{
        ///    // 连续操作记录 
        ///    for (int i = 0; i < 1000; i++)
        ///    {
        ///        ExecuteNonQuery(trans,commandText,[] paramList);
        ///    }
        ///    trans.Commit();
        ///}
        ///catch
        ///{
        ///    trans.Rollback();
        ///    throw;
        ///}
        ///trans.Connection.Close();//关闭事务连接
        ///transaction.Dispose();//释放事务对象
        /// </remarks>
        public static int ExecuteNonQuery(SQLiteTransaction transaction, string commandText, params  object[] paramList)
        {
            if (transaction == null) throw new ArgumentNullException("transaction is null");
            if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rolled back or committed,please provide an open transaction.", "transaction");
            using (IDbCommand cmd = transaction.Connection.CreateCommand())
            {
                cmd.CommandText = commandText;
                AttachParameters((SQLiteCommand)cmd, cmd.CommandText, paramList);
                if (transaction.Connection.State == ConnectionState.Closed)
                    transaction.Connection.Open();
                int result = cmd.ExecuteNonQuery();
                return result;
            }

        }
        #endregion

        #region ExecuteNonQuery(IDbCommand)
        /// <summary>
        /// 执行ExecuteNonQuery方法
        /// </summary>
        /// <param name="cmd">创建好的命令.</param>
        /// <returns></returns>
        public static int ExecuteNonQuery(IDbCommand cmd)
        {
            if (cmd.Connection.State == ConnectionState.Closed)
                cmd.Connection.Open();
            int result = cmd.ExecuteNonQuery();
            cmd.Connection.Close();
            cmd.Dispose();
            return result;
        }
        #endregion

        #region ExecuteScalar(commandText,paramList)
        /// <summary>
        /// 执行ExecuteScalar
        /// </summary>
        /// <param name="commandText">语句s</param>
        /// <param name="paramList">参数</param>
        /// <returns></returns>
        public static object ExecuteScalar(string commandText, params  object[] paramList)
        {
            SQLiteConnection cn = new SQLiteConnection(ConnectionString);
            SQLiteCommand cmd = cn.CreateCommand();
            cmd.CommandText = commandText;
            AttachParameters(cmd, commandText, paramList);
            if (cn.State == ConnectionState.Closed)
                cn.Open();
            object result = cmd.ExecuteScalar();
            cmd.Dispose();
            cn.Close();
            return result;
        }
        #endregion

        #region ExecuteXmlReader(IDbCommand)
        /// <summary>
        /// ExecuteXmlReader返回xml格式
        /// </summary>
        /// <param name="command">语句</param>
        /// <returns>返回XmlTextReader对象</returns>
        public static XmlReader ExecuteXmlReader(IDbCommand command)
        { // open the connection if necessary, but make sure we 
            // know to close it when we�1�7re done.
            if (command.Connection.State != ConnectionState.Open)
            {
                command.Connection.Open();
            }

            // get a data adapter  
            SQLiteDataAdapter da = new SQLiteDataAdapter((SQLiteCommand)command);
            DataSet ds = new DataSet();
            // fill the data set, and return the schema information
            da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
            da.Fill(ds);
            // convert our dataset to XML
            StringReader stream = new StringReader(ds.GetXml());
            command.Connection.Close();
            // convert our stream of text to an XmlReader
            return new XmlTextReader(stream);
        }
        #endregion

        #region AttachParameters(SQLiteCommand,commandText,object[] paramList)
        /// <summary>
        /// 增加参数到命令(自动判断类型)
        /// </summary>
        /// <param name="commandText">命令语句</param>
        /// <param name="paramList">object参数列表</param>
        /// <returns>返回SQLiteParameterCollection参数列表</returns>
        /// <remarks>Status experimental. Regex appears to be handling most issues. Note that parameter object array must be in same ///order as parameter names appear in SQL statement.</remarks>
        private static SQLiteParameterCollection AttachParameters(SQLiteCommand cmd, string commandText, params  object[] paramList)
        {
            if (paramList == null || paramList.Length == 0) return null;

            SQLiteParameterCollection coll = cmd.Parameters;
            string parmString = commandText.Substring(commandText.IndexOf("@"));
            // pre-process the string so always at least 1 space after a comma.
            parmString = parmString.Replace(",", " ,");
            // get the named parameters into a match collection
            string pattern = @"(@)\S*(.*?)\b";
            Regex ex = new Regex(pattern, RegexOptions.IgnoreCase);
            MatchCollection mc = ex.Matches(parmString);
            string[] paramNames = new string[mc.Count];
            int i = 0;
            foreach (Match m in mc)
            {
                paramNames[i] = m.Value;
                i++;
            }

            // now let's type the parameters
            int j = 0;
            Type t = null;
            foreach (object o in paramList)
            {
                t = o.GetType();

                SQLiteParameter parm = new SQLiteParameter();
                switch (t.ToString())
                {

                    case ("DBNull"):
                    case ("Char"):
                    case ("SByte"):
                    case ("UInt16"):
                    case ("UInt32"):
                    case ("UInt64"):
                        throw new SystemException("Invalid data type");


                    case ("System.String"):
                        parm.DbType = DbType.String;
                        parm.ParameterName = paramNames[j];
                        parm.Value = (string)paramList[j];
                        coll.Add(parm);
                        break;

                    case ("System.Byte[]"):
                        parm.DbType = DbType.Binary;
                        parm.ParameterName = paramNames[j];
                        parm.Value = (byte[])paramList[j];
                        coll.Add(parm);
                        break;

                    case ("System.Int32"):
                        parm.DbType = DbType.Int32;
                        parm.ParameterName = paramNames[j];
                        parm.Value = (int)paramList[j];
                        coll.Add(parm);
                        break;

                    case ("System.Boolean"):
                        parm.DbType = DbType.Boolean;
                        parm.ParameterName = paramNames[j];
                        parm.Value = (bool)paramList[j];
                        coll.Add(parm);
                        break;

                    case ("System.DateTime"):
                        parm.DbType = DbType.DateTime;
                        parm.ParameterName = paramNames[j];
                        parm.Value = Convert.ToDateTime(paramList[j]);
                        coll.Add(parm);
                        break;

                    case ("System.Double"):
                        parm.DbType = DbType.Double;
                        parm.ParameterName = paramNames[j];
                        parm.Value = Convert.ToDouble(paramList[j]);
                        coll.Add(parm);
                        break;

                    case ("System.Decimal"):
                        parm.DbType = DbType.Decimal;
                        parm.ParameterName = paramNames[j];
                        parm.Value = Convert.ToDecimal(paramList[j]);
                        break;

                    case ("System.Guid"):
                        parm.DbType = DbType.Guid;
                        parm.ParameterName = paramNames[j];
                        parm.Value = (System.Guid)(paramList[j]);
                        break;

                    case ("System.Object"):

                        parm.DbType = DbType.Object;
                        parm.ParameterName = paramNames[j];
                        parm.Value = paramList[j];
                        coll.Add(parm);
                        break;

                    default:
                        throw new SystemException("Value is of unknown data type");

                } // end switch

                j++;
            }
            return coll;
        }
        #endregion

        #region ExecuteNonQueryTypedParams(IDbCommand, DataRow)
        /// <summary>
        /// Executes non query typed params from a DataRow
        /// </summary>
        /// <param name="command">Command.</param>
        /// <param name="dataRow">Data row.</param>
        /// <returns>Integer result code</returns>
        public static int ExecuteNonQueryTypedParams(IDbCommand command, DataRow dataRow)
        {
            int retVal = 0;

            // If the row has values, the store procedure parameters must be initialized
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Set the parameters values
                AssignParameterValues(command.Parameters, dataRow);

                retVal = ExecuteNonQuery(command);
            }
            else
            {
                retVal = ExecuteNonQuery(command);
            }

            return retVal;
        }
        #endregion

        #region AssignParameterValues
        /// <summary>
        /// This method assigns dataRow column values to an IDataParameterCollection
        /// </summary>
        /// <param name="commandParameters">The IDataParameterCollection to be assigned values</param>
        /// <param name="dataRow">The dataRow used to hold the command's parameter values</param>
        /// <exception cref="System.InvalidOperationException">Thrown if any of the parameter names are invalid.</exception>
        protected internal static void AssignParameterValues(IDataParameterCollection commandParameters, DataRow dataRow)
        {
            if (commandParameters == null || dataRow == null)
            {
                // Do nothing if we get no data
                return;
            }

            DataColumnCollection columns = dataRow.Table.Columns;

            int i = 0;
            // Set the parameters values
            foreach (IDataParameter commandParameter in commandParameters)
            {
                // Check the parameter name
                if (commandParameter.ParameterName == null ||
                 commandParameter.ParameterName.Length <= 1)
                    throw new InvalidOperationException(string.Format(
                           "Please provide a valid parameter name on the parameter #{0},                            the ParameterName property has the following value: '{1}'.",
                     i, commandParameter.ParameterName));

                if (columns.Contains(commandParameter.ParameterName))
                    commandParameter.Value = dataRow[commandParameter.ParameterName];
                else if (columns.Contains(commandParameter.ParameterName.Substring(1)))
                    commandParameter.Value = dataRow[commandParameter.ParameterName.Substring(1)];

                i++;
            }
        }
        #endregion

        #region AssignParameterValues
        /// <summary>
        /// This method assigns dataRow column values to an array of IDataParameters
        /// </summary>
        /// <param name="commandParameters">Array of IDataParameters to be assigned values</param>
        /// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values</param>
        /// <exception cref="System.InvalidOperationException">Thrown if any of the parameter names are invalid.</exception>
        protected void AssignParameterValues(IDataParameter[] commandParameters, DataRow dataRow)
        {
            if ((commandParameters == null) || (dataRow == null))
            {
                // Do nothing if we get no data
                return;
            }

            DataColumnCollection columns = dataRow.Table.Columns;

            int i = 0;
            // Set the parameters values
            foreach (IDataParameter commandParameter in commandParameters)
            {
                // Check the parameter name
                if (commandParameter.ParameterName == null ||
                 commandParameter.ParameterName.Length <= 1)
                    throw new InvalidOperationException(string.Format(
                     "Please provide a valid parameter name on the parameter #{0}, the ParameterName property has the following value: '{1}'.",
                     i, commandParameter.ParameterName));

                if (columns.Contains(commandParameter.ParameterName))
                    commandParameter.Value = dataRow[commandParameter.ParameterName];
                else if (columns.Contains(commandParameter.ParameterName.Substring(1)))
                    commandParameter.Value = dataRow[commandParameter.ParameterName.Substring(1)];

                i++;
            }
        }
        #endregion

        #region AssignParameterValues
        /// <summary>
        /// This method assigns an array of values to an array of IDataParameters
        /// </summary>
        /// <param name="commandParameters">Array of IDataParameters to be assigned values</param>
        /// <param name="parameterValues">Array of objects holding the values to be assigned</param>
        /// <exception cref="System.ArgumentException">Thrown if an incorrect number of parameters are passed.</exception>
        protected void AssignParameterValues(IDataParameter[] commandParameters, params  object[] parameterValues)
        {
            if ((commandParameters == null) || (parameterValues == null))
            {
                // Do nothing if we get no data
                return;
            }

            // We must have the same number of values as we pave parameters to put them in
            if (commandParameters.Length != parameterValues.Length)
            {
                throw new ArgumentException("Parameter count does not match Parameter Value count.");
            }

            // Iterate through the IDataParameters, assigning the values from the corresponding position in the 
            // value array
            for (int i = 0, j = commandParameters.Length, k = 0; i < j; i++)
            {
                if (commandParameters[i].Direction != ParameterDirection.ReturnValue)
                {
                    // If the current array value derives from IDataParameter, then assign its Value property
                    if (parameterValues[k] is IDataParameter)
                    {
                        IDataParameter paramInstance;
                        paramInstance = (IDataParameter)parameterValues[k];
                        if (paramInstance.Direction == ParameterDirection.ReturnValue)
                        {
                            paramInstance = (IDataParameter)parameterValues[++k];
                        }
                        if (paramInstance.Value == null)
                        {
                            commandParameters[i].Value = DBNull.Value;
                        }
                        else
                        {
                            commandParameters[i].Value = paramInstance.Value;
                        }
                    }
                    else if (parameterValues[k] == null)
                    {
                        commandParameters[i].Value = DBNull.Value;
                    }
                    else
                    {
                        commandParameters[i].Value = parameterValues[k];
                    }
                    k++;
                }
            }
        }
        #endregion


    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Helper
{
    /// <summary>
    /// 查询语句帮助类
    /// </summary>
    public static class LinqHelper
    {


        /// <summary>
        /// 动态排序
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="source">数据源</param>
        /// <param name="sortExpression">排序字段</param>
        /// <param name="sortDirection">排序方式</param>
        /// <returns></returns>
        public static IQueryable<T> DataSorting<T>(IQueryable<T> source, string sortExpression, string sortDirection)
        {
            string sortingDir = string.Empty;
            if (sortDirection.ToUpper().Trim() == "ASC")
                return source.OrderBy(a => typeof(T).GetProperty(sortExpression).GetValue(a, null));
            else 
                return source.OrderByDescending(a => typeof(T).GetProperty(sortExpression).GetValue(a, null));
        }
        /// <summary>
        /// 动态排序旧方法
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="source">数据源</param>
        /// <param name="sortExpression">排序字段</param>
        /// <param name="sortDirection">排序方式</param>
        /// <returns></returns>
        public static IQueryable<T> DataSorting1<T>(IQueryable<T> source, string sortExpression, string sortDirection)
        {
            string sortingDir = string.Empty;
            if (sortDirection.ToUpper().Trim() == "ASC")
                sortingDir = "OrderBy";
            else if (sortDirection.ToUpper().Trim() == "DESC")
                sortingDir = "OrderByDescending";
            ParameterExpression param = Expression.Parameter(typeof(T), sortExpression);
            PropertyInfo pi = typeof(T).GetProperty(sortExpression);
            Type[] types = new Type[2];
            types[0] = typeof(T);
            types[1] = pi.PropertyType;
            Expression expr = Expression.Call(typeof(Queryable), sortingDir, types, source.Expression, Expression.Lambda(Expression.Property(param, sortExpression), param));
            IQueryable<T> query = source.AsQueryable().Provider.CreateQuery<T>(expr);
            return query;
        }
        /// <summary>
        /// 分页
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="source">数据源</param>
        /// <param name="pageIndex">分页页码从第一页开始</param>
        /// <param name="pageSize">页码</param>
        /// <returns></returns>
        public static IQueryable<T> DataPaging<T>(IQueryable<T> source, int pageIndex, int pageSize)
        {
            return source.Skip((pageIndex-1) * pageSize).Take(pageSize);
        }
        /// <summary>
        /// 排序并分页
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="source">数据源</param>
        /// <param name="sortExpression">排序字段</param>
        /// <param name="sortDirection">排序方式</param>
        /// <param name="pageNumber">分页页码从第一页开始</param>
        /// <param name="pageSize">页码</param>
        /// <returns></returns>
        public static IQueryable<T> SortingAndPaging<T>(IQueryable<T> source, string sortExpression, string sortDirection, int pageNumber, int pageSize)
        {
            IQueryable<T> query = DataSorting<T>(source, sortExpression, sortDirection);
            return DataPaging(query, pageNumber, pageSize);
        }
    }
}

public enum LogType
    {
        Overall,
    }

    public class LogHelper
    {
        public static string LogPath
        {
            get
            {
                return AppDomain.CurrentDomain.BaseDirectory+@"\log";
            }
        }

        public enum LogLevel
        {
            Info,
            Error
        }

        public static void Info(string message, LogType logType = LogType.Overall)
        {
            if (string.IsNullOrEmpty(message))
                return;
            var path = string.Format(@"\{0}\", logType.ToString());
            WriteLog(path, "", message);
        }

        public static void Error(string message, LogType logType = LogType.Overall)
        {
            if (string.IsNullOrEmpty(message))
                return;
            var path = string.Format(@"\{0}\", logType.ToString());
            WriteLog(path, "Error ", message);
        }

        public static void Error(Exception e, LogType logType = LogType.Overall)
        {
            if (e == null)
                return;
            var path = string.Format(@"\{0}\", logType.ToString());
            WriteLog(path, "Error ", e.Message);
        }

        private static void WriteLog(string path, string prefix, string message)
        {
            path = LogPath + path;
            var fileName = string.Format("{0}{1}.log", prefix, DateTime.Now.ToString("yyyyMMdd"));

            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);

            using (FileStream fs = new FileStream(path + fileName, FileMode.Append, FileAccess.Write,
                                                  FileShare.Write, 1024, FileOptions.Asynchronous))
            {
                byte[] buffer = System.Text.Encoding.UTF8.GetBytes(DateTime.Now.ToString("HH:mm:ss") + " " + message + "\r\n");
                IAsyncResult writeResult = fs.BeginWrite(buffer, 0, buffer.Length,
                    (asyncResult) =>
                    {
                        var fStream = (FileStream)asyncResult.AsyncState;
                        fStream.EndWrite(asyncResult);
                    },

                    fs);
                fs.Close();
            }
        }
    }

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;

namespace HesPis.Helper
{
    public static class XmlHelper
    {
        private static string SettingPath
        {
            get
            {
                return AppDomain.CurrentDomain.BaseDirectory + @"\Config";
            }
        }
        #region Fields and Properties

        public enum XmlType
        {
            File,
            String
        }

        #endregion

        #region  Methods

        /// <summary>
        ///     创建XML文档
        /// </summary>
        /// <param name="name">根节点名称</param>
        /// <param name="type">根节点的一个属性值</param>
        /// <returns></returns>
        public static XmlDocument CreateXmlDocument(string name, string type)
        {
            /**************************************************
            * .net中调用方法:写入文件中,则:
            *document = XmlOperate.CreateXmlDocument("sex", "sexy");
            *document.Save("c:/bookstore.xml");
            ************************************************/
            XmlDocument xmlDocument;
            try
            {
                xmlDocument = new XmlDocument();
                xmlDocument.LoadXml("<" + name + "/>");
                var rootElement = xmlDocument.DocumentElement;
                rootElement?.SetAttribute("type", type);
            }
            catch (Exception exception)
            {
                throw exception;
            }
            return xmlDocument;
        }

        /// <summary>
        ///     删除数据
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="node">节点</param>
        /// <param name="attribute">属性名,非空时删除该节点属性值,否则删除节点值</param>
        /// <returns></returns>
        public static void Delete(string path, string node, string attribute)
        {
            /**************************************************
             * 使用示列:
             * XmlHelper.Delete(path, "/Node", "")
             * XmlHelper.Delete(path, "/Node", "Attribute")
             ************************************************/
            try
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.Load(path);
                var selectSingleNode = xmlDocument.SelectSingleNode(node);
                var xmlElement = (XmlElement)selectSingleNode;
                if (attribute.Equals(""))
                    selectSingleNode?.ParentNode?.RemoveChild(selectSingleNode);
                else
                    xmlElement?.RemoveAttribute(attribute);
                xmlDocument.Save(path);
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     读取XML资源到DataSet中
        /// </summary>
        /// <param name="source">XML资源,文件为路径,否则为XML字符串</param>
        /// <param name="xmlType">XML资源类型</param>
        /// <returns>DataSet</returns>
        public static DataSet GetDataSet(string source, XmlType xmlType)
        {
            try
            {
                var dataSet = new DataSet();
                if (xmlType == XmlType.File)
                {
                    dataSet.ReadXml(source);
                }
                else
                {
                    var xmlDocument = new XmlDocument();
                    xmlDocument.LoadXml(source);
                    var xmlNodeReader = new XmlNodeReader(xmlDocument);
                    dataSet.ReadXml(xmlNodeReader);
                }
                return dataSet;
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     获得xml文件中指定节点的节点数据
        /// </summary>
        /// <returns></returns>
        public static string GetNodeInfoByNodeName(string path, string nodeName)
        {
            try
            {
                var xmlString = "";
                var xmlDocument = new XmlDocument();
                xmlDocument.Load(path);
                var documentElementRoot = xmlDocument.DocumentElement;
                var selectSingleNode = documentElementRoot?.SelectSingleNode("//" + nodeName);
                if (selectSingleNode != null)
                    xmlString = selectSingleNode.InnerText;
                return xmlString;
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     读取XML资源中的指定节点内容
        /// </summary>
        /// <param name="source">XML资源</param>
        /// <param name="xmlType">XML资源类型:文件,字符串</param>
        /// <param name="nodeName">节点名称</param>
        /// <returns>节点内容</returns>
        public static string GetNodeValue(string source, XmlType xmlType, string nodeName)
        {
            var xmlDocument = new XmlDocument();
            if (xmlType == XmlType.File)
                xmlDocument.Load(source);
            else
                xmlDocument.LoadXml(source);
            var documentElement = xmlDocument.DocumentElement;
            var selectSingleNode = documentElement?.SelectSingleNode("//" + nodeName);
            return selectSingleNode?.InnerText;
        }


        /// <summary>
        ///     读取XML资源中的指定节点属性的内容
        /// </summary>
        /// <param name="source">XML资源</param>
        /// <param name="xmlType">XML资源类型:文件,字符串</param>
        /// <param name="nodeName">属性节点名称</param>
        /// <param name="attributeString"></param>
        /// <returns>节点内容</returns>
        public static string GetNodeAttributeValue(string source, XmlType xmlType, string nodeName,
            string attributeString)
        {
            var xmlDocument = new XmlDocument();
            if (xmlType == XmlType.File)
                xmlDocument.Load(source);
            else
                xmlDocument.LoadXml(source);
            var documentElement = xmlDocument.DocumentElement;
            var selectSingleNode = (XmlElement)documentElement?.SelectSingleNode("//" + nodeName);
            //if (selectSingleNode != null)
            return selectSingleNode?.GetAttribute(attributeString);
        }

        /// <summary>
        ///     读取XML资源中的指定节点内容
        /// </summary>
        /// <param name="source">XML资源</param>
        /// <param name="nodeName">节点名称</param>
        /// <returns>节点内容</returns>
        public static string GetNodeValue(string source, string nodeName)
        {
            if (source == null || nodeName == null || source == "" || nodeName == "" ||
                source.Length < nodeName.Length * 2)
                return null;
            var start = source.IndexOf("<" + nodeName + ">", StringComparison.Ordinal) + nodeName.Length + 2;
            var end = source.IndexOf("</" + nodeName + ">", StringComparison.Ordinal);
            if (start == -1 || end == -1)
                return null;
            return start >= end ? null : source.Substring(start, end - start);
        }


        /// <summary>
        ///     读取XML资源到DataTable中
        /// </summary>
        /// <param name="source">XML资源,文件为路径,否则为XML字符串</param>
        /// <param name="xmlType">XML资源类型:文件,字符串</param>
        /// <param name="tableName">表名称</param>
        /// <returns>DataTable</returns>
        public static DataTable GetTable(string source, XmlType xmlType, string tableName)
        {
            try
            {
                var dataSet = new DataSet();
                if (xmlType == XmlType.File)
                {
                    dataSet.ReadXml(source);
                }
                else
                {
                    var xmlDocument = new XmlDocument();
                    xmlDocument.LoadXml(source);
                    var xmlNodeReader = new XmlNodeReader(xmlDocument);
                    dataSet.ReadXml(xmlNodeReader);
                }
                return dataSet.Tables[tableName];
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     读取XML资源中指定的DataTable的指定行指定列的值
        /// </summary>
        /// <param name="source">XML资源</param>
        /// <param name="xmlType">XML资源类型:文件,字符串</param>
        /// <param name="tableName">表名</param>
        /// <param name="rowIndex">行号</param>
        /// <param name="colName">列名</param>
        /// <returns>值,不存在时返回Null</returns>
        public static object GetTableCell(string source, XmlType xmlType, string tableName, int rowIndex, string colName)
        {
            try
            {
                var dataSet = new DataSet();
                if (xmlType == XmlType.File)
                {
                    dataSet.ReadXml(source);
                }
                else
                {
                    var xmlDocument = new XmlDocument();
                    xmlDocument.LoadXml(source);
                    var xmlNodeReader = new XmlNodeReader(xmlDocument);
                    dataSet.ReadXml(xmlNodeReader);
                }
                return dataSet.Tables[tableName].Rows[rowIndex][colName];
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     读取XML资源中指定的DataTable的指定行指定列的值
        /// </summary>
        /// <param name="source">XML资源</param>
        /// <param name="xmlType">XML资源类型:文件,字符串</param>
        /// <param name="tableName">表名</param>
        /// <param name="rowIndex">行号</param>
        /// <param name="colIndex">列号</param>
        /// <returns>值,不存在时返回Null</returns>
        public static object GetTableCell(string source, XmlType xmlType, string tableName, int rowIndex, int colIndex)
        {
            try
            {
                var dataSet = new DataSet();
                if (xmlType == XmlType.File)
                {
                    dataSet.ReadXml(source);
                }
                else
                {
                    var xmlDocument = new XmlDocument();
                    xmlDocument.LoadXml(source);
                    var xmlNodeReader = new XmlNodeReader(xmlDocument);
                    dataSet.ReadXml(xmlNodeReader);
                }
                return dataSet.Tables[tableName].Rows[rowIndex][colIndex];
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     获取一个字符串xml文档中的dataSet
        /// </summary>
        /// <param name="xmlString">含有xml信息的字符串</param>
        /// <param name="dataSet"></param>
        public static void GetXmlValueDataSet(string xmlString, ref DataSet dataSet)
        {
            try
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(xmlString);
                var xmlNodeReader = new XmlNodeReader(xmlDocument);
                dataSet.ReadXml(xmlNodeReader);
                xmlNodeReader.Close();
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     插入数据
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="node">节点</param>
        /// <param name="element">元素名,非空时插入新元素,否则在该元素中插入属性</param>
        /// <param name="attribute">属性名,非空时插入该元素属性值,否则插入元素值</param>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static void Insert(string path, string node, string element, string attribute, string value)
        {
            /**************************************************
            * 使用示列:
            * XmlHelper.Insert(path, "/Node", "Element", "", "Value")
            * XmlHelper.Insert(path, "/Node", "Element", "Attribute", "Value")
            * XmlHelper.Insert(path, "/Node", "", "Attribute", "Value")
            ************************************************/
            try
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.Load(path);
                var selectSingleNode = xmlDocument.SelectSingleNode(node);
                if (element.Equals(""))
                {
                    if (!attribute.Equals(""))
                    {
                        var xmlElement = (XmlElement)selectSingleNode;
                        xmlElement?.SetAttribute(attribute, value);
                    }
                }
                else
                {
                    var xmlElement = xmlDocument.CreateElement(element);
                    if (attribute.Equals(""))
                        xmlElement.InnerText = value;
                    else
                        xmlElement.SetAttribute(attribute, value);
                    selectSingleNode?.AppendChild(xmlElement);
                }
                xmlDocument.Save(path);
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     读取数据
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="node">节点</param>
        /// <param name="attribute">属性名,非空时返回该属性值,否则返回串联值</param>
        /// <returns>string</returns>
        public static string Read(string path, string node, string attribute)
        {
            /**************************************************
             * 使用示列:
             * XmlHelper.Read(path, "/Node", "")
             * XmlHelper.Read(path, "/Node/Element[@Attribute='Name']", "Attribute")
             ************************************************/
            var value = "";
            try
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.Load(path);
                var selectSingleNode = xmlDocument.SelectSingleNode(node);
                value = attribute.Equals("")
                    ? selectSingleNode?.InnerText
                    : selectSingleNode?.Attributes?[attribute].Value;
            }
            catch (Exception exception)
            {
                throw exception;
            }
            return value;
        }

        /// <summary>
        ///     读取xml的节点
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="nodeName">节点名称</param>
        /// <param name="name">属性名称</param>
        /// <returns></returns>
        public static string ReadXml(string path, string nodeName, string name) //读取XML
        {
            try
            {
                var xmlValue = "";
                if (!File.Exists(path))
                    return xmlValue;
                var myFile = new FileStream(path, FileMode.Open); //打开xml文件 
                var xmlTextReader = new XmlTextReader(myFile); //xml文件阅读器 
                while (xmlTextReader.Read())
                    if (xmlTextReader.Name == nodeName)
                    {
                        //获取服务器的地址//获取升级文档的最后一次更新日期 
                        xmlValue = xmlTextReader.GetAttribute(name);
                        break;
                    }
                xmlTextReader.Close();
                myFile.Close();
                return xmlValue;
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     读取xml文件,并将文件序列化为类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path"></param>
        /// <returns></returns>
        public static T ReadXML<T>(string path)
        {
            try
            {
                var reader = new XmlSerializer(typeof(T));
                var file = new StreamReader(path);
                return (T)reader.Deserialize(file);
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     将DataTable写入XML文件中
        /// </summary>
        /// <param name="dataTable">含有数据的DataTable</param>
        /// <param name="filePath">文件路径</param>
        public static void SaveTableToFile(DataTable dataTable, string filePath)
        {
            try
            {
                var dataSet = new DataSet("Config");
                dataSet.Tables.Add(dataTable.Copy());
                dataSet.WriteXml(filePath);
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     将DataTable以指定的根结点名称写入文件
        /// </summary>
        /// <param name="dataTable">含有数据的DataTable</param>
        /// <param name="rootName">根结点名称</param>
        /// <param name="filePath">文件路径</param>
        public static void SaveTableToFile(DataTable dataTable, string rootName, string filePath)
        {
            try
            {
                var dataSet = new DataSet(rootName);
                dataSet.Tables.Add(dataTable.Copy());
                dataSet.WriteXml(filePath);
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     静态扩展
        /// </summary>
        /// <typeparam name="T">需要序列化的对象类型,必须声明[Serializable]特征</typeparam>
        /// <param name="obj">需要序列化的对象</param>
        /// <param name="omitXmlDeclaration">true:省略XML声明;否则为false.默认false,即编写 XML 声明。</param>
        /// <returns></returns>
        public static string SerializeToXmlStr<T>(T obj, bool omitXmlDeclaration)
        {
            try
            {
                return XmlSerialize(obj, omitXmlDeclaration);
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }

        /// <summary>
        ///     修改数据
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="node">节点</param>
        /// <param name="attribute">属性名,非空时修改该节点属性值,否则修改节点值</param>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static void Update(string path, string node, string attribute, string value)
        {
            /**************************************************
             * 使用示列:
             * XmlHelper.Insert(path, "/Node", "", "Value")
             * XmlHelper.Insert(path, "/Node", "Attribute", "Value")
             ************************************************/
            try
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.Load(path);
                var selectSingleNode = xmlDocument.SelectSingleNode(node);
                var xmlElement = (XmlElement)selectSingleNode;
                if (attribute.Equals(""))
                {
                    if (xmlElement != null) xmlElement.InnerText = value;
                }
                else
                {
                    xmlElement?.SetAttribute(attribute, value);
                }
                xmlDocument.Save(path);
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }


        /// <summary>
        ///     更新XML文件中的指定节点内容
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="nodeName">节点名称</param>
        /// <param name="nodeValue">更新内容</param>
        /// <returns>更新是否成功</returns>
        public static bool UpdateNode(string filePath, string nodeName, string nodeValue)
        {
            bool flag;

            var xmlDocument = new XmlDocument();
            xmlDocument.Load(filePath);
            var documentElement = xmlDocument.DocumentElement;
            var selectSingleNode = documentElement?.SelectSingleNode("//" + nodeName);
            if (selectSingleNode != null)
            {
                selectSingleNode.InnerText = nodeValue;
                xmlDocument.Save(filePath);
                flag = true;
            }
            else
            {
                flag = false;
            }
            return flag;
        }


        /// <summary>
        ///     使用DataSet方式更新XML文件节点
        /// </summary>
        /// <param name="filePath">XML文件路径</param>
        /// <param name="tableName">表名称</param>
        /// <param name="rowIndex">行号</param>
        /// <param name="colName">列名</param>
        /// <param name="content">更新值</param>
        /// <returns>更新是否成功</returns>
        public static bool UpdateTableCell(string filePath, string tableName, int rowIndex, string colName,
            string content)
        {
            bool flag;
            var dataSet = new DataSet();
            dataSet.ReadXml(filePath);
            var dataTable = dataSet.Tables[tableName];

            if (dataTable.Rows[rowIndex][colName] != null)
            {
                dataTable.Rows[rowIndex][colName] = content;
                dataSet.WriteXml(filePath);
                flag = true;
            }
            else
            {
                flag = false;
            }
            return flag;
        }


        /// <summary>
        ///     使用DataSet方式更新XML文件节点
        /// </summary>
        /// <param name="filePath">XML文件路径</param>
        /// <param name="tableName">表名称</param>
        /// <param name="rowIndex">行号</param>
        /// <param name="colIndex">列号</param>
        /// <param name="content">更新值</param>
        /// <returns>更新是否成功</returns>
        public static bool UpdateTableCell(string filePath, string tableName, int rowIndex, int colIndex, string content)
        {
            bool flag;

            var dataSet = new DataSet();
            dataSet.ReadXml(filePath);
            var dataTable = dataSet.Tables[tableName];

            if (dataTable.Rows[rowIndex][colIndex] != null)
            {
                dataTable.Rows[rowIndex][colIndex] = content;
                dataSet.WriteXml(filePath);
                flag = true;
            }
            else
            {
                flag = false;
            }
            return flag;
        }


        /// <summary>
        ///     将对象写入XML文件
        /// </summary>
        /// <typeparam name="T">C#对象名</typeparam>
        /// <param name="item">对象实例</param>
        /// <param name="path">路径</param>
        /// <param name="jjdbh">标号</param>
        /// <param name="ends">结束符号(整个xml的路径类似如下:C:\xmltest\201111send.xml,其中path=C:\xmltest,jjdbh=201111,ends=send)</param>
        /// <returns></returns>
        public static string WriteXML<T>(T item, string path, string jjdbh, string ends)
        {
            if (string.IsNullOrEmpty(ends))
                ends = "send";
            var i = 0; //控制写入文件的次数,
            var serializer = new XmlSerializer(item.GetType());
            object[] obj = { path, "\\", jjdbh, ends, ".xml" };
            var xmlPath = string.Concat(obj);
            while (true)
                try
                {
                    var fileStream = File.Create(xmlPath); //用filestream方式创建文件不会出现“文件正在占用中,用File.create”则不行
                    fileStream.Close();
                    TextWriter writer = new StreamWriter(xmlPath, false, Encoding.UTF8);
                    var xmlSerializerNamespaces = new XmlSerializerNamespaces();
                    xmlSerializerNamespaces.Add(string.Empty, string.Empty);
                    serializer.Serialize(writer, item, xmlSerializerNamespaces);
                    writer.Flush();
                    writer.Close();
                    break;
                }
                catch (Exception exception)
                {
                    if (i < 5)
                        i++;
                    else
                    {
                        throw exception;
                    }
                }
            return SerializeToXmlStr(item, true);
        }

        /// <summary>
        ///     使用XmlSerializer反序列化对象
        /// </summary>
        /// <param name="xmlOfObject">需要反序列化的xml字符串</param>
        /// <returns>反序列化后的对象</returns>
        public static T XmlDeserialize<T>(string xmlOfObject) where T : class
        {
            var xmlReader = XmlReader.Create(new StringReader(xmlOfObject), new XmlReaderSettings());
            return (T)new XmlSerializer(typeof(T)).Deserialize(xmlReader);
        }

        /// <summary>
        ///     从文件读取并反序列化为对象 (解决: 多线程或多进程下读写并发问题)
        /// </summary>
        /// <typeparam name="T">返回的对象类型</typeparam>
        /// <param name="path">文件地址</param>
        /// <returns></returns>
        public static T XmlFileDeserialize<T>(string path)
        {
            var bytes = ShareReadFile(path);
            if (bytes.Length < 1) //当文件正在被写入数据时,可能读出为0
                for (var i = 0; i < 5; i++)
                {
                    bytes = ShareReadFile(path); //5次机会,采用这样诡异的做法避免独占文件和文件正在被写入时读出来的数据为0字节的问题。
                    if (bytes.Length > 0) break;
                    Thread.Sleep(50); //悲观情况下总共最多消耗1/4秒,读取文件
                }
            var xmlDocument = new XmlDocument();
            xmlDocument.Load(new MemoryStream(bytes));
            if (xmlDocument.DocumentElement != null)
                return (T)new XmlSerializer(typeof(T)).Deserialize(new XmlNodeReader(xmlDocument.DocumentElement));
            return default(T);
            /*var xmlReaderSettings = new XmlReaderSettings();
            xmlReaderSettings.CloseInput = true;
            using (var xmlReader = XmlReader.Create(path, xmlReaderSettings))
            {
            var obj = (T) new XmlSerializer(typeof(T)).Deserialize(xmlReader);
            return obj;
            }*/
        }


        /// <summary>
        ///     使用XmlSerializer序列化对象
        /// </summary>
        /// <typeparam name="T">需要序列化的对象类型,必须声明[Serializable]特征</typeparam>
        /// <param name="obj">需要序列化的对象</param>
        /// <param name="omitXmlDeclaration">true:省略XML声明;否则为false.默认false,即编写 XML 声明。</param>
        /// <returns>序列化后的字符串</returns>
        public static string XmlSerialize<T>(T obj, bool omitXmlDeclaration)
        {
            /* This property only applies to XmlWriter instances that output text content to a stream; otherwise, this setting is ignored.
            可能很多朋友遇见过 不能转换成Xml不能反序列化成为UTF8XML声明的情况,就是这个原因。
            */
            var xmlSettings = new XmlWriterSettings
            {
                OmitXmlDeclaration = omitXmlDeclaration,
                Encoding = new UTF8Encoding(false)
            };
            var stream = new MemoryStream(); //var writer = new StringWriter();
            var xmlwriter = XmlWriter.Create(stream /*writer*/, xmlSettings);
            //这里如果直接写成:Encoding = Encoding.UTF8 会在生成的xml中加入BOM(Byte-order Mark) 信息(Unicode 字节顺序标记) , 所以new System.Text.UTF8Encoding(false)是最佳方式,省得再做替换的麻烦
            var xmlSerializerNamespaces = new XmlSerializerNamespaces();
            xmlSerializerNamespaces.Add(string.Empty, string.Empty); //在XML序列化时去除默认命名空间xmlns:xsd和xmlns:xsi
            var xmlSerializer = new XmlSerializer(typeof(T));
            xmlSerializer.Serialize(xmlwriter, obj, xmlSerializerNamespaces);

            return Encoding.UTF8.GetString(stream.ToArray()); //writer.ToString();
        }

        /// <summary>
        ///     使用XmlSerializer序列化对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path">文件路径</param>
        /// <param name="obj">需要序列化的对象</param>
        /// <param name="omitXmlDeclaration">true:省略XML声明;否则为false.默认false,即编写 XML 声明。</param>
        /// <param name="removeDefaultNamespace">是否移除默认名称空间(如果对象定义时指定了:XmlRoot(Namespace = "http://www.xxx.com/xsd")则需要传false值进来)</param>
        /// <returns>序列化后的字符串</returns>
        public static void XmlSerialize<T>(string path, T obj, bool omitXmlDeclaration, bool removeDefaultNamespace)
        {
            var xmlWriterSettings = new XmlWriterSettings { OmitXmlDeclaration = omitXmlDeclaration };
            using (var xmlWriter = XmlWriter.Create(path, xmlWriterSettings))
            {
                var xmlSerializerNamespaces = new XmlSerializerNamespaces();
                if (removeDefaultNamespace)
                    xmlSerializerNamespaces.Add(string.Empty, string.Empty); //在XML序列化时去除默认命名空间xmlns:xsd和xmlns:xsi
                var xmlSerializer = new XmlSerializer(typeof(T));
                xmlSerializer.Serialize(xmlWriter, obj, xmlSerializerNamespaces);
            }
        }

        private static byte[] ShareReadFile(string filePath)
        {
            byte[] bytes;
            //避免"正由另一进程使用,因此该进程无法访问此文件"造成异常 共享锁 flieShare必须为ReadWrite,但是如果文件不存在的话,还是会出现异常,所以这里不能吃掉任何异常,但是需要考虑到这些问题
            using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                bytes = new byte[fileStream.Length];
                var numBytesToRead = (int)fileStream.Length;
                var numBytesRead = 0;
                while (numBytesToRead > 0)
                {
                    var bytesRead = fileStream.Read(bytes, numBytesRead, numBytesToRead);
                    if (bytesRead == 0)
                        break;
                    numBytesRead += bytesRead;
                    numBytesToRead -= bytesRead;
                }
            }
            return bytes;
        }

        #endregion
    }
}

package

Install-Package NPOI

NPOIHelper

using NPOI.HPSF;
using NPOI.HSSF.UserModel;
using NPOI.SS.Formula.Eval;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;

namespace Helper
{
    /// <summary>
    /// NPOIHelper
    /// </summary>
    public class NPOIHelper
    {
        /// <summary>
        /// 公司
        /// </summary>
        public static string Company="NPOI";
        /// <summary>
        /// 作者
        /// </summary>
        public static string Author = "作者";
        /// <summary>
        /// 创建程序信息
        /// </summary>
        public static string ApplicationName = "创建程序信息";
        /// <summary>
        /// 最后保存者信息
        /// </summary>
        public static string LastAuthor = "最后保存者信息";
        /// <summary>
        /// 作者信息
        /// </summary>
        public static string Comments = "作者信息";
        /// <summary>
        /// 标题信息
        /// </summary>
        public static string Title = "标题信息";
        /// <summary>
        /// 主题信息
        /// </summary>
        public static string Subject = "主题信息";

        /// <summary>
        /// 创建Excel
        /// </summary>
        /// <returns></returns>
        public static HSSFWorkbook CreateExcel()
        {
            HSSFWorkbook workbook = new HSSFWorkbook();

            #region 右击文件 属性信息
            DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();
            dsi.Company = Company;
            workbook.DocumentSummaryInformation = dsi;
            SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
            si.Author = Author; //填加xls文件作者信息
            si.ApplicationName = ApplicationName; //填加xls文件创建程序信息
            si.LastAuthor = LastAuthor; //填加xls文件最后保存者信息
            si.Comments = Comments; //填加xls文件作者信息
            si.Title = Title; //填加xls文件标题信息
            si.Subject = Subject;//填加文件主题信息

            si.CreateDateTime = DateTime.Now;
            workbook.SummaryInformation = si;
            #endregion
            return workbook;
        }

        #region 从datatable中将数据导出到excel
        /// <summary>
        /// DataTable导出到Excel的MemoryStream
        /// </summary>
        /// <param name="dtSource">源DataTable</param>
        /// <param name="strHeaderText">表头文本</param>
        static MemoryStream ExportDT(DataTable dtSource, string strHeaderText)
        {
            HSSFWorkbook workbook = CreateExcel();
            HSSFSheet sheet = workbook.CreateSheet() as HSSFSheet;

            HSSFCellStyle dateStyle = workbook.CreateCellStyle() as HSSFCellStyle;
            HSSFDataFormat format = workbook.CreateDataFormat() as HSSFDataFormat;
            dateStyle.DataFormat = format.GetFormat("yyyy-mm-dd");

            //取得列宽
            int[] arrColWidth = new int[dtSource.Columns.Count];
            foreach (DataColumn item in dtSource.Columns)
            {
                arrColWidth[item.Ordinal] = Encoding.GetEncoding(936).GetBytes(item.ColumnName.ToString()).Length;
            }
            for (int i = 0; i < dtSource.Rows.Count; i++)
            {
                for (int j = 0; j < dtSource.Columns.Count; j++)
                {
                    int intTemp = Encoding.GetEncoding(936).GetBytes(dtSource.Rows[i][j].ToString()).Length;
                    if (intTemp > arrColWidth[j])
                    {
                        arrColWidth[j] = intTemp;
                    }
                }
            }
            int rowIndex = 0;

            foreach (DataRow row in dtSource.Rows)
            {
                #region 新建表,填充表头,填充列头,样式

                if (rowIndex == 65535 || rowIndex == 0)
                {
                    if (rowIndex != 0)
                    {
                        sheet = workbook.CreateSheet() as HSSFSheet;
                    }

                    #region 表头及样式

                    {
                        HSSFRow headerRow = sheet.CreateRow(0) as HSSFRow;
                        headerRow.HeightInPoints = 25;
                        headerRow.CreateCell(0).SetCellValue(strHeaderText);

                        HSSFCellStyle headStyle = workbook.CreateCellStyle() as HSSFCellStyle;
                        headStyle.Alignment = HorizontalAlignment.Center;
                        HSSFFont font = workbook.CreateFont() as HSSFFont;
                        font.FontHeightInPoints = 20;
                        font.Boldweight = 700;
                        headStyle.SetFont(font);

                        headerRow.GetCell(0).CellStyle = headStyle;

                        sheet.AddMergedRegion( new  Region(0, 0, 0, dtSource.Columns.Count - 1));
                        //headerRow.Dispose();
                    }

                    #endregion


                    #region 列头及样式

                    {
                        HSSFRow headerRow = sheet.CreateRow(1) as HSSFRow;


                        HSSFCellStyle headStyle = workbook.CreateCellStyle() as HSSFCellStyle;
                        headStyle.Alignment = HorizontalAlignment.Center;
                        HSSFFont font = workbook.CreateFont() as HSSFFont;
                        font.FontHeightInPoints = 10;
                        font.Boldweight = 700;
                        headStyle.SetFont(font);


                        foreach (DataColumn column in dtSource.Columns)
                        {
                            headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
                            headerRow.GetCell(column.Ordinal).CellStyle = headStyle;

                            //设置列宽
                            sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1) * 256);

                        }
                        //headerRow.Dispose();
                    }

                    #endregion

                    rowIndex = 2;
                }

                #endregion

                #region 填充内容

                HSSFRow dataRow = sheet.CreateRow(rowIndex) as HSSFRow;
                foreach (DataColumn column in dtSource.Columns)
                {
                    HSSFCell newCell = dataRow.CreateCell(column.Ordinal) as HSSFCell;

                    string drValue = row[column].ToString();

                    switch (column.DataType.ToString())
                    {
                        case "System.String": //字符串类型
                            double result;
                            if (isNumeric(drValue, out result))
                            {

                                double.TryParse(drValue, out result);
                                newCell.SetCellValue(result);
                                break;
                            }
                            else
                            {
                                newCell.SetCellValue(drValue);
                                break;
                            }

                        case "System.DateTime": //日期类型
                            DateTime dateV;
                            DateTime.TryParse(drValue, out dateV);
                            newCell.SetCellValue(dateV);

                            newCell.CellStyle = dateStyle; //格式化显示
                            break;
                        case "System.Boolean": //布尔型
                            bool boolV = false;
                            bool.TryParse(drValue, out boolV);
                            newCell.SetCellValue(boolV);
                            break;
                        case "System.Int16": //整型
                        case "System.Int32":
                        case "System.Int64":
                        case "System.Byte":
                            int intV = 0;
                            int.TryParse(drValue, out intV);
                            newCell.SetCellValue(intV);
                            break;
                        case "System.Decimal": //浮点型
                        case "System.Double":
                            double doubV = 0;
                            double.TryParse(drValue, out doubV);
                            newCell.SetCellValue(doubV);
                            break;
                        case "System.DBNull": //空值处理
                            newCell.SetCellValue("");
                            break;
                        default:
                            newCell.SetCellValue("");
                            break;
                    }

                }

                #endregion

                rowIndex++;
            }
            using (MemoryStream ms = new MemoryStream())
            {
                workbook.Write(ms);
                ms.Flush();
                ms.Position = 0;

                //sheet.Dispose();
                //workbook.Dispose();

                return ms;
            }
        }

        /// <summary>
        /// DataTable导出到Excel的MemoryStream
        /// </summary>
        /// <param name="dtSource">源DataTable</param>
        /// <param name="strHeaderText">表头文本</param>
        static void ExportDTI(DataTable dtSource, string strHeaderText, FileStream fs)
        {
            XSSFWorkbook workbook = new XSSFWorkbook();
            XSSFSheet sheet = workbook.CreateSheet() as XSSFSheet;

            #region 右击文件 属性信息

            //{
            //    DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();
            //    dsi.Company = "http://www.yongfa365.com/";
            //    workbook.DocumentSummaryInformation = dsi;

            //    SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
            //    si.Author = "柳永法"; //填加xls文件作者信息
            //    si.ApplicationName = "NPOI测试程序"; //填加xls文件创建程序信息
            //    si.LastAuthor = "柳永法2"; //填加xls文件最后保存者信息
            //    si.Comments = "说明信息"; //填加xls文件作者信息
            //    si.Title = "NPOI测试"; //填加xls文件标题信息
            //    si.Subject = "NPOI测试Demo"; //填加文件主题信息
            //    si.CreateDateTime = DateTime.Now;
            //    workbook.SummaryInformation = si;
            //}

            #endregion

            XSSFCellStyle dateStyle = workbook.CreateCellStyle() as XSSFCellStyle;
            XSSFDataFormat format = workbook.CreateDataFormat() as XSSFDataFormat;
            dateStyle.DataFormat = format.GetFormat("yyyy-mm-dd");

            //取得列宽
            int[] arrColWidth = new int[dtSource.Columns.Count];
            foreach (DataColumn item in dtSource.Columns)
            {
                arrColWidth[item.Ordinal] = Encoding.GetEncoding(936).GetBytes(item.ColumnName.ToString()).Length;
            }
            for (int i = 0; i < dtSource.Rows.Count; i++)
            {
                for (int j = 0; j < dtSource.Columns.Count; j++)
                {
                    int intTemp = Encoding.GetEncoding(936).GetBytes(dtSource.Rows[i][j].ToString()).Length;
                    if (intTemp > arrColWidth[j])
                    {
                        arrColWidth[j] = intTemp;
                    }
                }
            }
            int rowIndex = 0;

            foreach (DataRow row in dtSource.Rows)
            {
                #region 新建表,填充表头,填充列头,样式

                if (rowIndex == 0)
                {
                    #region 表头及样式
                    //{
                    //    XSSFRow headerRow = sheet.CreateRow(0) as XSSFRow;
                    //    headerRow.HeightInPoints = 25;
                    //    headerRow.CreateCell(0).SetCellValue(strHeaderText);

                    //    XSSFCellStyle headStyle = workbook.CreateCellStyle() as XSSFCellStyle;
                    //    headStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.CENTER;
                    //    XSSFFont font = workbook.CreateFont() as XSSFFont;
                    //    font.FontHeightInPoints = 20;
                    //    font.Boldweight = 700;
                    //    headStyle.SetFont(font);

                    //    headerRow.GetCell(0).CellStyle = headStyle;

                    //    //sheet.AddMergedRegion(new Region(0, 0, 0, dtSource.Columns.Count - 1));
                    //    //headerRow.Dispose();
                    //}

                    #endregion


                    #region 列头及样式

                    {
                        XSSFRow headerRow = sheet.CreateRow(0) as XSSFRow;


                        XSSFCellStyle headStyle = workbook.CreateCellStyle() as XSSFCellStyle;
                        headStyle.Alignment = HorizontalAlignment.Center;
                        XSSFFont font = workbook.CreateFont() as XSSFFont;
                        font.FontHeightInPoints = 10;
                        font.Boldweight = 700;
                        headStyle.SetFont(font);


                        foreach (DataColumn column in dtSource.Columns)
                        {
                            headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
                            headerRow.GetCell(column.Ordinal).CellStyle = headStyle;

                            //设置列宽
                            sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1) * 256);

                        }
                        //headerRow.Dispose();
                    }

                    #endregion

                    rowIndex = 1;
                }

                #endregion

                #region 填充内容

                XSSFRow dataRow = sheet.CreateRow(rowIndex) as XSSFRow;
                foreach (DataColumn column in dtSource.Columns)
                {
                    XSSFCell newCell = dataRow.CreateCell(column.Ordinal) as XSSFCell;

                    string drValue = row[column].ToString();

                    switch (column.DataType.ToString())
                    {
                        case "System.String": //字符串类型
                            double result;
                            if (isNumeric(drValue, out result))
                            {

                                double.TryParse(drValue, out result);
                                newCell.SetCellValue(result);
                                break;
                            }
                            else
                            {
                                newCell.SetCellValue(drValue);
                                break;
                            }

                        case "System.DateTime": //日期类型
                            DateTime dateV;
                            DateTime.TryParse(drValue, out dateV);
                            newCell.SetCellValue(dateV);

                            newCell.CellStyle = dateStyle; //格式化显示
                            break;
                        case "System.Boolean": //布尔型
                            bool boolV = false;
                            bool.TryParse(drValue, out boolV);
                            newCell.SetCellValue(boolV);
                            break;
                        case "System.Int16": //整型
                        case "System.Int32":
                        case "System.Int64":
                        case "System.Byte":
                            int intV = 0;
                            int.TryParse(drValue, out intV);
                            newCell.SetCellValue(intV);
                            break;
                        case "System.Decimal": //浮点型
                        case "System.Double":
                            double doubV = 0;
                            double.TryParse(drValue, out doubV);
                            newCell.SetCellValue(doubV);
                            break;
                        case "System.DBNull": //空值处理
                            newCell.SetCellValue("");
                            break;
                        default:
                            newCell.SetCellValue("");
                            break;
                    }

                }

                #endregion

                rowIndex++;
            }
            workbook.Write(fs);
            fs.Close();
        }

        /// <summary>
        /// DataTable导出到Excel文件
        /// </summary>
        /// <param name="dtSource">源DataTable</param>
        /// <param name="strHeaderText">表头文本</param>
        /// <param name="strFileName">保存位置</param>
        public static void ExportDTtoExcel(DataTable dtSource, string strHeaderText, string strFileName)
        {
            string[] temp = strFileName.Split('.');

            if (temp[temp.Length - 1] == "xls" && dtSource.Columns.Count < 256 && dtSource.Rows.Count < 65536)
            {
                using (MemoryStream ms = ExportDT(dtSource, strHeaderText))
                {
                    using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write))
                    {
                        byte[] data = ms.ToArray();
                        fs.Write(data, 0, data.Length);
                        fs.Flush();
                    }
                }
            }
            else
            {
                if (temp[temp.Length - 1] == "xls")
                    strFileName = strFileName + "x";

                using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write))
                {
                    ExportDTI(dtSource, strHeaderText, fs);
                }
            }
        }
        #endregion

        #region 从excel中将数据导出到datatable
        /// <summary>
        /// 读取excel 默认第一行为标头
        /// </summary>
        /// <param name="strFileName">excel文档路径</param>
        /// <returns></returns>
        public static DataTable ImportExceltoDt(string strFileName)
        {
            DataTable dt = new DataTable();
            IWorkbook wb;
            using (FileStream file = new FileStream(strFileName, FileMode.Open, FileAccess.Read,FileShare.ReadWrite))
            {
                wb = WorkbookFactory.Create(file);
            }
            ISheet sheet = wb.GetSheetAt(0);
            dt = ImportDt(sheet, 0, true);
            return dt;
        }

        /// <summary>
        /// 读取Excel流到DataTable
        /// </summary>
        /// <param name="stream">Excel流</param>
        /// <returns>第一个sheet中的数据</returns>
        public static DataTable ImportExceltoDt(Stream stream)
        {
            try
            {
                DataTable dt = new DataTable();
                IWorkbook wb;
                using (stream)
                {
                    wb = WorkbookFactory.Create(stream);
                }
                ISheet sheet = wb.GetSheetAt(0);
                dt = ImportDt(sheet, 0, true);
                return dt;
            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// 读取Excel流到DataTable
        /// </summary>
        /// <param name="stream">Excel流</param>
        /// <param name="sheetName">表单名</param>
        /// <param name="HeaderRowIndex">列头所在行号,-1表示没有列头</param>
        /// <returns>指定sheet中的数据</returns>
        public static DataTable ImportExceltoDt(Stream stream, string sheetName, int HeaderRowIndex)
        {
            try
            {
                DataTable dt = new DataTable();
                IWorkbook wb;
                using (stream)
                {
                    wb = WorkbookFactory.Create(stream);
                }
                ISheet sheet = wb.GetSheet(sheetName);
                dt = ImportDt(sheet, HeaderRowIndex, true);
                return dt;
            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// 读取Excel流到DataSet
        /// </summary>
        /// <param name="stream">Excel流</param>
        /// <returns>Excel中的数据</returns>
        public static DataSet ImportExceltoDs(Stream stream)
        {
            try
            {
                DataSet ds = new DataSet();
                IWorkbook wb;
                using (stream)
                {
                    wb = WorkbookFactory.Create(stream);
                }
                for (int i = 0; i < wb.NumberOfSheets; i++)
                {
                    DataTable dt = new DataTable();
                    ISheet sheet = wb.GetSheetAt(i);
                    dt = ImportDt(sheet, 0, true);
                    ds.Tables.Add(dt);
                }
                return ds;
            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// 读取Excel流到DataSet
        /// </summary>
        /// <param name="stream">Excel流</param>
        /// <param name="dict">字典参数,key:sheet名,value:列头所在行号,-1表示没有列头</param>
        /// <returns>Excel中的数据</returns>
        public static DataSet ImportExceltoDs(Stream stream, Dictionary<string, int> dict)
        {
            try
            {
                DataSet ds = new DataSet();
                IWorkbook wb;
                using (stream)
                {
                    wb = WorkbookFactory.Create(stream);
                }
                foreach (string key in dict.Keys)
                {
                    DataTable dt = new DataTable();
                    ISheet sheet = wb.GetSheet(key);
                    dt = ImportDt(sheet, dict[key], true);
                    ds.Tables.Add(dt);
                }
                return ds;
            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// 读取excel
        /// </summary>
        /// <param name="strFileName">excel文件路径</param>
        /// <param name="sheet">需要导出的sheet</param>
        /// <param name="HeaderRowIndex">列头所在行号,-1表示没有列头</param>
        /// <returns></returns>
        public static DataTable ImportExceltoDt(string strFileName, string SheetName, int HeaderRowIndex)
        {
            HSSFWorkbook workbook;
            IWorkbook wb;
            using (FileStream file = new FileStream(strFileName, FileMode.Open, FileAccess.Read,FileShare.ReadWrite))
            {
                wb = new HSSFWorkbook(file);
            }
            ISheet sheet = wb.GetSheet(SheetName);
            DataTable table = new DataTable();
            table = ImportDt(sheet, HeaderRowIndex, true);
            //ExcelFileStream.Close();
            workbook = null;
            sheet = null;
            return table;
        }

        /// <summary>
        /// 读取excel
        /// </summary>
        /// <param name="strFileName">excel文件路径</param>
        /// <param name="sheet">需要导出的sheet序号</param>
        /// <param name="HeaderRowIndex">列头所在行号,-1表示没有列头</param>
        /// <returns></returns>
        public static DataTable ImportExceltoDt(string strFileName, int SheetIndex, int HeaderRowIndex)
        {
            HSSFWorkbook workbook;
            IWorkbook wb;
            using (FileStream file = new FileStream(strFileName, FileMode.Open, FileAccess.Read,FileShare.ReadWrite))
            {
                wb = WorkbookFactory.Create(file);
            }
            ISheet isheet = wb.GetSheetAt(SheetIndex);
            DataTable table = new DataTable();
            table = ImportDt(isheet, HeaderRowIndex, true);
            //ExcelFileStream.Close();
            workbook = null;
            isheet = null;
            return table;
        }

        /// <summary>
        /// 读取excel
        /// </summary>
        /// <param name="strFileName">excel文件路径</param>
        /// <param name="sheet">需要导出的sheet</param>
        /// <param name="HeaderRowIndex">列头所在行号,-1表示没有列头</param>
        /// <returns></returns>
        public static DataTable ImportExceltoDt(string strFileName, string SheetName, int HeaderRowIndex, bool needHeader)
        {
            HSSFWorkbook workbook;
            IWorkbook wb;
            using (FileStream file = new FileStream(strFileName, FileMode.Open, FileAccess.Read,FileShare.ReadWrite))
            {
                wb = WorkbookFactory.Create(file);
            }
            ISheet sheet = wb.GetSheet(SheetName);
            DataTable table = new DataTable();
            table = ImportDt(sheet, HeaderRowIndex, needHeader);
            //ExcelFileStream.Close();
            workbook = null;
            sheet = null;
            return table;
        }

        /// <summary>
        /// 读取excel
        /// </summary>
        /// <param name="strFileName">excel文件路径</param>
        /// <param name="sheet">需要导出的sheet序号</param>
        /// <param name="HeaderRowIndex">列头所在行号,-1表示没有列头</param>
        /// <returns></returns>
        public static DataTable ImportExceltoDt(string strFileName, int SheetIndex, int HeaderRowIndex, bool needHeader)
        {
            HSSFWorkbook workbook;
            IWorkbook wb;
            using (FileStream file = new FileStream(strFileName, FileMode.Open, FileAccess.Read,FileShare.ReadWrite))
            {
                wb = WorkbookFactory.Create(file);
            }
            ISheet sheet = wb.GetSheetAt(SheetIndex);
            DataTable table = new DataTable();
            table = ImportDt(sheet, HeaderRowIndex, needHeader);
            //ExcelFileStream.Close();
            workbook = null;
            sheet = null;
            return table;
        }

        /// <summary>
        /// 将制定sheet中的数据导出到datatable中
        /// </summary>
        /// <param name="sheet">需要导出的sheet</param>
        /// <param name="HeaderRowIndex">列头所在行号,-1表示没有列头</param>
        /// <returns></returns>
        static DataTable ImportDt(ISheet sheet, int HeaderRowIndex, bool needHeader)
        {
            DataTable table = new DataTable();
            IRow headerRow;
            int cellCount;
            try
            {
                if (HeaderRowIndex < 0 || !needHeader)
                {
                    headerRow = sheet.GetRow(0);
                    cellCount = headerRow.LastCellNum;

                    for (int i = headerRow.FirstCellNum; i <= cellCount; i++)
                    {
                        DataColumn column = new DataColumn(Convert.ToString(i));
                        table.Columns.Add(column);
                    }
                }
                else
                {
                    headerRow = sheet.GetRow(HeaderRowIndex);
                    cellCount = headerRow.LastCellNum;

                    for (int i = headerRow.FirstCellNum; i <= cellCount; i++)
                    {
                        if (headerRow.GetCell(i) == null)
                        {
                            if (table.Columns.IndexOf(Convert.ToString(i)) > 0)
                            {
                                DataColumn column = new DataColumn(Convert.ToString("重复列名" + i));
                                table.Columns.Add(column);
                            }
                            else
                            {
                                DataColumn column = new DataColumn(Convert.ToString(i));
                                table.Columns.Add(column);
                            }

                        }
                        else if (table.Columns.IndexOf(headerRow.GetCell(i).ToString()) > 0)
                        {
                            DataColumn column = new DataColumn(Convert.ToString("重复列名" + i));
                            table.Columns.Add(column);
                        }
                        else
                        {
                            DataColumn column = new DataColumn(headerRow.GetCell(i).ToString());
                            table.Columns.Add(column);
                        }
                    }
                }
                int rowCount = sheet.LastRowNum;
                for (int i = (HeaderRowIndex + 1); i <= sheet.LastRowNum; i++)
                {
                    try
                    {
                        IRow row;
                        if (sheet.GetRow(i) == null)
                        {
                            row = sheet.CreateRow(i);
                        }
                        else
                        {
                            row = sheet.GetRow(i);
                        }

                        DataRow dataRow = table.NewRow();

                        for (int j = row.FirstCellNum; j <= cellCount; j++)
                        {
                            try
                            {
                                if (row.GetCell(j) != null)
                                {
                                    switch (row.GetCell(j).CellType)
                                    {
                                        case CellType.String:
                                            string str = row.GetCell(j).StringCellValue;
                                            if (str != null && str.Length > 0)
                                            {
                                                dataRow[j] = str.ToString();
                                            }
                                            else
                                            {
                                                dataRow[j] = null;
                                            }
                                            break;
                                        case CellType.Numeric:
                                            if (DateUtil.IsCellDateFormatted(row.GetCell(j)))
                                            {
                                                dataRow[j] = DateTime.FromOADate(row.GetCell(j).NumericCellValue);
                                            }
                                            else
                                            {
                                                dataRow[j] = Convert.ToDouble(row.GetCell(j).NumericCellValue);
                                            }
                                            break;
                                        case CellType.Boolean:
                                            dataRow[j] = Convert.ToString(row.GetCell(j).BooleanCellValue);
                                            break;
                                        case CellType.Error:
                                            dataRow[j] = ErrorEval.GetText(row.GetCell(j).ErrorCellValue);
                                            break;
                                        case CellType.Formula:
                                            switch (row.GetCell(j).CachedFormulaResultType)
                                            {
                                                case CellType.String:
                                                    string strFORMULA = row.GetCell(j).StringCellValue;
                                                    if (strFORMULA != null && strFORMULA.Length > 0)
                                                    {
                                                        dataRow[j] = strFORMULA.ToString();
                                                    }
                                                    else
                                                    {
                                                        dataRow[j] = null;
                                                    }
                                                    break;
                                                case CellType.Numeric:
                                                    dataRow[j] = Convert.ToString(row.GetCell(j).NumericCellValue);
                                                    break;
                                                case CellType.Boolean:
                                                    dataRow[j] = Convert.ToString(row.GetCell(j).BooleanCellValue);
                                                    break;
                                                case CellType.Error:
                                                    dataRow[j] = ErrorEval.GetText(row.GetCell(j).ErrorCellValue);
                                                    break;
                                                default:
                                                    dataRow[j] = "";
                                                    break;
                                            }
                                            break;
                                        default:
                                            dataRow[j] = "";
                                            break;
                                    }
                                }
                            }
                            catch (Exception exception)
                            {
                                //wl.WriteLogs(exception.ToString());
                                throw;
                            }
                        }
                        table.Rows.Add(dataRow);
                    }
                    catch (Exception exception)
                    {
                        //wl.WriteLogs(exception.ToString());
                        throw;
                    }
                }
            }
            catch (Exception exception)
            {
                //wl.WriteLogs(exception.ToString());
                throw;
            }
            return table;
        }

        #endregion


        public static void InsertSheet(string outputFile, string sheetname, DataTable dt)
        {
            FileStream readfile = new FileStream(outputFile, FileMode.Open, FileAccess.Read,FileShare.ReadWrite);
            IWorkbook hssfworkbook = WorkbookFactory.Create(readfile);
            //HSSFWorkbook hssfworkbook = new HSSFWorkbook(readfile);
            int num = hssfworkbook.GetSheetIndex(sheetname);
            ISheet sheet1;
            if (num >= 0)
                sheet1 = hssfworkbook.GetSheet(sheetname);
            else
            {
                sheet1 = hssfworkbook.CreateSheet(sheetname);
            }


            try
            {
                if (sheet1.GetRow(0) == null)
                {
                    sheet1.CreateRow(0);
                }
                for (int coluid = 0; coluid < dt.Columns.Count; coluid++)
                {
                    if (sheet1.GetRow(0).GetCell(coluid) == null)
                    {
                        sheet1.GetRow(0).CreateCell(coluid);
                    }

                    sheet1.GetRow(0).GetCell(coluid).SetCellValue(dt.Columns[coluid].ColumnName);
                }
            }
            catch (Exception ex)
            {
                //wl.WriteLogs(ex.ToString());
                throw;
            }


            for (int i = 1; i <= dt.Rows.Count; i++)
            {
                try
                {
                    if (sheet1.GetRow(i) == null)
                    {
                        sheet1.CreateRow(i);
                    }
                    for (int coluid = 0; coluid < dt.Columns.Count; coluid++)
                    {
                        if (sheet1.GetRow(i).GetCell(coluid) == null)
                        {
                            sheet1.GetRow(i).CreateCell(coluid);
                        }

                        sheet1.GetRow(i).GetCell(coluid).SetCellValue(dt.Rows[i - 1][coluid].ToString());
                    }
                }
                catch (Exception ex)
                {
                    //wl.WriteLogs(ex.ToString());
                    throw;
                }
            }
            try
            {
                readfile.Close();

                FileStream writefile = new FileStream(outputFile, FileMode.OpenOrCreate, FileAccess.Write);
                hssfworkbook.Write(writefile);
                writefile.Close();
            }
            catch (Exception ex)
            {
                //wl.WriteLogs(ex.ToString());
                throw;
            }
        }

        #region 更新excel中的数据
        /// <summary>
        /// 更新Excel表格
        /// </summary>
        /// <param name="outputFile">需更新的excel表格路径</param>
        /// <param name="sheetname">sheet名</param>
        /// <param name="updateData">需更新的数据</param>
        /// <param name="coluid">需更新的列号</param>
        /// <param name="rowid">需更新的开始行号</param>
        public static void UpdateExcel(string outputFile, string sheetname, string[] updateData, int coluid, int rowid)
        {
            //FileStream readfile = new FileStream(outputFile, FileMode.Open, FileAccess.Read,FileShare.ReadWrite);
            IWorkbook hssfworkbook = null;// WorkbookFactory.Create(outputFile);
            //HSSFWorkbook hssfworkbook = new HSSFWorkbook(readfile);
            ISheet sheet1 = hssfworkbook.GetSheet(sheetname);
            for (int i = 0; i < updateData.Length; i++)
            {
                try
                {
                    if (sheet1.GetRow(i + rowid) == null)
                    {
                        sheet1.CreateRow(i + rowid);
                    }
                    if (sheet1.GetRow(i + rowid).GetCell(coluid) == null)
                    {
                        sheet1.GetRow(i + rowid).CreateCell(coluid);
                    }

                    sheet1.GetRow(i + rowid).GetCell(coluid).SetCellValue(updateData[i]);
                }
                catch (Exception ex)
                {
                    //wl.WriteLogs(ex.ToString());
                    throw;
                }
            }
            try
            {
                //readfile.Close();
                FileStream writefile = new FileStream(outputFile, FileMode.OpenOrCreate, FileAccess.Write);
                hssfworkbook.Write(writefile);
                writefile.Close();
            }
            catch (Exception ex)
            {
                //wl.WriteLogs(ex.ToString());
                throw;
            }

        }

        /// <summary>
        /// 更新Excel表格
        /// </summary>
        /// <param name="outputFile">需更新的excel表格路径</param>
        /// <param name="sheetname">sheet名</param>
        /// <param name="updateData">需更新的数据</param>
        /// <param name="coluids">需更新的列号</param>
        /// <param name="rowid">需更新的开始行号</param>
        public static void UpdateExcel(string outputFile, string sheetname, string[][] updateData, int[] coluids, int rowid)
        {
            FileStream readfile = new FileStream(outputFile, FileMode.Open, FileAccess.Read,FileShare.ReadWrite);

            HSSFWorkbook hssfworkbook = new HSSFWorkbook(readfile);
            readfile.Close();
            ISheet sheet1 = hssfworkbook.GetSheet(sheetname);
            for (int j = 0; j < coluids.Length; j++)
            {
                for (int i = 0; i < updateData[j].Length; i++)
                {
                    try
                    {
                        if (sheet1.GetRow(i + rowid) == null)
                        {
                            sheet1.CreateRow(i + rowid);
                        }
                        if (sheet1.GetRow(i + rowid).GetCell(coluids[j]) == null)
                        {
                            sheet1.GetRow(i + rowid).CreateCell(coluids[j]);
                        }
                        sheet1.GetRow(i + rowid).GetCell(coluids[j]).SetCellValue(updateData[j][i]);
                    }
                    catch (Exception ex)
                    {
                        //wl.WriteLogs(ex.ToString());
                        throw;
                    }
                }
            }
            try
            {
                FileStream writefile = new FileStream(outputFile, FileMode.Create);
                hssfworkbook.Write(writefile);
                writefile.Close();
            }
            catch (Exception ex)
            {
                //wl.WriteLogs(ex.ToString());
                throw;
            }
        }

        /// <summary>
        /// 更新Excel表格
        /// </summary>
        /// <param name="outputFile">需更新的excel表格路径</param>
        /// <param name="sheetname">sheet名</param>
        /// <param name="updateData">需更新的数据</param>
        /// <param name="coluid">需更新的列号</param>
        /// <param name="rowid">需更新的开始行号</param>
        public static void UpdateExcel(string outputFile, string sheetname, double[] updateData, int coluid, int rowid)
        {
            FileStream readfile = new FileStream(outputFile, FileMode.Open, FileAccess.Read,FileShare.ReadWrite);

            HSSFWorkbook hssfworkbook = new HSSFWorkbook(readfile);
            ISheet sheet1 = hssfworkbook.GetSheet(sheetname);
            for (int i = 0; i < updateData.Length; i++)
            {
                try
                {
                    if (sheet1.GetRow(i + rowid) == null)
                    {
                        sheet1.CreateRow(i + rowid);
                    }
                    if (sheet1.GetRow(i + rowid).GetCell(coluid) == null)
                    {
                        sheet1.GetRow(i + rowid).CreateCell(coluid);
                    }

                    sheet1.GetRow(i + rowid).GetCell(coluid).SetCellValue(updateData[i]);
                }
                catch (Exception ex)
                {
                    //wl.WriteLogs(ex.ToString());
                    throw;
                }
            }
            try
            {
                readfile.Close();
                FileStream writefile = new FileStream(outputFile, FileMode.Create, FileAccess.Write);
                hssfworkbook.Write(writefile);
                writefile.Close();
            }
            catch (Exception ex)
            {
                //wl.WriteLogs(ex.ToString());
                throw;
            }

        }

        /// <summary>
        /// 更新Excel表格
        /// </summary>
        /// <param name="outputFile">需更新的excel表格路径</param>
        /// <param name="sheetname">sheet名</param>
        /// <param name="updateData">需更新的数据</param>
        /// <param name="coluids">需更新的列号</param>
        /// <param name="rowid">需更新的开始行号</param>
        public static void UpdateExcel(string outputFile, string sheetname, double[][] updateData, int[] coluids, int rowid)
        {
            FileStream readfile = new FileStream(outputFile, FileMode.Open, FileAccess.Read,FileShare.ReadWrite);

            HSSFWorkbook hssfworkbook = new HSSFWorkbook(readfile);
            readfile.Close();
            ISheet sheet1 = hssfworkbook.GetSheet(sheetname);
            for (int j = 0; j < coluids.Length; j++)
            {
                for (int i = 0; i < updateData[j].Length; i++)
                {
                    try
                    {
                        if (sheet1.GetRow(i + rowid) == null)
                        {
                            sheet1.CreateRow(i + rowid);
                        }
                        if (sheet1.GetRow(i + rowid).GetCell(coluids[j]) == null)
                        {
                            sheet1.GetRow(i + rowid).CreateCell(coluids[j]);
                        }
                        sheet1.GetRow(i + rowid).GetCell(coluids[j]).SetCellValue(updateData[j][i]);
                    }
                    catch (Exception ex)
                    {
                        //wl.WriteLogs(ex.ToString());
                        throw;
                    }
                }
            }
            try
            {
                FileStream writefile = new FileStream(outputFile, FileMode.Create);
                hssfworkbook.Write(writefile);
                writefile.Close();
            }
            catch (Exception ex)
            {
                //wl.WriteLogs(ex.ToString());
                throw;
            }
        }

        #endregion
        /// <summary>
        /// 获取工作页的页数
        /// </summary>
        /// <param name="outputFile"></param>
        /// <returns></returns>
        public static int GetSheetNumber(string outputFile)
        {
            int number = 0;
            try
            {
                FileStream readfile = new FileStream(outputFile, FileMode.Open, FileAccess.Read,FileShare.ReadWrite);

                IWorkbook wb = WorkbookFactory.Create(readfile);
                number = wb.NumberOfSheets;

            }
            catch (Exception exception)
            {
                //wl.WriteLogs(exception.ToString());
                throw;
            }
            return number;
        }
        /// <summary>
        /// 获取工作页名称
        /// </summary>
        /// <param name="outputFile"></param>
        /// <returns></returns>
        public static ArrayList GetSheetName(string outputFile)
        {
            ArrayList arrayList = new ArrayList();
            try
            {
                FileStream readfile = new FileStream(outputFile, FileMode.Open, FileAccess.Read,FileShare.ReadWrite);
                IWorkbook wb =WorkbookFactory.Create(readfile);
                for (int i = 0; i < wb.NumberOfSheets; i++)
                {
                    arrayList.Add(wb.GetSheetName(i));
                }
            }
            catch (Exception exception)
            {
                //wl.WriteLogs(exception.ToString());
                throw;
            }
            return arrayList;
        }

        public static bool isNumeric(String message, out double result)
        {
            Regex rex = new Regex(@"^[-]?\d+[.]?\d*$");
            result = -1;
            if (rex.IsMatch(message))
            {
                result = double.Parse(message);
                return true;
            }
            else
                return false;

        }



        //////////  现用导出  \\\\\\\\\\  
        /// <summary>
        /// 用于Web导出                                                                                             第一步
        /// </summary>
        /// <param name="dtSource">源DataTable</param>
        /// <param name="strHeaderText">表头文本</param>
        /// <param name="strFileName">文件名</param>
        public static void ExportByWeb(DataTable dtSource, string strHeaderText, string strFileName)
        {
            HttpContext curContext = HttpContext.Current;

            // 设置编码和附件格式
            curContext.Response.ContentType = "application/vnd.ms-excel";
            curContext.Response.ContentEncoding = Encoding.UTF8;
            curContext.Response.Charset = "";
            curContext.Response.AppendHeader("Content-Disposition",
            "attachment;filename=" + HttpUtility.UrlEncode(strFileName, Encoding.UTF8));

            curContext.Response.BinaryWrite(Export(dtSource, strHeaderText).GetBuffer());
            curContext.Response.End();
        }



        /// <summary>
        /// DataTable导出到Excel的MemoryStream                                                                      第二步
        /// </summary>
        /// <param name="dtSource">源DataTable</param>
        /// <param name="strHeaderText">表头文本</param>
        public static MemoryStream Export(DataTable dtSource, string strHeaderText)
        {
            HSSFWorkbook workbook = new HSSFWorkbook();
            HSSFSheet sheet = workbook.CreateSheet() as HSSFSheet;

            #region 右击文件 属性信息
            {
                DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();
                dsi.Company = "NPOI";
                workbook.DocumentSummaryInformation = dsi;

                SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
                si.Author = "文件作者信息"; //填加xls文件作者信息
                si.ApplicationName = "创建程序信息"; //填加xls文件创建程序信息
                si.LastAuthor = "最后保存者信息"; //填加xls文件最后保存者信息
                si.Comments = "作者信息"; //填加xls文件作者信息
                si.Title = "标题信息"; //填加xls文件标题信息
                si.Subject = "主题信息";//填加文件主题信息

                si.CreateDateTime = DateTime.Now;
                workbook.SummaryInformation = si;
            }
            #endregion

            HSSFCellStyle dateStyle = workbook.CreateCellStyle() as HSSFCellStyle;
            HSSFDataFormat format = workbook.CreateDataFormat() as HSSFDataFormat;
            dateStyle.DataFormat = format.GetFormat("yyyy-mm-dd");

            //取得列宽
            int[] arrColWidth = new int[dtSource.Columns.Count];
            foreach (DataColumn item in dtSource.Columns)
            {
                arrColWidth[item.Ordinal] = Encoding.GetEncoding(936).GetBytes(item.ColumnName.ToString()).Length;
            }
            for (int i = 0; i < dtSource.Rows.Count; i++)
            {
                for (int j = 0; j < dtSource.Columns.Count; j++)
                {
                    int intTemp = Encoding.GetEncoding(936).GetBytes(dtSource.Rows[i][j].ToString()).Length;
                    if (intTemp > arrColWidth[j])
                    {
                        arrColWidth[j] = intTemp;
                    }
                }
            }
            int rowIndex = 0;
            foreach (DataRow row in dtSource.Rows)
            {
                #region 新建表,填充表头,填充列头,样式
                if (rowIndex == 65535 || rowIndex == 0)
                {
                    if (rowIndex != 0)
                    {
                        sheet = workbook.CreateSheet() as HSSFSheet;
                    }

                    #region 表头及样式
                    {
                        if (string.IsNullOrEmpty(strHeaderText))
                        {
                            HSSFRow headerRow = sheet.CreateRow(0) as HSSFRow;
                            headerRow.HeightInPoints = 25;
                            headerRow.CreateCell(0).SetCellValue(strHeaderText);
                            HSSFCellStyle headStyle = workbook.CreateCellStyle() as HSSFCellStyle;
                            //headStyle.Alignment = CellHorizontalAlignment.CENTER;
                            HSSFFont font = workbook.CreateFont() as HSSFFont;
                            font.FontHeightInPoints = 20;
                            font.Boldweight = 700;
                            headStyle.SetFont(font);
                            headerRow.GetCell(0).CellStyle = headStyle;
                            sheet.AddMergedRegion(new Region(0, 0, 0, dtSource.Columns.Count - 1));
                            //headerRow.Dispose();
                        }
                    }
                    #endregion

                    #region 列头及样式
                    {
                        HSSFRow headerRow = sheet.CreateRow(0) as HSSFRow;
                        HSSFCellStyle headStyle = workbook.CreateCellStyle() as HSSFCellStyle;
                        //headStyle.Alignment = CellHorizontalAlignment.CENTER;
                        HSSFFont font = workbook.CreateFont() as HSSFFont;
                        font.FontHeightInPoints = 10;
                        font.Boldweight = 700;
                        headStyle.SetFont(font);
                        foreach (DataColumn column in dtSource.Columns)
                        {
                            headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
                            headerRow.GetCell(column.Ordinal).CellStyle = headStyle;

                            //设置列宽
                            sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1) * 256);
                        }
                        //headerRow.Dispose();
                    }
                    #endregion

                    rowIndex = 1;
                }
                #endregion


                #region 填充内容
                HSSFRow dataRow = sheet.CreateRow(rowIndex) as HSSFRow;
                foreach (DataColumn column in dtSource.Columns)
                {
                    HSSFCell newCell = dataRow.CreateCell(column.Ordinal) as HSSFCell;

                    string drValue = row[column].ToString();

                    switch (column.DataType.ToString())
                    {
                        case "System.String"://字符串类型
                            newCell.SetCellValue(drValue);
                            break;
                        case "System.DateTime"://日期类型
                            DateTime dateV;
                            DateTime.TryParse(drValue, out dateV);
                            newCell.SetCellValue(dateV);

                            newCell.CellStyle = dateStyle;//格式化显示
                            break;
                        case "System.Boolean"://布尔型
                            bool boolV = false;
                            bool.TryParse(drValue, out boolV);
                            newCell.SetCellValue(boolV);
                            break;
                        case "System.Int16"://整型
                        case "System.Int32":
                        case "System.Int64":
                        case "System.Byte":
                            int intV = 0;
                            int.TryParse(drValue, out intV);
                            newCell.SetCellValue(intV);
                            break;
                        case "System.Decimal"://浮点型
                        case "System.Double":
                            double doubV = 0;
                            double.TryParse(drValue, out doubV);
                            newCell.SetCellValue(doubV);
                            break;
                        case "System.DBNull"://空值处理
                            newCell.SetCellValue("");
                            break;
                        default:
                            newCell.SetCellValue("");
                            break;
                    }
                }
                #endregion

                rowIndex++;
            }
            using (MemoryStream ms = new MemoryStream())
            {
                workbook.Write(ms);
                ms.Flush();
                ms.Position = 0;

                //sheet.Dispose();
                //workbook.Dispose();//一般只用写这一个就OK了,他会遍历并释放所有资源,但当前版本有问题所以只释放sheet
                return ms;
            }
        }

        /// <summary>
        /// /注:分浏览器进行编码(IE必须编码,FireFox不能编码,Chrome可编码也可不编码)
        /// </summary>
        /// <param name="ds"></param>
        /// <param name="strHeaderText"></param>
        /// <param name="strFileName"></param>
        public static void ExportByWeb(DataSet ds, string strHeaderText, string strFileName)
        {
            HttpContext curContext = HttpContext.Current;
            curContext.Response.ContentType = "application/vnd.ms-excel";
            curContext.Response.Charset = "";
            if (curContext.Request.UserAgent.ToLower().IndexOf("firefox", System.StringComparison.Ordinal) > 0)
            {
                curContext.Response.AppendHeader("Content-Disposition", "attachment;filename=" + strFileName);
            }
            else
            {
                curContext.Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(strFileName, System.Text.Encoding.UTF8));
            }

            //  curContext.Response.AppendHeader("Content-Disposition", "attachment;filename=" +strFileName);
            curContext.Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");
            curContext.Response.BinaryWrite(ExportDataSetToExcel(ds, strHeaderText).GetBuffer());
            curContext.Response.End();
        }

        /// <summary>
        /// 由DataSet导出Excel
        /// </summary>
        /// <param name="sourceTable">要导出数据的DataTable</param>
        /// <param name="sheetName">工作表名称</param>
        /// <returns>Excel工作表</returns>
        private static MemoryStream ExportDataSetToExcel(DataSet sourceDs, string sheetName)
        {
            HSSFWorkbook workbook = new HSSFWorkbook();
            MemoryStream ms = new MemoryStream();
            string[] sheetNames = sheetName.Split(',');
            for (int i = 0; i < sheetNames.Length; i++)
            {
                ISheet sheet = workbook.CreateSheet(sheetNames[i]);

                #region 列头
                IRow headerRow = sheet.CreateRow(0);
                HSSFCellStyle headStyle = workbook.CreateCellStyle() as HSSFCellStyle;
                HSSFFont font = workbook.CreateFont() as HSSFFont;
                font.FontHeightInPoints = 10;
                font.Boldweight = 700;
                headStyle.SetFont(font);

                //取得列宽
                int[] arrColWidth = new int[sourceDs.Tables[i].Columns.Count];
                foreach (DataColumn item in sourceDs.Tables[i].Columns)
                {
                    arrColWidth[item.Ordinal] = Encoding.GetEncoding(936).GetBytes(item.ColumnName.ToString()).Length;
                }

                // 处理列头
                foreach (DataColumn column in sourceDs.Tables[i].Columns)
                {
                    headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
                    headerRow.GetCell(column.Ordinal).CellStyle = headStyle;
                    //设置列宽
                    sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1) * 256);

                }
                #endregion

                #region 填充值
                int rowIndex = 1;
                foreach (DataRow row in sourceDs.Tables[i].Rows)
                {
                    IRow dataRow = sheet.CreateRow(rowIndex);
                    foreach (DataColumn column in sourceDs.Tables[i].Columns)
                    {
                        dataRow.CreateCell(column.Ordinal).SetCellValue(row[column].ToString());
                    }
                    rowIndex++;
                }
                #endregion
            }
            workbook.Write(ms);
            ms.Flush();
            ms.Position = 0;
            workbook = null;
            return ms;
        }


        /// <summary>
        /// 验证导入的Excel是否有数据
        /// </summary>
        /// <param name="excelFileStream"></param>
        /// <returns></returns>
        public static bool HasData(Stream excelFileStream)
        {
            using (excelFileStream)
            {
                IWorkbook workBook = new HSSFWorkbook(excelFileStream);
                if (workBook.NumberOfSheets > 0)
                {
                    ISheet sheet = workBook.GetSheetAt(0);
                    return sheet.PhysicalNumberOfRows > 0;
                }
            }
            return false;
        }
        
    }
}