Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version
Go to top

An UMDF Driver for a Virtual Smart Card Reader

, 30 Jan 2014
A simple implementation of a driver for a virtual smart card reader, based on UMDF
BixVReader.zip
exports.def
Win7_x64
WinXP_x86
Win7_x86
Win7
WinXP
BixVReader.inx
makefile
sources
BixVReader.inx
makefile
sources
BixVReader.dll
BixVReader.inf
BixVReader.dll
BixVReader.inf
BixVReader.dll
BixVReader.inf
#include "internal.h"
#include "VirtualSCReader.h"
#include "queue.h"
#include "device.h"
#include "driver.h"
#include <stdio.h>
#include <winscard.h>
#include "memory.h"
#include "SectionLocker.h"

HRESULT
CMyDevice::CreateInstance(
                          __in IWDFDriver *FxDriver,
                          __in IWDFDeviceInitialize * FxDeviceInit
                          )

                          /*++

                          Routine Description:

                          This method creates and initializs an instance of the virtual smart card reader driver's 
                          device callback object.

                          Arguments:

                          FxDeviceInit - the settings for the device.

                          Device - a location to store the referenced pointer to the device object.

                          Return Value:

                          Status

                          --*/
{
    inFunc
        SectionLogger a(__FUNCTION__);
    CComObject<CMyDevice>* device = NULL;
    HRESULT hr;

    OutputDebugString(L"[BixVReader]CreateInstance");    //
    // Allocate a new instance of the device class.
    //
    hr = CComObject<CMyDevice>::CreateInstance(&device);

    if (device==NULL)
    {
        return E_OUTOFMEMORY;
    }

    //
    // Initialize the instance.
    //
    device->AddRef();

    OutputDebugString(L"[BixVReader]SetLockingConstraint");    //
    FxDeviceInit->SetLockingConstraint(WdfDeviceLevel);

    CComPtr<IUnknown> spCallback;
    OutputDebugString(L"[BixVReader]QueryInterface");    //
    hr = device->QueryInterface(IID_IUnknown, (void**)&spCallback);

    CComPtr<IWDFDevice> spIWDFDevice;
    if (SUCCEEDED(hr))
    {
        OutputDebugString(L"[BixVReader]CreateDevice");    //
        hr = FxDriver->CreateDevice(FxDeviceInit, spCallback, &spIWDFDevice);
    }

    device->numInstances=GetPrivateProfileInt(L"Driver",L"NumReaders",1,L"BixVReader.ini");	

    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        OutputDebugString(L"[BixVReader]Error at WSAStartup()\n");
    }

    for (int i=0;i<device->numInstances;i++) {
        OutputDebugString(L"[BixVReader]CreateDeviceInterface");    //
        wchar_t name[10];
        swprintf(name,L"DEV%i",i);

        if (spIWDFDevice->CreateDeviceInterface(&SmartCardReaderGuid,name)!=0)	
            OutputDebugString(L"[BixVReader]CreateDeviceInterface Failed");
    }

    SAFE_RELEASE(device);	
    return hr;
}

