将 Suprema Biostar C++ 代码转换为 C#

Posted

技术标签:

【中文标题】将 Suprema Biostar C++ 代码转换为 C#【英文标题】:Converting Suprema Biostar C++ code to C# 【发布时间】:2015-02-03 07:39:46 【问题描述】:

我从 Suprema 那里得到了 Biostation T2,他们提供了一个用 C# 制作的包装 Dll,他们还提供了使用的示例:VB6、VB.net、C++ 和 C#。大部分文档都是用 C++ 编写的,我很难尝试将该逻辑转换为 C#。我无法使用粘贴中的以下函数注册用户。主要是因为我不确定 C# 和 C++ 中的逻辑是否匹配。

查看C++ code for enrolling user and my C# attempt 馅饼

我在尝试读取或写入此处捕获的受保护内存时出错

这里是他们提供的 sdk 示例的链接sdk samples in vc,c#,C++

【问题讨论】:

请尝试为您的 p/invoke 问题创建一个Minimal, Complete, and Verifiable example。我们无法用您发布的内容复制此内容。 @dbc 我的问题是 C++ 代码对 C# 代码的解释是否正确匹配?让我试着把它编辑一个档次。 【参考方案1】:

我们无法使用您向我们展示的内容编译和测试您的代码。话虽如此,将 c++ 和 c# 并排比较,我发现以下不一致之处:

    c++代码如下:

    unsigned char* templateBuf = (unsigned char*)malloc( userHeader.numOfFinger * 2 * BS_TEMPLATE_SIZE );
    int bufPos = 0;
    for( int i = 0; i < userHeader.numOfFinger * 2; i++ )
    
        result = BS_ScanTemplate( handle, templateBuf + bufPos );
        bufPos += BS_TEMPLATE_SIZE;
    
    

    此代码多次调用BS_ScanTemplate,并将结果顺序存储在一个字节数组中。您的代码执行以下操作:

        byte[] templateBuf = new byte[userHdr.numOfFinger * 2 * BS_TEMPLATE_SIZE];
        int bufPos = 0;
        for (int i = 0; i < userHdr.numOfFinger * 2; i++)
        
            templateBuf = new byte[userHdr.numOfFinger * 2 * BS_TEMPLATE_SIZE * bufPos];
            result = BSSDK.BS_ScanTemplate(m_Handle, templateBuf);
            bufPos += BS_TEMPLATE_SIZE;
        
    

    此代码不是按顺序存储BS_ScanTemplate 的结果,而是通过重新分配数组来丢弃之前每次调用的结果。也许你想要这样的东西:

        byte[] templateBuf = new byte[userHdr.numOfFinger * 2 * BS_TEMPLATE_SIZE];
        for (int i = 0, bufPos = 0; i < userHdr.numOfFinger * 2; i++)
        
            byte[] singleBuf = new byte[BS_TEMPLATE_SIZE];
            result = BSSDK.BS_ScanTemplate(m_Handle, singleBuf);
            Array.Copy(singleBuf, 0, templateBuf, bufPos, singleBuf.Length);
            bufPos += singleBuf.Length;
        
    

    c++ 代码可以

    for( int i = 0; i < userHeader.numOfFinger; i++ )
    
        userHeader.duress[i] = 0; // no duress finger
    
    

    c#代码是这样的:

        userHdr.duressMask = 0; // no duress finger
    

    这完全不同。

    c++ 代码是这样的:

    for( int i = 0; i < userHeader.numOfFinger * 2; i++ )
    
        if( i % 2 == 0 )
        
            userHeader.fingerChecksum[i/2] = 0;
        
        unsigned char* templateData = templateBuf + i * BS_TEMPLATE_SIZE;
        for( int j = 0; j < BS_TEMPLATE_SIZE; j++ )
        
            userHeader.fingerChecksum[i/2] += templateData[j];
        
    
    

    c#代码是这样的:

        for (int i = 0; i < userHdr.numOfFinger * 2; i++)
        
            if (i % 2 == 0)
            
                userHdr.checksum[i / 2] = 0;
            
            byte[] templateData = templateBuf;
            for (int j = 0; j < 2000 - 1; j++)
            
                userHdr.checksum[i / 2] += templateData[j];
            
        
    

    如您所见,c++ 代码的循环次数是 c# 代码的两倍。 c#代码大概应该是:

        for (int i = 0; i < userHdr.numOfFinger; i++)
        
            if (i % 2 == 0)
            
                userHdr.checksum[i / 2] = 0;
            
            for (int j = 0; j < BS_TEMPLATE_SIZE; j++)
            
                userHdr.checksum[i / 2] += templateBuf[i * BS_TEMPLATE_SIZE + j];
            
        
    

    您没有在 pastie 中显示对 BS_EnrollUserBioStation2 的 c++ 调用,因此无法与 c# 调用进行比较。

    userHdr.checksum = new ushort[] 0 ; 看起来不对。不应该是userHdr.checksum = new ushort[userHdr.numOfFinger];

因此我建议如下:

