我一直在尝试使用C#中的非接触式mifare读卡器提供的VB DLL,但是传递变量类型时出现问题。原始代码是:
READER_API int __stdcall RDR_LoginToSector(UCHAR Sector, UCHAR KeyType, unsigned char * KEY);
UCHAR可以毫无问题地用作“uint”或“byte”,但是“unsigned char *”无法正常工作
我尝试将其称为各种类型:
[DllImport("SmartReader.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern int RDR_LoginToSector(byte Sector, byte KeyType, IntPtr KEY);
byte[] D = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
IntPtr F = new IntPtr();
F = Marshal.AllocHGlobal(Marshal.SizeOf(D));
Logged = RDR_LoginToSector((byte) 0x01, (byte)0x60, F);
[DllImport("SmartReader.dll", CallingConvention = CallingConvention.Cdecl] public static extern int RDR_LoginToSector(byte Sector, byte KeyType, StringBuilder KEY);
StringBuilder E = new StringBuilder(6);
E.Append((byte)0xff);
E.Append((byte)0xff);
E.Append((byte)0xff);
E.Append((byte)0xff);
E.Append((byte)0xff);
E.Append((byte)0xff);
Logged = RDR_LoginToSector((byte) 0x01, (byte)0x60, E);
[DllImport("SmartReader.dll", CharSet = CharSet.Unicode)] public static extern int RDR_LoginToSector(byte Sector, byte KeyType, byte[] KEY);
byte[] D = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
Logged = RDR_LoginToSector((byte) 0x01, (byte)0x60, D);
[DllImport("SmartReader.dll", CharSet = CharSet.Unicode)] public static extern int RDR_LoginToSector(byte Sector, byte KeyType, char[] KEY);
char[] C = { (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff, (char)0xff };
Logged = RDR_LoginToSector((byte) 0x01, (byte)0x60, C);
我也试过“ref”声明但没有成功。
在所有方法中,返回值为3表示登录失败。我使用我正在工作的Android应用程序仔细检查了密钥,并且可以正确记录,也可以使用它附带的已编译源代码。
所有不需要“unsigned char *”的方法都能正常工作,例如验证卡类型,打开COM端口等的方法。
有什么想法吗?
谢谢大家。
答案 0 :(得分:1)
声明这个的正确方法是:
[DllImport("SmartReader.dll", CallingConvention = CallingConvention.Stdcall)]
public static extern int RDR_LoginToSector(
byte Sector,
byte KeyType,
[In] byte[] Key
);
此声明与您提供的本机声明匹配。您的尝试使用了错误的调用约定,最终参数应为byte[]
。实际上,您甚至可以省略CallingConvention
,因为Stdcall
是默认值。但是,要明确这一点并不会有害。同样,[In]
可以省略,但再次明确是明智的。
因此返回值指示的错误意味着您传递的参数不正确。我们很难调试你传递的参数,因为我们不知道这个函数的细节。
所以,我想说的是,如果你使用上面的p / invoke,你可以从可能的失败模式列表中删除interop。事实上,要完全确定你应该用C ++编写一个成功调用函数的测试程序。这样你就可以调试你使用的参数,而不必担心它会导致问题的互操作。
答案 1 :(得分:0)
当您的C函数声明为__stdcall
时,您应该使用匹配的调用约定:CallingConvention.StdCall
。
Unicode Charset对您没有任何帮助。我想你想使用字节数组作为前两个参数的最后一个参数(aka,Key)和字节。 (除了调用约定和不必要的Charset之外,你的第三个例子看起来正确。)
您还可以验证字节数组中数据的字节顺序。我不确定它是如何在其他领域使用的。