void CMyDevice::ProcessIoControl(__in IWDFIoQueue*     pQueue,
                                 __in IWDFIoRequest*   pRequest,
                                 __in ULONG            ControlCode,
                                 SIZE_T           inBufSize,
                                 SIZE_T           outBufSize)
{
    inFunc
        SectionLogger a(__FUNCTION__);
    UNREFERENCED_PARAMETER(pQueue);
    wchar_t log[300];
    swprintf(log,L"[BixVReader][IOCT]IOCTL %08X - In %i Out %i",ControlCode,inBufSize,outBufSize);
    OutputDebugString(log);

    //SectionLocker lock(m_RequestLock);
    int instance=0;
    {	
        CComPtr<IWDFFile>   pFileObject;
        pRequest->GetFileObject(&pFileObject);

        if (pFileObject != NULL)
        {
            DWORD logLen=300;
            pFileObject->RetrieveFileName(log,&logLen);
            instance=_wtoi(log+(logLen-2));
        }
    }
    Reader &reader=*readers[instance];

    if (ControlCode==IOCTL_SMARTCARD_GET_ATTRIBUTE) {
        reader.IoSmartCardGetAttribute(pRequest,inBufSize,outBufSize);
        return;
    }
    else if (ControlCode==IOCTL_SMARTCARD_IS_PRESENT) {
        reader.IoSmartCardIsPresent(pRequest,inBufSize,outBufSize);
        return;
    }
    else if (ControlCode==IOCTL_SMARTCARD_GET_STATE) {
        reader.IoSmartCardGetState(pRequest,inBufSize,outBufSize);
        return;
    }
    else if (ControlCode==IOCTL_SMARTCARD_IS_ABSENT) {
        reader.IoSmartCardIsAbsent(pRequest,inBufSize,outBufSize);
        return;
    }
    else if (ControlCode==IOCTL_SMARTCARD_POWER) {
        reader.IoSmartCardPower(pRequest,inBufSize,outBufSize);
        return;
    }	
    else if (ControlCode==IOCTL_SMARTCARD_SET_ATTRIBUTE) {
        reader.IoSmartCardSetAttribute(pRequest,inBufSize,outBufSize);
        return;
    }
    else if (ControlCode==IOCTL_SMARTCARD_SET_PROTOCOL) {
        reader.IoSmartCardSetProtocol(pRequest,inBufSize,outBufSize);
        return;
    }
    else if (ControlCode==IOCTL_SMARTCARD_TRANSMIT) {
        reader.IoSmartCardTransmit(pRequest,inBufSize,outBufSize);
        return;
    }
    swprintf(log,L"[BixVReader][IOCT]ERROR_NOT_SUPPORTED:%08X",ControlCode);
    OutputDebugString(log);
    pRequest->CompleteWithInformation(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), 0);

    return;
}


DWORD WINAPI ServerFunc(Reader *reader) {
    return reader->startServer();
}


/////////////////////////////////////////////////////////////////////////
//
// CMyDevice::OnPrepareHardware
//
//  Called by UMDF to prepare the hardware for use. 
//
// Parameters:
//      pWdfDevice - pointer to an IWDFDevice object representing the
//      device
//
// Return Values:
//      S_OK: success
//
/////////////////////////////////////////////////////////////////////////

HRESULT CMyDevice::OnPrepareHardware(
                                     __in IWDFDevice* pWdfDevice
                                     )
{
    inFunc
        SectionLogger a(__FUNCTION__);
    // Store the IWDFDevice pointer
    m_pWdfDevice = pWdfDevice;

    // Configure the default IO Queue
    HRESULT hr = CMyQueue::CreateInstance(m_pWdfDevice, this);

    return hr;
}


/////////////////////////////////////////////////////////////////////////
//
// CMyDevice::OnReleaseHardware
//
// Called by WUDF to uninitialize the hardware.
//
// Parameters:
//      pWdfDevice - pointer to an IWDFDevice object for the device
//
// Return Values:
//      S_OK:
//
/////////////////////////////////////////////////////////////////////////
HRESULT CMyDevice::OnReleaseHardware(
                                     __in IWDFDevice* pWdfDevice
                                     )
{
    inFunc
        SectionLogger a(__FUNCTION__);
    UNREFERENCED_PARAMETER(pWdfDevice);

    // Release the IWDFDevice handle, if it matches
    if (pWdfDevice == m_pWdfDevice.p)
    {
        m_pWdfDevice.Release();
    }

    return S_OK;
}


