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





3.00/5 (1 vote)
Example for read Magnetic Strip Reader using ActiveX, COM Object for KioskMsr reader
- Download source files - 20 Kb
- Download demo project - 60 Kb
- Download original SDK Kiosk100 program in Borland C++ and driver setup program - 961Kb
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.
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.
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.