• Welcome to Theos PowerBasic Museum 2017.

SCardListReaders pointer response

Started by Dan Gin zel, November 06, 2010, 01:16:08 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Dan Gin zel

Greetings!

Well, I'm digging into another new area (at least for me) and really could use a bit of assistance understanding how to translate an example to PowerBasic.

First, the function is SCardListReaders in WinSCard.dll and for who Jose has provided the following definition for PowerBasic:


DECLARE FUNCTION SCardListReaders LIB "WINSCARD.DLL" ALIAS "SCardListReadersA" ( _        
  BYVAL hContext AS DWORD _                            ' __in    SCARDCONTEXT hContext
, BYREF mszGroups AS ASCIIZ _                          ' __in    LPCSTR mszGroups
, BYREF mszReaders AS ASCIIZ _                         ' __out   LPSTR mszReaders
, BYREF pcchReaders AS DWORD _                         ' __inout LPDWORD pcchReaders
) AS LONG                                              ' LONG


Specifically, I can provide the hContext and mscGroups as returned from SCardListReaderGroups and call SCardListReaders here and I get returned in mscReaders the name of the first reader. The problem is that each reader is really two parts and I need the name of the second part.

In MSDN at http://msdn.microsoft.com/en-us/library/aa379793%28v=VS.85%29.aspx, the example shows how to get multiple items from mscReaders, but I am having difficulty understanding what they are doing in this block:


       // Do something with the multi string of readers.
       // Output the values.
       // A double-null terminates the list of values.
       pReader = pmszReaders;
       while ( '\0' != *pReader )
       {
           // Display the value.
           printf("Reader: %S\n", pReader );
           // Advance to the next value.
           pReader = pReader + wcslen((wchar_t *)pReader) + 1;
       }
       // Free the memory.
       lReturn2 = SCardFreeMemory( hSC,
                                  pmszReaders );
       if ( SCARD_S_SUCCESS != lReturn2 )
           printf("Failed SCardFreeMemory\n");
       break;


I was just curious if anyone could help me understand what is going on here. It looks like the response is a pointer to a sequence of strings but I can only see one of the strings and am not sure out to step through them in PowerBasic.

Thanks a bunch !

Dan

[SIZE="1"]www.thecomputerarchive.com  Preserving the history of companies that advanced the computer revolution[/SIZE]

José Roca

 
What they are doing in that block is to extract asciiz strings from a double null terminated list of asciiz strings.


'LPTSTR          pmszReaders = NULL;
'LPTSTR          pReader;
'LONG            lReturn, lReturn2;
'DWORD           cch = SCARD_AUTOALLOCATE;

LOCAL pmszReaders AS ASCIIZ PTR
LOCAL pReader AS ASCIIZ PTR
LOCAL lReturn, lReturn2 AS LONG
LOCAL cch AS DWORD

cch = %SCARD_AUTOALLOCATE

'// Retrieve the list the readers.
'// hSC was set by a previous call to SCardEstablishContext.
'lReturn = SCardListReaders(hSC,
'                           NULL,
'                           (LPTSTR)&pmszReaders,
'                           &cch );

lReturn = SCardListReaders(hSC, _
                           BYVAL %NULL, _
                           BYVAL VARPTR(pmszReaders), _
                           cch)

'switch( lReturn )
'{
SELECT CASE lReturn
'    case SCARD_E_NO_READERS_AVAILABLE:
'        printf("Reader is not in groups.\n");
'        // Take appropriate action.
'        // ...
'        break;

    CASE %SCARD_E_NO_READERS_AVAILABLE
        ? "Reader is not in groups."
'        // Take appropriate action.
'        // ...