更新BSUserHdrEx如下:

    public const int BS_MAX_NAME_LEN = 32;
    public const int BS_MAX_PASSWORD_LEN = 16;

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct BSUserHdrEx
    
        public static BSUserHdrEx CreateDefaultBSUserHdrEx()
        
            var userHdr = new BSUserHdrEx();
            userHdr.name = new byte[BSSDK.BS_MAX_NAME_LEN + 1];
            userHdr.department = new byte[BSSDK.BS_MAX_NAME_LEN + 1];
            userHdr.password = new byte[BSSDK.BS_MAX_PASSWORD_LEN];
            userHdr.checksum = new ushort[5];
            return userHdr;
        

        public uint ID;
        public ushort reserved1;
        public ushort adminLevel;
        public ushort securityLevel;
        public ushort statusMask; // internally used by BioStation
        public uint accessGroupMask;

        //char name[BS_MAX_NAME_LEN + 1];
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = BSSDK.BS_MAX_NAME_LEN + 1)]
        public byte[] name;

        //char department[BS_MAX_NAME_LEN + 1];
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = BSSDK.BS_MAX_NAME_LEN + 1)]
        public byte[] department;

        // char password[BS_MAX_PASSWORD_LEN + 1];
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = BSSDK.BS_MAX_PASSWORD_LEN + 1)]
        public byte[] password;

        public ushort numOfFinger;
        public ushort duressMask;

        //public ushort checksum[5];
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
        public ushort[] checksum;

        public ushort authMode;
        public ushort authLimitCount; // 0 for no limit
        public ushort reserved;
        public ushort timedAntiPassback; // in minutes. 0 for no limit
        public uint cardID; // 0 for not used
        public bool bypassCard;
        public bool disabled;
        public uint expireDateTime;
        public uint customID; //card Custom ID
        public int version; // card Info Version
        public uint startDateTime;
    ;

更新btngetUserInfo_Click如下:

    private void btngetUserInfo_Click(object sender, EventArgs e)
    
        int result;

        BSSDK.BSUserHdrEx userHdr = BSSDK.BSUserHdrEx.CreateDefaultBSUserHdrEx();
        userHdr.ID = 2; // 0 cannot be assigned as a user ID
        userHdr.startDateTime = 0; // no check for start date
        userHdr.expireDateTime = 0; // no check for expiry date
        userHdr.adminLevel = BSSDK.BS_USER_NORMAL;
        userHdr.securityLevel = BSSDK.BS_USER_SECURITY_DEFAULT;
        userHdr.authMode = BSSDK.BS_AUTH_MODE_DISABLED; // use the authentication mode of the device
        userHdr.accessGroupMask = 0xffff0201; // a member of Group 1 and Group 2;
        Encoding.UTF8.GetBytes("Madman").CopyTo(userHdr.name, 0);
        Encoding.UTF8.GetBytes("INC").CopyTo(userHdr.department, 0);
        Encoding.UTF8.GetBytes("").CopyTo(userHdr.password, 0);
        userHdr.password = Encoding.UTF8.GetBytes("");  // no password is enrolled. Password should be longer than 4 bytes.
        userHdr.numOfFinger = 2;
        byte[] templateBuf = new byte[userHdr.numOfFinger * 2 * BSSDK.BS_TEMPLATE_SIZE];
        for (int i = 0, bufPos = 0; i < userHdr.numOfFinger * 2; i++)
        
            byte[] singleBuf = new byte[BSSDK.BS_TEMPLATE_SIZE];
            result = BSSDK.BS_ScanTemplate(m_Handle, singleBuf);
            Array.Copy(singleBuf, 0, templateBuf, bufPos, singleBuf.Length);
            bufPos += singleBuf.Length;
        
        userHdr.duressMask = 0; // no duress finger

        for (int i = 0; i < userHdr.numOfFinger * 2; i++)
        
            if (i % 2 == 0)
            
                userHdr.checksum[i / 2] = 0;
            
            // byte[] templateData = templateBuf;
            for (int j = 0; j < BSSDK.BS_TEMPLATE_SIZE; j++)
            
                userHdr.checksum[i / 2] += templateBuf[i * BSSDK.BS_TEMPLATE_SIZE + j];
            
        

        // enroll the user
        result = BSSDK.BS_EnrollUserBioStation2(m_Handle, ref userHdr, templateBuf);
        if (result == (int)BSSDK.BS_RET_CODE.BS_SUCCESS)
        
            MessageBox.Show("user " + userHdr.name.ToString() + " enrolled");
        

更新

你正在编组的结构是BSUserHdrExBS_EnrollUserBioStation2 不将此作为论据。 BS_EnrollUserBioStation2BS2UserHdr 作为参数(来源:“BioStar SDK Manual V1.8.pdf”的第 158 页。)BSUserHdrExBS_EnrollUserEx 的参数。 (第 129 页)。

BS_EnrollUserEx "将用户注册到 BioStation。每个用户最多可以注册 5 根手指。" BS_EnrollUserBioStation2 "将用户注册到 BioStation T2。每个用户最多 10 根手指。"

要么你需要切换到前一个函数,要么使用后一个数据结构。

【讨论】:

非常感谢您的分析我忘了添加最后一行以注册用户,但我现在已经更新了馅饼。让我尝试进行更改。 @Gotalove - 答案已更新。如果没有看到 c++ BS2UserHdr 类,我就无能为力了。 @Gotalove - 在 c++ 中有 faceTemplateBuf 传递给 BS_EnrollUserBioStation2,这在 c# 代码中甚至不存在。

以上是关于将 Suprema Biostar C++ 代码转换为 C#的主要内容,如果未能解决你的问题,请参考以下文章

C++ 数组转数字

[转] Matlab与C++混合编程(依赖OpenCV)

关于C++ const 的全面总结《转》

LeetCode剑指 Offer 58 - II. 左旋转字符串(C++)

c++矩阵的转置和快速转置

Visual Studio C++ 项目转到定义打开对象浏览器而不是转到源代码