HRESULT CMyDevice::OnD0Entry(IN IWDFDevice*  pWdfDevice,IN WDF_POWER_DEVICE_STATE  previousState) {
    SectionLogger a(__FUNCTION__);
    UNREFERENCED_PARAMETER(pWdfDevice);
    UNREFERENCED_PARAMETER(previousState);

    numInstances=GetPrivateProfileInt(L"Driver",L"NumReaders",1,L"BixVReader.ini");	
    readers.resize(numInstances);

    for (int i=0;i<numInstances;i++) {
        wchar_t section[300];
        char sectionA[300];
        swprintf(section,L"Reader%i",i);
        sprintf(sectionA,"Reader%i",i);

        int rpcType=GetPrivateProfileInt(section,L"RPC_TYPE",0,L"BixVReader.ini");
        if (rpcType==0)
            readers[i]=new PipeReader();
        else if (rpcType==1)
            readers[i]=new TcpIpReader();

        readers[i]->instance=i;
        readers[i]->device=this;
        GetPrivateProfileStringA(sectionA,"VENDOR_NAME","Bix",readers[i]->vendorName,300,"BixVReader.ini");
        GetPrivateProfileStringA(sectionA,"VENDOR_IFD_TYPE","VIRTUAL_CARD_READER",readers[i]->vendorIfdType,300,"BixVReader.ini");
        readers[i]->deviceUnit=GetPrivateProfileInt(section,L"DEVICE_UNIT",i,L"BixVReader.ini");
        readers[i]->protocol=0;

        readers[i]->init(section);

        DWORD pipeThreadID;
        readers[i]->serverThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ServerFunc,readers[i],0,&pipeThreadID);
    }

    return S_OK;
}
HRESULT CMyDevice::OnD0Exit(IN IWDFDevice*  pWdfDevice,IN WDF_POWER_DEVICE_STATE  newState) {
    SectionLogger a(__FUNCTION__);
    UNREFERENCED_PARAMETER(pWdfDevice);
    UNREFERENCED_PARAMETER(newState);
    // dovrei fermare tutti i thread in ascolto dei lettori
    shutDown();
    return S_OK;
}

void CMyDevice::shutDown() {
    SectionLogger a(__FUNCTION__);
    for (int i=0;i<numInstances;i++) {
        readers[i]->shutdown();
        delete readers[i];
    }
    numInstances=0;
}
HRESULT CMyDevice::OnQueryRemove(IN IWDFDevice*  pWdfDevice) {
    SectionLogger a(__FUNCTION__);
    UNREFERENCED_PARAMETER(pWdfDevice);
    OutputDebugString(L"[BixVReader]OnQueryRemove");
    shutDown();
    return S_OK;
}
HRESULT CMyDevice::OnQueryStop(IN IWDFDevice*  pWdfDevice) {
    SectionLogger a(__FUNCTION__);
    UNREFERENCED_PARAMETER(pWdfDevice);
    OutputDebugString(L"[BixVReader]OnQueryStop");
    shutDown();
    return S_OK;
}
void CMyDevice::OnSurpriseRemoval(IN IWDFDevice*  pWdfDevice) {
    SectionLogger a(__FUNCTION__);
    UNREFERENCED_PARAMETER(pWdfDevice);
    OutputDebugString(L"[BixVReader]OnSurpriseRemoval");
    shutDown();
}

STDMETHODIMP_ (void) CMyDevice::OnCancel(IN IWDFIoRequest*  pWdfRequest) {
    SectionLogger a(__FUNCTION__);

    wchar_t log[300];
    SectionLocker lock(m_RequestLock);

    int instance=0;
    {	
        CComPtr<IWDFFile>   pFileObject;
        pWdfRequest->GetFileObject(&pFileObject);

        if (pFileObject != NULL)
        {
            DWORD logLen=300;
            pFileObject->RetrieveFileName(log,&logLen);
            instance=_wtoi(log+(logLen-2));
        }
    }
    Reader &reader=*readers[instance];

    if (pWdfRequest==reader.waitRemoveIpr) {
        OutputDebugString(L"[BixVReader]Cancel Remove");
        reader.waitRemoveIpr=NULL;
    }
    else if (pWdfRequest==reader.waitInsertIpr) {
        OutputDebugString(L"[BixVReader]Cancel Insert");
        reader.waitInsertIpr=NULL;
    }
    pWdfRequest->CompleteWithInformation(HRESULT_FROM_WIN32(ERROR_CANCELLED), 0);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Fabio Ottavi
Engineer
Italy Italy
No Biography provided

| Advertise | Privacy | Mobile
Web04 | 2.8.140905.1 | Last Updated 30 Jan 2014
Article Copyright 2010 by Fabio Ottavi
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid