Solved

using winscard.dll

Posted on 2004-08-16
10
4,311 Views
Last Modified: 2007-12-19

I'm trying this here because not very many vb programmers work with this I am sure:

 I'm using the ACS 30 Reader and an ACOS1 Card and I am calling using APIs to call winscard.dll using VB .Net 2003

I've written a very nice application that works wonderfully....  except...

I have a memory leak.

I've cut out all my code, and I find that it is the API calls themselves that cause the problem.

I'm writing counters onto the card using SCARDTRANSMIT, so I made a stress test that simply puts SCARDTRANSMIT in a loop.

I noticed that when I write over 47,000 times to a counter on the card (in a file that I have set up on the card) that winscard.dll starts hogging all sorts of memory.  so that when I get up to 98,000 writes, that windows has
used up to 1 GB of RAM!  is there any help anyone can give me here?

like I said, there is like, no other programming than just calling the API.

-K
0
Comment
Question by:jderting
  • 5
  • 3
  • 2
10 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 11811582
Could you post your code? What happens when you do a 'ScardDisconnect()' and then reconnect?
0
 
LVL 2

Author Comment

by:jderting
ID: 11812293
actually, it is funny. that is the first thing I tried.

when I do scardDisconnect, then start over, the memory problems are worse!

in my stress test code, I use the following APIs:

    Public Declare Function SCardEstablishContext Lib "Winscard.dll" (ByVal dwScope As Integer, ByVal pvReserved1 As Integer, ByVal pvReserved2 As Integer, ByRef phContext As Integer) As Integer
    Public Declare Function SCardReleaseContext Lib "Winscard.dll" (ByVal hContext As Integer) As Integer
    Public Declare Function SCardConnect Lib "Winscard.dll" Alias "SCardConnectA" (ByVal hContext As Integer, ByVal szReaderName As String, ByVal dwShareMode As Integer, ByVal dwPrefProtocol As Integer, ByRef hCard As Integer, ByRef ActiveProtocol As Integer) As Integer
    Public Declare Function SCardDisconnect Lib "Winscard.dll" (ByVal hCard As Integer, ByVal Disposistion As Integer) As Integer
    Public Declare Function SCardBeginTransaction Lib "Winscard.dll" (ByVal hCard As Integer) As Integer
    Public Declare Function SCardEndTransaction Lib "Winscard.dll" (ByVal hCard As Integer, ByVal Disposition As Integer) As Integer
    Public Declare Function SCardState Lib "Winscard.dll" (ByVal hCard As Integer, ByRef State As Integer, ByRef Protocol As Integer, ByRef ATR As Byte, ByRef ATRLen As Integer) As Integer
    Public Declare Function SCardStatus Lib "Winscard.dll" Alias "SCardStatusA" (ByVal hCard As Integer, ByVal szReaderName As String, ByRef pcchReaderLen As Integer, ByRef State As Integer, ByRef Protocol As Integer, ByRef ATR As Byte, ByRef ATRLen As Integer) As Integer
    Public Declare Function SCardListReaders Lib "Winscard.dll" Alias "SCardListReadersA" (ByVal hContext As Integer, ByVal mzGroup As String, ByVal ReaderList As String, ByRef pcchReaders As Integer) As Integer
    Public Declare Function SCardReset Lib "Winscard.dll" (ByVal hCard As Integer, ByRef pioSendRequest As SCARD_IO_REQUEST, ByRef SendBuff As Byte, ByVal SendBuffLen As Integer, ByRef pioRecvRequest As SCARD_IO_REQUEST, ByRef RecvBuff As Byte, ByRef RecvBuffLen As Integer) As Integer



this is how I have written the test:

1. SCardEstablishContext
2. SCardListReaders (to find my reader)
3. SCardConnect
4. SCardBeginTransaction


5. SCardTransmit
  - I loop and call this a bunch of times

6. SCardEndTransaction
7. SCardDisconnect


I know what you are asking, so I tried it this way:


1. SCardEstablishContext
2. SCardListReaders (to find my reader)
3. SCardConnect
4. SCardBeginTransaction
5. SCardTransmit
6. SCardEndTransaction
7. SCardDisconnect

loop through 1 to 7 a bunch of times


..liike said. I got it talking just fine with the card, and saving what I need, it is just that I want to use this for a document processing system, and I want to increment a counter on the card for each document processed.  

what I do is:
I connect to the card (and get the card handle) and I keep it open

then I call scardtransmit for every one processed

then I disconnect from the card.

-K
0
 
LVL 86

Expert Comment

by:jkr
ID: 11812338
So, what about the actual code? (BTW, the above looks suspiciously like VB)
0
 
LVL 2

Author Comment

by:jderting
ID: 11812557
like said in my first post, it IS vb.  I posted here because I figured I would find more programmers familiar with winscard.dll

-K
0
 
LVL 19

Accepted Solution

by:
drichards earned 500 total points
ID: 11812661
Where's the declaration for SCardTransmit?  This is called more than any other function and you don't have it listed in your Declare statements.

Two immediate observations:

1) In the original version of your code you started a transaction and then did tens of thousands of operations.  If "transaction" in tis context is at all like a database transaction, it is saving LOTS of stuff and would be chewing up lots of memory.

2) .NET runtime will also chew up memory if you are doing lots of allocations in the loop - need to see that code.

Also, did anything chahge when you changed the code to do one connect-transmit-disconnect cycle per loop iteration?
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 19

Expert Comment

by:drichards
ID: 11812702
I take that back - it MIGHT chew up lots of memory for a transaction.  Depends on the implementation of course.
0
 
LVL 2

Author Comment

by:jderting
ID: 11814224
ok.. I'll try to keep it short and concise.   -- in vb, this is basically what I am doing:

you will see

1. the APIs,
2. a structure (passed to SCARDTRANSMIT),
3.  a button function which runs the code.

earlier, when I had it connect, do 1 write, disconnect   (which had both start and end transaction in there), then it used up MORE memory! it was almost like the .dll was just continuiing to inflate itself.

