tags:

views:

587

answers:

5

Hi, I'm trying to use an API under Delphi. Here's the API documentation

OKERR ENTRY SCardCLMifareStdAuthent 
    (IN SCARDHANDLE ulHandleCard,IN ULONG ulMifareBlockNr,
    IN UCHAR ucMifareAuthMode,IN UCHAR ucMifareAccessType,IN UCHAR ucMifareKeyNr,
    IN PUCHAR pucMifareKey,IN ULONG ulMifareKeyLen);

Whereas pucMifareKey: A pointer to the six byte Mifare key. The code i've been trying so far;

function Auth():Integer;
type
  TSCardCLMifareStdAuthent = function(SCARDHANDLE: cardinal; ulMifareBlockNr: ULONG;
   ucMifareAuthMode, ucMifareAccessType, ucMifareKeyNr: byte; pucMifareKey: puchar;
   ulMifareKeyLen: cardinal):LONG;
var
  SCardCLMifareStdAuthent: TSCardCLMifareStdAuthent;
  hDLL: Integer;
  CardHandle: cardinal;
  i: integer;
  Key: array of UCHAR;
begin
  Result:=1;
  //CardHandle is defined here
  SetLength(Key, 6);
  for i := low(key) to high(key) do
    Key[i] := $FF;
  hDLL := LoadLibrary('scardsyn.dll');
  @SCardCLMifareStdAuthent := GetProcAddress(hDLL, 'SCardCLMifareStdAuthent');
  if @SCardCLMifareStdAuthent <> nil then
    Result:=SCardCLMifareStdAuthent(CardHandle, $00, 96, 0, 0, ^Key, 6);
  FreeLibrary(hDLL);
end;

The error i'm getting is Incompatible types: 'Byte' and 'Char' at the line of Result:=SCardCL.... due ^Key pointer. Any ideas?

+1  A: 

You wouldn't happen to be in Delphi 2009? If so, "char" is defined as 2 bytes. Try "AnsiChar" instead.

Mason Wheeler
No, I'm using Delphi 7 right now.
Ertugrul Tamer Kara
+2  A: 
type
  TSCardCLMifareStdAuthent = function(SCARDHANDLE: cardinal; ulMifareBlockNr: ULONG;
    ucMifareAuthMode, ucMifareAccessType, ucMifareKeyNr: byte; pucMifareKey: puchar;
    ulMifareKeyLen: cardinal):LONG;

I think you should replace 'byte' with 'UCHAR':

ucMifareAuthMode, ucMifareAccessType, ucMifareKeyNr: byte;

It is a bad practice to treat 'byte' as a 'char'.

Nick D
Thanks for advice, that part is fixed now. But I'm still getting error on pointer variable.
Ertugrul Tamer Kara
As long as this is pre Delphi 2009 there is no difference between using char or byte.
mghie
+1  A: 

Try this:

  1. Introduce new type for array of UCHAR.
  2. Introduce new local variable of pointer type.
  3. Set this variable to be pointer to your Key array
  4. Use this pointer in function call

    type 
      TArrayOfUchar = array of UCHAR;
    
    
    var 
      ...
      Key  : TArrayOfUchar;
      PKey : ^TArrayOfUchar; 
    begin
      ...
      PKey = @Key;
      if @SCardCLMifareStdAuthent <> nil then
        Result:=SCardCLMifareStdAuthent(CardHandle, $00, 96, 0, 0, PKey, 6);
    
zendar
It gives `incompatible types: char and pointer` error at `Pkey:=^Key;` line.
Ertugrul Tamer Kara
Sorry. You are both right. Code was not tested and had some stupid mistakes. I think(hope) that edited version is correct.
zendar
+1  A: 

I don't know the DLL in question, but for a Delphi pre 2009 I would do the following:

function Auth: integer;
type
  TSCardCLMifareStdAuthent = function(SCARDHANDLE: cardinal;
    ulMifareBlockNr: ULONG; ucMifareAuthMode, ucMifareAccessType,
    ucMifareKeyNr: byte; pucMifareKey: PAnsiChar;
    ulMifareKeyLen: Cardinal): longint;
var
  SCardCLMifareStdAuthent: TSCardCLMifareStdAuthent;
  hDLL: Integer;
  CardHandle: Cardinal;
  Key: string;
begin
  Result := 1;
  //CardHandle is defined here...
  Key := StringOfChar(Chr($FF), 6);
  hDLL := LoadLibrary('scardsyn.dll');
  if hDLL <> 0 then begin
    @SCardCLMifareStdAuthent := GetProcAddress(hDLL, 'SCardCLMifareStdAuthent');
    if @SCardCLMifareStdAuthent <> nil then begin
      Result := SCardCLMifareStdAuthent(CardHandle, $00, 96, 0, 0,
        PChar(Key), Length(Key));
    end;
    FreeLibrary(hDLL);
  end;
end;

The access violation you get probably comes from the C string not being 0-terminated. Using a string and casting it to PChar will make things easier.

mghie
Thank you. The new function seems to work better, although now it gives `application defined exception` - which I think caused from DLL due CardHandle. I'll test and post results later on.
Ertugrul Tamer Kara
I'd say it is still missing the calling convention - maybe appending "stdcall;" to the function declaration does help? It is the most probable, although "cdecl;" is also possible; you should check the API documentation for details.
mghie
The API documentation should also tell you whether the key is more like a sequence of chars or a sequence of 8 bit integer numbers - I assumed the former, but if the latter is true using PChar isn't really correct, and you should instead declare a custom type for it instead and make pucMifareKey a pointer to that type.
mghie
That did it, thank you.
Ertugrul Tamer Kara
+1  A: 

You stated that the key is a 6 byte (uchar) array. You are declaring a dynamic array to pass along, why not just declare an array?

var
  {...}
  MyKey: array[0..5] of UCHAR;
begin
  {...}
  Result:=SCardCLMifareStdAuthent(CardHandle, $00, 96, 0, 0, @MyKey, 6);
The_Fox