Преобразование кода Suprema Biostar C++ в C#

Я получил Biostation T2 от Suprema, они предоставили упакованный Dll, сделанный на C#, они также предоставляют пример с использованием: VB6, VB.net, C++ и C#. Большая часть документации находится на C++, и я с трудом пытаюсь преобразовать это логика для C#. Я не могу зарегистрировать пользователя, используя перечисленные ниже функции в pastie. В основном, я не уверен, что логика в C# и C++ совпадает.

Смотрите код C++ для регистрации пользователя и мою попытку C# pastie

Я получил ошибку при попытке чтения или записи в защищенную память

Вот ссылка на примеры sdk, которые они предоставляют sdk-образцы в vc, C#, C++

1 ответ

Решение

У нас нет возможности компилировать и тестировать ваш код с помощью того, что вы нам показали. При этом, сравнивая C++ и C# бок о бок, я вижу следующие несоответствия:

  1. 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;
        }
    
  2. Код C++ делает

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

    Код C# делает:

        userHdr.duressMask = 0; // no duress finger
    

    Это совершенно другое.

  3. Код 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];
            }
        }
    
  4. Вы не показываете вызов C++ BS_EnrollUserBioStation2 в твоих руках, так что это нельзя сравнить с вызовом C#.

  5. 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");
        }

Обновить

Структура, которую вы используете BSUserHdrEx, BS_EnrollUserBioStation2 не принимает это в качестве аргумента. BS_EnrollUserBioStation2 занимает BS2UserHdr в качестве аргумента (источник: стр. 158 "Руководства BioStar SDK V1.8.pdf".) BSUserHdrEx это аргумент BS_EnrollUserEx, (Стр. 129).

  • BS_EnrollUserEx "Зарегистрирует пользователя в BioStation. Максимум 5 пальцев могут быть зарегистрированы на пользователя".
  • BS_EnrollUserBioStation2 "Зарегистрирует пользователя в BioStation T2. ​​Максимум 10 пальцев на пользователя".

Либо вам нужно переключиться на первую функцию, либо использовать последнюю структуру данных.

Другие вопросы по тегам