I think you might have a good point in the 'transaction' part, i've rewritten the stress test to start a transaction, do a write, then end the transaction, etc.



    ' - The Transmit API is in CardModule_Base

    Public Declare Function SCardEstablishContext Lib "Winscard.dll" (ByVal dwScope As Integer, ByVal pvReserved1 As Integer, ByVal pvReserved2 As Integer, ByRef phContext As Integer) As Integer
    Public Declare Function SCardReleaseContext Lib "Winscard.dll" (ByVal hContext As Integer) As Integer
    Public Declare Function SCardConnect Lib "Winscard.dll" Alias "SCardConnectA" (ByVal hContext As Integer, ByVal szReaderName As String, ByVal dwShareMode As Integer, ByVal dwPrefProtocol As Integer, ByRef hCard As Integer, ByRef ActiveProtocol As Integer) As Integer
    Public Declare Function SCardDisconnect Lib "Winscard.dll" (ByVal hCard As Integer, ByVal Disposistion As Integer) As Integer
    Public Declare Function SCardBeginTransaction Lib "Winscard.dll" (ByVal hCard As Integer) As Integer
    Public Declare Function SCardEndTransaction Lib "Winscard.dll" (ByVal hCard As Integer, ByVal Disposition As Integer) As Integer
    Public Declare Function SCardState Lib "Winscard.dll" (ByVal hCard As Integer, ByRef State As Integer, ByRef Protocol As Integer, ByRef ATR As Byte, ByRef ATRLen As Integer) As Integer
    Public Declare Function SCardStatus Lib "Winscard.dll" Alias "SCardStatusA" (ByVal hCard As Integer, ByVal szReaderName As String, ByRef pcchReaderLen As Integer, ByRef State As Integer, ByRef Protocol As Integer, ByRef ATR As Byte, ByRef ATRLen As Integer) As Integer
    Public Declare Function SCardListReaders Lib "Winscard.dll" Alias "SCardListReadersA" (ByVal hContext As Integer, ByVal mzGroup As String, ByVal ReaderList As String, ByRef pcchReaders As Integer) As Integer
    Public Declare Function SCardReset Lib "Winscard.dll" (ByVal hCard As Integer, ByRef pioSendRequest As SCARD_IO_REQUEST, ByRef SendBuff As Byte, ByVal SendBuffLen As Integer, ByRef pioRecvRequest As SCARD_IO_REQUEST, ByRef RecvBuff As Byte, ByRef RecvBuffLen As Integer) As Integer
    Public Declare Function SCardTransmit Lib "Winscard.dll" (ByVal hCard As Integer, ByRef pioSendRequest As SCARD_IO_REQUEST, ByRef SendBuff As Byte, ByVal SendBuffLen As Integer, ByRef pioRecvRequest As SCARD_IO_REQUEST, ByRef RecvBuff As Byte, ByRef RecvBuffLen As Integer) As Integer

    Public Structure SCARD_IO_REQUEST

        Dim dwProtocol As Integer
        Dim cbPciLength As Integer

    End Structure

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim SCARD_SCOPE_USER As Short = 0
        Dim SCARD_S_SUCCESS As Short = 0 'API will return this if success
        Const SCARD_SHARE_EXCLUSIVE As Integer = 1 ' This application is not willing to share this card with other applications.
        Const SCARD_PROTOCOL_T0 As Short = 1

        Dim ioSendRequest As SCARD_IO_REQUEST
        Dim ioRecvRequest As SCARD_IO_REQUEST
        Dim bySendBuff(255 + 10) As Byte
        Dim byRecvBuff(255 + 2) As Byte
        Dim iSendBuffLen As Integer
        Dim iRecvBuffLen As Integer
        Dim iorequest As New SCARD_IO_REQUEST

        Dim bSuccess As Boolean
        Dim iCardContext As Integer
        Dim iHandle As Integer 'Card Handle
        Dim iProtocol As Integer

        Dim Buff As String
        Dim sGroup As String
        Dim BuffLen As Integer

        bSuccess = (SCardEstablishContext(SCARD_SCOPE_USER, 0, 0, iCardContext) = SCARD_S_SUCCESS) 'iCardContext is populated by this function

        'Make this into a function that will pull the first available reader
        Buff = New String(vbNullChar, 255)
        BuffLen = 255
        sGroup = vbNullString
        RetCode = SCardListReaders(iCardContext, sGroup, Buff, BuffLen)

        Buff = FixString(Buff)

        bSuccess = (SCardConnect(iCardContext, Buff, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0, iHandle, iProtocol) = SCARD_S_SUCCESS) 'iHandle  & iProtocol are populated here by this function
        bSuccess = (SCardBeginTransaction(iHandle) = SCARD_S_SUCCESS)




        '''We are now all connected to the card. this is an MCU card, so to save time, I selected the appropriate file before starting
'This is the key TRANSMIT function that is called many times, (imagine different values sent to SCARDTRANSMIT for each iteration of the loop.

        ReDim bySendBuff(255 + 10) 'Clear Buffer
        ReDim byRecvBuff(255 + 2) 'Clear Buffer

        'Now we will write '0' to the card

        bySendBuff(0) = &H80 'CLA
        bySendBuff(1) = 210 'INS
        bySendBuff(2) = 1 'P1
        bySendBuff(3) = &H0S 'P2
        bySendBuff(4) = &H1  'P3

        'Data we will be writing
        bySendBuff(5) = 48

        iSendBuffLen = 5 + 1   'Compute our send length by adding Header to data length
        iRecvBuffLen = 2 'Since we are sending data, then we know we will get a response of 2 characters.


        'Here is our structure, it is basically 2 integers

        ioSendRequest.dwProtocol = SCARD_PROTOCOL_T0
        ioSendRequest.cbPciLength = Len(ioSendRequest)

        ioRecvRequest.dwProtocol = SCARD_PROTOCOL_T0
        ioRecvRequest.cbPciLength = Len(ioRecvRequest)

        bSuccess = (SCardTransmit(iHandle, ioSendRequest, bySendBuff(0), iSendBuffLen, ioRecvRequest, byRecvBuff(0), iRecvBuffLen) = SCARD_S_SUCCESS)

        Stop

    End Sub
0
 
LVL 19

Expert Comment

by:drichards
ID: 11814627
Doesn't look like anything out of the ordinary.  You're killing about 500 bytes per transmit as a result of the ReDim on the buffers, but even doing really conservative math and saying it's 1KB and figuring your 98,000 iterations, that's about 98MB (agree with the math?) of memory, not 1GB.  Off by an order of magnitude.  It IS quite a bit, however, and you might want to fix that.

When you said 1GB of memory usage, was that process memory of machine memory.  My machine sits idle at over 200MB - much less if I shut down the two web servers, though :)

I notice you never call SCardReleaseContext.  Is there something in the context that grows over time?

You might also try a bit of experimentation.  Run the code but comment out the actual sCardTransmit call.  If memory still goes up, comment out the transmit and the transaction calls.  Work your way out (or start out and go in) until memory use does not increase.

Have you checked if there are any known defects or issues with this library?
0
 
LVL 2

Author Comment

by:jderting
ID: 11815333
1GB is machine memory.

I ran the test on Sunday with the SCARDTRANSMIT commented out, and i did not have the same problems. memory stayed pretty much even, but I only ran it to 98,000

I keep the context open because I am expecting to keep the card in as the counter is incremented. (kind of like when you go to Kinko's, insert a card, then it records clicks on the card)


where would I look to find defects in the library?


as far as the commenting scenarios, I'll let you know about what I find.


-K
0
 
LVL 2

Author Comment

by:jderting
ID: 11821766
...that was it!  ending the transaction after a write significantly reduced the memory leak issues.  :)   (significantly enough to remove winscard.dll as my problem now, which leaves MY code doing the rest.)  Not ending the transaction between writes was eating memory like no vb program would.

I have found, actually, that I can do a number of writes per transaction..   but for now I can assume that doing as few writes as possible in a transaction is best. It is a work in progress.

It would sure be nice to see some written documentation on this.   I have had the hardest time finding people or groups that know how to use smart cards.   The manual that comes with the ACR30 and the ACOS1 are cryptic at best for VB Programmers. but I was able to muddle through.

The code I have posted is not my actual code, I have 3 objects that do this. The code I have posted is the distillation of what they do.  I had just felt that either I did not understand the smart card lingo, hardware, but most likely computing in general to know fully what's going on.

as a VB programmer, I usually write Front-End stuph just connecting to a DB, however, lately, I have been having to do a lot of processing work myself.  I was pretty much treating the Smart Card as my database, I just had to do some manipulation of the data to and from hex when dealing with the card. - but it was the processing part of the equation that got me here.

Every time I talk to a C++ programmer, I usually get an additional education of what my code REALLY does, so I am grateful for your patience and the advice.
if anyone knows where I can find groups on smart cards, please reply with links (I dont want to keep having to post in the C++ forum)
if anyone knows where I can find tools to help me with memory leaks please let me know as well.  

also, I have seen a number of posts online for people working with .net needing to know how to deal with smart cards, so the code is good for them to understand how it works.

demo code to use the ACR30 can be found here:    http://www.acs.com.hk/downloads_demo.asp
that page contains code in VB6, C++, and Delphi (.Net programmers will have to convert the vb6 code)

-K

0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now