将 Suprema Biostar C++ 代码转换为 C#
Converting Suprema Biostar C++ code to C#
我从 Suprema 那里得到了 Biostation T2,他们提供了一个用 C# 制作的包装 Dll,他们还提供了使用 VB6、VB.net、C++ 和 C# 的示例。大部分文档都是 C++ 的,我有很难尝试将该逻辑转换为 C#。我无法在 pastie.Mainly 中使用以下函数注册用户,因为我不确定 C# 和 C++ 中的逻辑是否匹配。
查看 C++ code for enrolling user and my C# attempt 馅饼
我在尝试读取或写入受保护内存时遇到错误,如此处捕获
这是他们提供的 link 个 SDK 示例 sdk samples in vc,c#,C++
我们无法使用您向我们展示的内容编译和测试您的代码。话虽这么说,并排比较 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");
}
更新
您正在编组的结构是 BSUserHdrEx
。 BS_EnrollUserBioStation2
不以此为论据。 BS_EnrollUserBioStation2
将 BS2UserHdr
作为参数(来源:"BioStar SDK Manual V1.8.pdf" 第 158 页)。BSUserHdrEx
是 BS_EnrollUserEx
的参数。 (第 129 页)。
BS_EnrollUserEx
"Enrolls a user to BioStation. Maximum 5 fingers can be enrolled per user."
BS_EnrollUserBioStation2
"Enrolls a user to BioStation T2. Maximum 10 fingers per user."
要么改用前一个函数,要么使用后一个数据结构
我从 Suprema 那里得到了 Biostation T2,他们提供了一个用 C# 制作的包装 Dll,他们还提供了使用 VB6、VB.net、C++ 和 C# 的示例。大部分文档都是 C++ 的,我有很难尝试将该逻辑转换为 C#。我无法在 pastie.Mainly 中使用以下函数注册用户,因为我不确定 C# 和 C++ 中的逻辑是否匹配。
查看 C++ code for enrolling user and my C# attempt 馅饼
我在尝试读取或写入受保护内存时遇到错误,如此处捕获
这是他们提供的 link 个 SDK 示例 sdk samples in vc,c#,C++
我们无法使用您向我们展示的内容编译和测试您的代码。话虽这么说,并排比较 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");
}
更新
您正在编组的结构是 BSUserHdrEx
。 BS_EnrollUserBioStation2
不以此为论据。 BS_EnrollUserBioStation2
将 BS2UserHdr
作为参数(来源:"BioStar SDK Manual V1.8.pdf" 第 158 页)。BSUserHdrEx
是 BS_EnrollUserEx
的参数。 (第 129 页)。
BS_EnrollUserEx
"Enrolls a user to BioStation. Maximum 5 fingers can be enrolled per user."BS_EnrollUserBioStation2
"Enrolls a user to BioStation T2. Maximum 10 fingers per user."
要么改用前一个函数,要么使用后一个数据结构