Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ActiveX Magnetic Strip reader for Web and Windows Appications with a custom event

0.00/5 (No votes)
29 May 2006 1  
Example for read Magnetic Strip Reader using ActiveX, COM Object for KioskMsr reader

Web card reader tester

Introduction

In this article show how can use an ActiveX Magnetic Strip Reader for read Magnetic Cards on Html page or Asp, Aspx page using an ActiveX component. 

Case of study:

This program applies for example if you need read a Magnetic card in a Kiosk for a Banking automation and Self Service Terminals.
Kiosk
You need create web application capable read when the client insert a card and validate it and do validations then grand or deny the access into website. For achieve the goal you need create two components. First you need create an activeX program and second a web page for test the activeX component. The ActiveX component needs be able interact with card reader hardware.

For test this program you need buy a card reader (45USD). Other option is buy a Kiosk Virtual (showed in the above picture). 

In my example I choose the first option. In other example I will show how can interact with a Kiosk Virtual. I test with an "USB EZ-100PU Smart Card Reader" series from the provider http://www.casauto.com.tw/ I upload the drivers from the same site. Also you need the manual for API(Application Programming Interface) use. This model is "Kiosk100 Hybrid Card Reader with USB connector". The software is "EZ100/200/Mini PC/SC series smart card reader and read magnetic stripe card data in the Kiosk100 hybrid card reader".

Using the code

First I create an ActiveX Dll project in Vb 6.0. If you know Visual C++ you can create ATL Project. In Borland C++ also you can create a project. In my example I use API declarations for import functions from the dll called "WinScard.dll" and "KIOSKMSR.DLL"(included in the source in this article). First you need translate API functions from C++ to VB, for example:

LONG SCardEstablishContext(IN DWORD dwScope,IN LPCVOID pvReserved1,IN LPCVOID pvReserved2,OUT LPSCARDCONTEXT phContext);

In visual basic is equivalent to:

Public Declare Function SCardEstablishContext Lib "WinScard" (ByVal dwScope As Long, ByVal pvReserved1 As Long, ByVal pvReserved2 As Long, ByRef phContext As Long) As Long


In the module I declare functions for use API libraries.

Public Declare Function SCardEstablishContext Lib "WinScard" (ByVal dwScope As Long, ByVal pvReserved1 As Long, ByVal pvReserved2 As Long, ByRef phContext As Long) As Long
Public Declare Function SCardReleaseContext Lib "WinScard" (ByVal hContext As Long) As Long
Public Declare Function SCardListReaders Lib "WinScard" Alias "SCardListReadersA" (ByVal hContext As Long, ByVal mszGroups As String, ByVal mszReaders As String, ByRef phContext As Long) As Long

Public Declare Function CasOpenMSR Lib "KIOSKMSR" (ByVal szReader As String, ByRef phMSR As Long) As Long
Public Declare Function CasReadMSR Lib "KIOSKMSR" (ByVal hMSR As Long, ByRef pMSR_Data As MSR_DATA, ByVal ulTimeout As Integer) As Long
Public Declare Function CasWaitForMSR Lib "KIOSKMSR" (ByVal hMSR As Long, ByRef pMSR_Data As MSR_DATA) As Long
Public Declare Function CasDisableMSR Lib "KIOSKMSR" (ByVal hMSR As Long) As Long
Public Declare Function CasCloseMSR Lib "KIOSKMSR" (ByVal hMSR As Long) As Long
Global Const SCARD_S_SUCCESS = 0
Global Const SCARD_W_WAIT_MSR = &H8010006A

' Output track
Public Type Track
    '// A buffer that receives the MSR Track data from the reader

    Buffer As String * 255
    '// The length of the data of Track received from the reader
    BufferLength As Long
End Type
Public Type MSR_DATA
    Track01 As Track
    Track02 As Track
    Track03 As Track
End Type

The first declaration use WinScard Functions from WinScard library for list card readers installed and detected in the local computer. The WinScard library is included in all Windows versions and you can found at System32 directory (at runtime the program search the winscard.dll at system32 directory). Also you need verify "Smart Card" service is started, you can verify writing services.msc from "Start Menu -> Run" and find "Smart Card" in the services window showed. Start if it is stopped, and i recommend change Startup type to "Automatic" 

The other declarations (Kioskmsr) are used for read tracks for MSR (Magnetic strip Reader). And "Type structure" is used for store the read tracks of the card.

Also I use user32.dll for import Timer functions for program timeout option in the program.

Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long 
Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long 
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (dest As Any, source As Any, ByVal bytes As Long) 

Other important point is an event called LecturaTracks.

Public Event LecturaTracks(ByVal valor As Long) 

