Reputation: 31
I have been trying to use a VB DLL supplied with a Contactless mifare Card reader, in C#, however there's a problem passing a variable type. The original code is:
READER_API int __stdcall RDR_LoginToSector(UCHAR Sector, UCHAR KeyType, unsigned char * KEY);
The UCHAR can be used as "uint" or "byte" without problems, however the "unsigned char *" is not working
I have tried calling it as various types:
[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);
I also tried with the "ref" statement without success.
In all of the methods the return is 3 which means Login Failure. I double checked the Key using an Android app I was working and could log correctly, also the compiled source that comes with it also works with this key.
All methods that does not require "unsigned char * " work properly, like those to verify the type of the card, opening the COM port and such.
Any ideas?
Thank you everyone.
Upvotes: 3
Views: 543
Reputation: 613013
The correct way to declare this is:
[DllImport("SmartReader.dll", CallingConvention = CallingConvention.Stdcall)]
public static extern int RDR_LoginToSector(
byte Sector,
byte KeyType,
[In] byte[] Key
);
This declaration matches the native declaration that you provided. Your attempts used the wrong calling convention, and the final parameter should be byte[]
. In fact, you could even omit the CallingConvention
because Stdcall
is the default. However, it does not hurt to be explicit. Likewise, the [In]
could be omitted but again being explicit is wise.
The error indicated by the return value therefore means that you are passing incorrect parameters. It's hard for us to debug the parameters that you pass since we do not know the specifics of this function.
So, what I am trying to say is that if you use the p/invoke above, you can remove interop from the list of possible failure modes. In fact, to be completely sure of that you should write a test program in C++ that calls the function successfully. That way you can debug the parameters you use without having the worry at the back of your mind that it is the interop that is causing the problem.
Upvotes: 1
Reputation: 5414
As your C function is declared __stdcall
, you should use the matching calling convention: CallingConvention.StdCall
.
The Unicode Charset isn't helping you any. I think you want to use the byte array for the last parameter (aka, Key) and bytes for the first two parameters. (Your third example in looks right other than the calling convention and the unnecessary Charset.)
You might also verify the byte order of your data in the byte array. I'm not sure how it is used in other areas.
Upvotes: 0