[WIN API][WinSCard] - Stuck on an easy thing (Win Api Types and QString)



  • Hi everybody,

    My question may be obvious for some of you but i'm stuck on an easy issue i guess.
    So i ask for someone help me.

    I'm trying to use winscard lib from windows SDK
    I have no probel to link it and compile.

    My problem is after usung SCardEstablishContext i try to call SCardListReaders() that gives a list of reades available.
    Here is my problems i'm stuck with f*** microsoft api type and maybe unicode.

    I don't know how to get the content of "mszReaders" variable.
    Here is my code :

    .pro

    #-------------------------------------------------
    #
    # Project created by QtCreator 2017-09-04T18:17:36
    #
    #-------------------------------------------------
    
    QT       += core gui
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = SCL011_Reader
    TEMPLATE = app
    
    # The following define makes your compiler emit warnings if you use
    # any feature of Qt which as been marked as deprecated (the exact warnings
    # depend on your compiler). Please consult the documentation of the
    # deprecated API in order to know how to port your code away from it.
    DEFINES += QT_DEPRECATED_WARNINGS
    
    # You can also make your code fail to compile if you use deprecated APIs.
    # In order to do so, uncomment the following line.
    # You can also select to disable deprecated APIs only up to a certain version of Qt.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    
    INCLUDEPATH += "$$PWD/libs"
    LIBS += -L"$$PWD/libs" -lMCSCM
    LIBS += -L"D:/MicrosoftSDK/Lib/10.0.15063.0/um/x86/" -lwinscard
    
    #DEPENDPATH += "D:/MicrosoftSDK/Lib/10.0.15063.0/um/x86/"
    
    SOURCES += \
            main.cpp \
            mainwindow.cpp
    
    HEADERS += \
            mainwindow.h
    
    FORMS += \
            mainwindow.ui
    
    

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QDebug>
    #include "qt_windows.h"
    #include "winnt.h"
    
    
    #include "winscard.h"
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
    };
    
    #endif // MAINWINDOW_H
    
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        SCARDCONTEXT cardContext;
        wchar_t *mszReaders;
        DWORD dwReaders;
    
    
        SCardEstablishContext(SCARD_SCOPE_USER,NULL,NULL,&cardContext);
        dwReaders = SCARD_AUTOALLOCATE;
        SCardListReadersW(cardContext,NULL,mszReaders,&dwReaders);
    
        QByteArray buffer;
        wchar_t *it = mszReaders;
    
        while(*it++)
        {
            buffer.append(QChar(*it));
        }
       qDebug()<<buffer;
    
    
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    

    Output of qDebug()<<buffer

    \xE6\x94\x80\xE7\x88\x80\xE6\xB8\x80\xE6\x8C\x80\xE6\xBC\x80\xE7\x88\x80\xE6\x94\x80\xE2\xB4\x80\xE7\x9C\x80\xE6\xA4\x80\xE6\xB8\x80\xE3\x8C\x80\xE3\x88\x80\xE6\xAC\x80\xE2\xB4\x80\xE6\x88\x80\xE6\x84\x80\xE7\x8C\x80\xE6\x94\x80\xE2\xB4\x80\xE6\xB8\x80\xE7\x90\x80\xE7\x94\x80\xE7\x8C\x80\xE6\x94\x80\xE7\x88\x80\xE2\xB4\x80\xE6\xB0\x80\xE3\x84\x80\xE2\xB4\x80\xE3\x84\x80\xE2\xB4\x80\xE3\x80\x80\x0
    

    Hope this clear, thanks in advance.
    Have a nice day


  • Lifetime Qt Champion

    Hi,

    Are you looking for QString:: fromWCharArray ?



  • Hi, using SCARD_AUTOALLOCATE is tricky, because Windows then tries to return the pointer to the mszReaders variable, and without an "&" prefix your buffer will contain only gibberish :-(
    Try something like this:

    SCARDCONTEXT cardContext;
    LPTSTR mszReaders = NULL;
    DWORD dwReaders;
    
    SCardEstablishContext(SCARD_SCOPE_USER,NULL,NULL,&cardContext);
    dwReaders = SCARD_AUTOALLOCATE;
    SCardListReadersW(cardContext,NULL,(LPTSTR)&mszReaders,&dwReaders);
    
    QByteArray buffer;
    wchar_t *it = mszReaders;
    
    while (*it)
    {
        while(*it)
            buffer.append(QChar(*it++));
    
        qDebug() << buffer;
        buffer.clear();
        ++it;
    }
    
    

    Also your loop had a bug I think so it will throw away/skip the first char of the readers' name.

    P.S. You'll need a double loop to pick up more than one card reader name. Note: haven't tested the code!



  • @hskoglund

    I update my code and it works but i don't understand the tricks about passing a casted referenced variable

    For who interest

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        SCARDCONTEXT cardContext;
        LPWSTR mszReaders;
        DWORD dwReaders;
    
    
        SCardEstablishContext(SCARD_SCOPE_USER,NULL,NULL,&cardContext);
        dwReaders = SCARD_AUTOALLOCATE;
        SCardListReadersW(cardContext,NULL,(LPWSTR)&mszReaders,&dwReaders);
    
        QByteArray buffer;
        wchar_t *it = mszReaders;
    
        while(*it !='\0')
        {
            buffer.append(QChar(*it));
            *it++;
        }
       qDebug()<<buffer;
    
    
    }
    


  • @NicoFrom13 Why the trick? If you look at the API documentation it says that mszReaders is a pointer to a buffer which you allocate, i.e. you hand over a buffer pointer (LPWSTR) to Windows which then fills it with the card reader name(s).

    But then someone had a bright idea at Microsoft and decided that this wasn't enough and that Windows could give you a helping hand by allocating the buffer for you. This option you select by using SCARD_AUTOALLOCATE. Problem is that the API is already documented and fixed/not changeable. So that's why you have to give Windows a pointer to your pointer, so that it can return the actual pointer to you, but in order to conform the API and make the compiler happy you have to use the cast (not to a reference but a to pointer BTW).

    P.S. Note, with your code you'll only see the name of the first card reader. To see names of additional reader(s) you'll need the double loop.



  • @hskoglund Thank you for your feedback

    I moved forward on my project and i have one more question.
    Could somebody explain me this ?

    When i switch the two unsigned char "receive" and "command" declaration line, i haven't the same result

    in the actual code below all things work i get all information as writen in the TAG.
    If i move up the command declaration above the receive declaration, all things messed up

    I think it's an problem about C++ understanding, sorry i'm beginner.

    here is the code

        unsigned long proto=0;
        const wchar_t rdName[] = L"SCM Microsystems Inc. SCL011G Contactless Reader 0";
    
        QByteArray *myBuffer=new QByteArray();
        resConnect = SCardConnectW(cardContext,rdName,SCARD_SHARE_SHARED,SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,&cardHandle,&proto);
        qDebug()<<QString("Connect : %1").arg(resConnect,0,16);
    
    
        unsigned char receive[4] = {0,0,0,0};
        unsigned char command[] = {0xFF,0xB0,0x00,0x01,0x04};
    
        SCARD_IO_REQUEST *senpci = new SCARD_IO_REQUEST;
        senpci->cbPciLength = sizeof(SCARD_IO_REQUEST);
        senpci->dwProtocol = SCARD_PROTOCOL_T1;
    
    
        DWORD rcvLen;
    
        for (int i(1); i<28; i++)
        {
            resConnect = SCardTransmit(cardHandle,senpci,command,sizeof(command),NULL,receive,&rcvLen);
            myBuffer->append((char*)receive,4);
            command[3]=i;
        }
    
        qDebug()<<*myBuffer;
        SCardDisconnect(cardHandle,SCARD_LEAVE_CARD);
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.