Go to the action:
In the web page I use this event "CardReader_LecturaTracks", and when the client inserts a card, in visual basic I can detect it, and throw an event LecturaTracks at webpage. The first part of this method is the class name and the second part is the event name.

<HTML><HEAD><TITLE>Kiosk100Msr.CAB</TITLE></HEAD> 
<BODY onload="StartReader()" onunload="TerminateReader()"> 
<SCRIPT LANGUAGE="VBScript"> 
Function CardReader_LecturaTracks(valor) 
 alert("EventCardReader_LecturaTracks") 
 if (valor = 0) then 
   alert(CardReader.Track1 + chr(10)+ CardReader.Track2 + chr(10)+ CardReader.Track3) 
 else 
   alert("MSR read fail: " + valor) 
end if
End Function 
Sub ReadTracks 
  call CardReader.LeerTracks() 
  alert("Read tracks") 
End Sub 
Sub StartReader 
  call CardReader.Inicializar() 
  alert("Started") 
End Sub 
Sub TerminateReader 
  call CardReader.Finalizar() 
  alert("Finalized") 
End Sub </SCRIPT> 
<OBJECT id="CardReader" codeBase="BPKiosk100Msr.CAB#version=1,0,0,0" classid="CLSID:EE1E2BF0-5033-44C2-82B4-0D822A257369">
</OBJECT> 
<INPUT id="Button1" type="button" value="ReadTracks" name="Button1" onclick="ReadTracks()" >
</BODY>
 </HTML> 

When Web page is showed by internet explorer, the body tag execute onLoad event calling "StartReader" method. This method calls to "CardReader.Inicializar".

At visual basic program the "Inicializar" method perform this actions: First validate if the smart card service is started (SCardEstablishContext), if fail return -1 and is equal to "Establish Context Fail. Start windows service named: 'Smart card reader' and try again". Second the method validate if exists card Readers connected and ready for the use (SCardListReaders),if fail then return -2 and is equal to "SCardListReaders Fail!. Connect the MSR and try again". If exist one or more card reader, use the first card reader (GetFirstLector). 

lResult = SCardEstablishContext(2, 0, 0, ScardContext) 
If lResult <> SCARD_S_SUCCESS Then 
  Inicializar = -1
  Exit Function 
End If 
Dim mszGroups As String 
Dim szReaderLists As String * 256 
Dim nReaderCount As Long 
nReaderCount = 255 
lResult = SCardListReaders(ScardContext, mszGroups, szReaderLists, nReaderCount) 
If lResult <> SCARD_S_SUCCESS Then 
  Inicializar = -2 
  Exit Function 
End If 
szReader = GetFirstLector(szReaderLists) 
If (szReader = "") Then 
  Inicializar = -2 
  Exit Function 
End If 

Returning at the web page, when user perform click action at ReadTrack button, the "ReadTracks()" method is executed. In the "LeerTracks" method in visual basic performs these actions: First Disabled the card reader CasDisableMSR), after close (CasCloseMSR). This is for release the card for use it. After execute CasOpemMSR, if this API method return a value different of zero then throw -11 and is equal to "Open MSR Fail!." & vbCrLf & "Connect the MSR and try again". If the Open is success, try reading the magnetic strip. The API method CasReadMSR is a loop and send a signal to card reader for read the tracks. Only if the card is already inserted in the reader return 0, but in the most cases return SCARD_W_WAIT_MSR, because the card isn't yet in the card reader. In this case, I activate the timer.

Public Function LeerTracks() As Long 
  Dim lResult As Long lResult = CasDisableMSR(MsrHandle) 
  lResult = CasCloseMSR(MsrHandle) 
  lResult = CasOpenMSR(szReader, MsrHandle) 
  If (lResult <> SCARD_S_SUCCESS) Then 
    LeerTracks = -11 
    Exit Function 
  End If 
  MsrData.Track01.Buffer = Space(255) 
  MsrData.Track02.Buffer = Space(255) 
  lResult = CasReadMSR(MsrHandle, MsrData, 0) 
  If (lResult <> SCARD_S_SUCCESS) Then 
     If (lResult = SCARD_W_WAIT_MSR) Then 
        contTimeout = 0 
        MsrTimer.Enabled = True 
     Else 
        LeerTracks = -20 
        Exit Function 
     End If 
  End If 
  LeerTracks = 0 
Exit Function 

End Function  

The timer function perform these actions: First validate if status of card is waiting using CasWaitForMSR API function in card reader. If can read the tracks throw "LecturaTracks" event and notify to web page this event are processed.

Private Sub MsrTimer_Timer() 
  Dim lResult As Long 
  lResult = CasWaitForMSR(MsrHandle, MsrData) 
  If (lResult = SCARD_S_SUCCESS) Then 
    MsrTimer.Enabled = False ' disable the timer
    RaiseEvent LecturaTracks(0) 
    Exit Sub 
  **** 
  ****




  Exit Sub 