'    case SCARD_S_SUCCESS:
'        // Do something with the multi string of readers.
'        // Output the values.
'        // A double-null terminates the list of values.
'        pReader = pmszReaders;
'        while ( '\0' != *pReader )
'        {
'            // Display the value.
'            printf("Reader: %S\n", pReader );
'            // Advance to the next value.
'            pReader = pReader + wcslen((wchar_t *)pReader) + 1;
'        }
'        // Free the memory.
'        lReturn2 = SCardFreeMemory( hSC,
'                                   pmszReaders );
'        if ( SCARD_S_SUCCESS != lReturn2 )
'            printf("Failed SCardFreeMemory\n");
'        break;

    CASE %SCARD_S_SUCCESS
'        // Do something with the multi string of readers.
'        // Output the values.
'        // A double-null terminates the list of values.
        pReader = pmszReaders
        DO
            IF @pReader = $NUL THEN EXIT DO
'            // Display the value.
            ? "Reader: %S\n", @pReader
'            // Advance to the next value.
            pReader = pReader + LEN(@pReader) + 1
        LOOP
       
'        // Free the memory.
'        lReturn2 = SCardFreeMemory( hSC,
'                                   pmszReaders );
'        if ( SCARD_S_SUCCESS != lReturn2 )
'            printf("Failed SCardFreeMemory\n");
'        break;

        lReturn2 = SCardFreeMemory(hSC, _
                                   pmszReaders)
        IF %SCARD_S_SUCCESS <> lReturn2 THEN
            ? "Failed SCardFreeMemory"
        END IF

'default:
'        printf("Failed SCardListReaders\n");
'        // Take appropriate action.
'        // ...
'        break;
'}

       CASE ELSE
'        printf("Failed SCardListReaders\n");
'        // Take appropriate action.
'        // ...


Dan Gin zel

That's what it looked like but I kept hitting a wall with ASCIIZ strings terminating at the first NUL. What is the correct way to handle ASCIIZ strings with embedded NULLs that I want to keep? If I pass the string, only up to the first NUL is passed.

So, here's what I did and you tell me if I did it right or wrong:

I make the following declaration:

DECLARE FUNCTION SCardListReaders2 LIB "WINSCARD.DLL" ALIAS "SCardListReadersA" ( _
   BYVAL hContext AS DWORD _                            ' __in    SCARDCONTEXT hContext
, BYREF mszGroups AS ASCIIZ _                          ' __in    LPCSTR mszGroups
, BYVAL mszReaders AS DWORD _                         ' __out   LPSTR mszReaders
, BYREF pcchReaders AS DWORD _                         ' __inout LPDWORD pcchReaders
) AS LONG                                              ' LONG


and called it with

static hSC as dword
static szgroups as asciiz * 1024
local buffer as string
local pbuffer as string ptr
local readers as dword
static szreaders as ascii * 1024

buffer = space$(1024)
pbuffer = strptr(buffer)
readers = 1024
result = SCardListReaders2 (hSC, szgroups, pbuffer, readers)


That way I just passed a pointer to a string and now buffer correctly contains the two expected values "text1 NUL text2 NULL NULL".

WOW! Revelation! This is why the W (unicode) versions call it that way!!!

(Contemplating...  for i = 1 to 10 : i = 3 : next)

Okay, I've converted to the W versions and most of it seems to be working, so I guess for future-proofing, this would be better than using the version that I presented above. (Unless you say otherwise.) At least I learned something!

José, one again, thanks you for the kick start. I really do appreciate it.

Dan
[SIZE="1"]www.thecomputerarchive.com  Preserving the history of companies that advanced the computer revolution[/SIZE]

José Roca

The way to extract the returned strings is:


       DO
           IF @pReader = $NUL THEN EXIT DO
'            // Display the value.
           ? "Reader: %S\n", @pReader
'            // Advance to the next value.
           pReader = pReader + LEN(@pReader) + 1
       LOOP


Quote
What is the correct way to handle ASCIIZ strings with embedded NULLs that I want to keep? If I pass the string, only up to the first NUL is passed.

As you can't use with PB an asciiz string with embedded nulls, then you can use an string and pass a pointer to the data, i.e. BYVAL STRPTR(myString). You can also use a fixed length string and pass BYVAL VARPTR(myFixexLengthString).

Using the BYVAL override, you don't need to change the declare.