【问题标题】:Error with "Unsigned Char * " in DLL imported on C#在 C# 上导入的 DLL 中出现“Unsigned Char *”错误
【发布时间】:2013-12-09 14:23:14
【问题描述】:

我一直在尝试在 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端口等等。

有什么想法吗?

谢谢大家。

【问题讨论】:

  • 1) 字符串以 null 结尾(包括 +1 字符)。 2)字符串是Unicode! E.追加((字节)0xff);不会做你所期望的(你所有的例子都是如此。像你的第一个例子一样使用 System.Byte (但在末尾添加一个空终止符“0”)。
  • @Adriano mabye 一些代码会有所帮助
  • @MauricioGracia 我有点忙,所以我才发表评论!

标签: c# pinvoke


【解决方案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,您可以从可能的故障模式列表中删除互操作。实际上,要完全确定您应该用 C++ 编写一个成功调用该函数的测试程序。这样您就可以调试您使用的参数,而不必担心是互操作导致了问题。

【讨论】:

  • 对不起,参数应该是0x00到0x0f到Sector的范围,KeyType为0x60为KeyA,0x61为KeyB,Key本身由6个字节组成。谢谢,我会尽快测试并返回。
  • 我尝试过但没有成功,可能是错误的 DLL,但是在 C++ 中它可以工作。我联系了供应商,他们说会发送串行命令来访问阅读器,所以我会制作自己的库。
  • 如果您展示了有效的 C++ 调用代码,我们很可能会发现不匹配
【解决方案2】:

由于您的 C 函数声明为 __stdcall,您应该使用匹配的调用约定:CallingConvention.StdCall

Unicode 字符集对您没有任何帮助。我认为您想将字节数组用于最后一个参数(又名 Key),将字节用于前两个参数。 (除了调用约定和不必要的字符集之外,您的第三个示例看起来正确。)

您还可以验证字节数组中数据的字节顺序。我不确定它在其他领域是如何使用的。

【讨论】:

    猜你喜欢
    • 2021-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多