End Sub  

In the web page I can validate it in CardReader_LecturaTracks function, in this case, when "valor" is equal to 0, the magnetic strip are success read, and you can show the tracks using CardReader.Track1, Track2, Track3 properties.

Function CardReader_LecturaTracks(valor) 
alert("EventCardReader_LecturaTracks") 
if (valor = 0) then 
alert(CardReader.Track1 + chr(10)+ CardReader.Track2 + chr(10)+ CardReader.Track3) 
else 
alert("MSR read fail: " + valor) 
end if
End Function  Sub 
End Sub  

 

Points of Interest

For obtain the goal, fist I read some articles about magnetic strip, and now I know about the data stored on the magnetic stripe. ANSI/ISO standards define *3* Tracks, each of which is used for different purposes. These Tracks are defined only by their location on the magnetic stripe, since the magnetic stripe as a whole is magnetically homogeneous all Cards have 3 tracks. The structure is:

*** Track 1 Layout: ***
| SS | FC | PAN | Name | FS | Additional Data | ES | LRC |
SS=Start Sentinel "%"
FC=Format Code
PAN=Primary Account. # (19 digits max)
FS=Field Separator "^"
Name=26 alphanumeric characters max.
Additional Data=Expiration Date, offset, encrypted PIN, etc.
ES=End Sentinel "?"
LRC=Longitudinal Redundancy Check

*** Track 2 Layout: ***
| SS | PAN | FS | Additional Data | ES | LRC |
SS=Start Sentinel ";"
PAN=Primary Account. # (19 digits max)
FS=Field Separator "="
Additional Data=Expiration Date, offset, encrypted PIN, etc.
ES=End Sentinel "?"
LRC=Longitudinal Redundancy Check

*** Track 3 Layout: **
Similar to tracks 1 and 2. Almost never used. Many different data standards used.

In the picture the first track start with "%" (Start Sentinel) follow with format code ("B" in this case) and finalize with "?". The "^" is a field separator.

Now I test the original program written in Borland C++ and try and this work correctly.

After I research about ActiveX component, I found some articles about this, in Visual C++, and Visual Basic. I create a Visual C++ ATL project and I test in a Window application and this work, but when I test in a web application didn't work. Then I create a Visual Basic ActiveX project and work in a windows and web application. For test in a web application I modify internet explorer setting. First I open Internet explorer and in the menu Tools->Options. In the dialog window I select security tab and select Local intranet. After I do click in "Custom Level..." button. I change to "Enable" the following options:
  - Download signed ActiveX controls
  - Download unsigned ActiveX controls
  - Initialize and script ActiveX controls not marked as safe
Note: Modify Internet zone (not Local intranet zone) is not recommended because expose your computer for install all ActiveX and will install a virus ActiveX in your computer. 

In the programming, the most difficult problem was using API functions from the "KIOSKMSR.DLL". You can inspect the methods exposed in the dll using Dependency Walker program. And with a "Kiosk 100 MSR API Reference" I transtlate API entries to Visual Basic. 

Other point was creating in Visual Basic a Public Event. This can be used in a web page in Internet explorer.

After in Visual Basic I create Cab installer for generate html page and obtain a classid for use ActiveX component.

Is necessary copy KIOSKMSR.DLL on system32 directory because Internet explorer search this dll in "%ProgramFiles%\Internet Explorer" directory, system32 directory. Other alternative is copy at "%ProgramFiles%\Internet Explorer".

When you open the page the cab component install in your computer. You can view the installed component for example at "C:\WINDOWS\Downloaded Program Files". If you didn't compile the program, then you can manually register the "Kiosk100Msr.dll" included in a cab component using the follow syntax: regsvr32 Kiosk100Msr.dll.

Because I program the reader for a Virtual Kiosk I need show full screen and I need change this registry entries:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_WINDOW_RESTRICTIONS] @="" "iexplore.exe"=dword:00000000
"explorer.exe"=dword:00000001
"msimn.exe"=dword:00000001

[HKEY_CURRENT_USER\Console]
"FullScreen"=dword:00000001

Finally at the kiosk I install SP2 for Windows Xp, and I configure for disable all programs, and configure "Automatico Logon" with "tweakUI PowerToy". Then the Kiosk is ready for use it.
 

History

There are two demo programs. One is a windows application for test the reader and are a Kiosk100MsrTESTER.HTM for test on the web.

window card reader tester

This is my first version; you can improve and modify it. If the application is used at Internet (not intranet), the cabinet component need be signed with a valid certificate (Verisign provide certificate and the cost is around 100USD per year). for correct installation on client computer.

I also programmed idckde readers for read tracks.

Thanks to all people for your help.

 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here