Printable Version of Topic

Click here to view this topic in its original format

UtterAccess Forums _ Visual Basic 2003 and Later _ Converting Code To Vba

Posted by: Zepha Jun 12 2019, 08:32 AM

Dear Members

I am trying to write functions to read data from and write data to a Smart Card. I searched for VBA codes all over the Internet and failed to find anything I can use. However, i came across some codes which I believe I could modify for my purpose. However, while walking through the codes I have found some statements that require different syntax in VBA, but I cannot translate them. I request anybody in here with knowledge of both languages to help me translate these selected codes to VBA:

ASCII.GetBytes(lpszSendData, 0, Len(lpszSendData), aSend, 5)

ASCII.GetString(aRecv).Substring(0, pbLen)

pszRdr = New String(vbNullChar, 255)

aRdrLst(i) = aRdrLst(i).Replace(vbNullChar, vbNullString)

Dim sATR As String = String.Empty

Dim aATR() As Byte = Array.CreateInstance(GetType(Byte), 0)

pszATR = pszATR.TrimEnd(vbNullChar)

For i = 0 To (Len(pszATR) - 1)
pbAttr += Hex(Asc(pszATR.Chars(i))).PadLeft(2, "0") & Space(1)
Next i

Thank you very much







Posted by: ADezii Jun 12 2019, 11:24 AM

This will be a somewhat feeble attempt to convert the Code into VBA, especially given the fact that I'm not even sure what Language the Code is in. In any event, here is what I came up with. I CANNOT attest to it's accuracy or interpretation, I can only hope that it will at least point you in the right direction.

CODE
'pszRdr = New String(vbNullChar, 255)
'vbNullChar - a character having a Value of 0 (translated)

Dim pszRdr As String
pszRdr = String(255, vbNullChar)
'OR
pszRdr = String(255, Chr$(0))

CODE
'aRdrLst(i) = aRdrLst(i).Replace(vbNullChar, vbNullString)
'If a NULL Character exists in the nth Element of an
'Array, Replace it with a NULL String

aRdrLst(i) = Replace(aRdrLst(i), vbNullChar, vbNullString)

CODE
'Dim sATR As String = String.Empty
'String.Empty - an Empty String (translated)

Dim sATR As String
sATR = ""

CODE
'Dim aATR() As Byte = Array.CreateInstance(GetType(Byte), 0)
'Creates a 1-dimensional Byte Array of Zero Length

Dim aATR() As Byte

CODE
'pszATR = pszATR.TrimEnd(vbNullChar)
'Remove a Trailing NULL Character from a String

Dim pszATR As String    'with a Trailing NULL
pszATR = Left$(pszATR, Len(pszATR) - 1)

CODE
'For i = 0 To (Len(pszATR) - 1)
  'pbAttr += Hex(Asc(pszATR.Chars(i))).PadLeft(2, "0") & Space(1)
'Next i
'Converts each Character of a String to a Hex Value padded
'on the left with 2 zeros (0's) and an additional Space

Dim pszATR As String
Dim i As Integer

pszATR = "Hello Dolly!"

Debug.Print pszATR

For i = 1 To Len(pszATR)
  Debug.Print Mid$(pszATR, i, 1) & ": 00" & _
              Hex(Asc(Mid$(pszATR, i, 1))) & Space(1)
Next i

CODE
OUTPUT from above:
Hello Dolly!
H: 0048
e: 0065
l: 006C
l: 006C
o: 006F
: 0020
D: 0044
o: 006F
l: 006C
l: 006C
y: 0079
!: 0021

CODE
'ASCII.GetBytes(lpszSendData, 0, Len(lpszSendData), aSend, 5)
'ASCII.GetString(aRecv).Substring(0, pbLen)

'Not sure on these two, it looks like ASCII Encoding/Decoding
'whereas a String is converted into an Array of Bytes and
'vice versa

Posted by: Zepha Jun 13 2019, 02:25 AM

Thank you ADzeiI for your prompt reply. I will try to fix the codes you have given me and see if they can work. However, I have already tried to run the following simple VBA code to connect to the my Card Reader, but it returns a value of 6, which according to the constants refers to ERROR_INVALID_HANDLE

CODE
' API Functions

Public Declare Function SCardEstablishContext Lib "winscard.dll" (ByVal dwScope As Long, _
    ByVal pvReserved1 As Long, ByVal pvReserved2 As Long, ByRef phContext As Long) As Long

Public Declare Function SCardListReaders Lib "winscard.dll" Alias "SCardListReadersA" _
    (ByVal hContext As Long, ByVal mszGroups As String, ByVal mszReaders As String, _
    ByRef pcchReaders As Long) As Long



CODE
Sub GetContext()

    Dim lReturn As Long
    Dim RSVD1 As Long, RSVD2 As Long
    Dim myContext As Long

    lReturn = SCardEstablishContext(SCARD_SCOPE_USER, RSVD1, RSVD2, myContext)
    
    Debug.Print "SCardEstablishContext: Return =" & lReturn & _
                " myContext.CardContext1 = " & myContext & _
                " myContext.ReaderName = " & Chr(34) & myContext & Chr(34)

    Dim ListOfReaders As String, lenListOfReaders As Long

    lReturn = SCardListReaders(myContext, SCARD_DEFAULT_READERS, ListOfReaders, lenListOfReaders)

    Debug.Print "SCardListReaders: Return =" & lReturn & _
                " ListOfReaders = " & Chr(34) & ListOfReaders & Chr(34) & _
                " lenListOfReaders = " & lenListOfReaders

    lReturn = SCardReleaseContext(myContext)
    Debug.Print "SCardReleaseContext: Return =" & lReturn

End Sub


This has left me wondering what I can do. I am designing an application in Ms Access and that is why I am searching for VBA codes to read from and write to a Smart Card. The Internet is replete with codes in .Net or C#. My only problem is that I cannot translate the .Net codes like the ones I found on this website https://www.codeproject.com/Articles/16653/A-Smart-Card-Framework-for-NET to VBA. I highly appreciate any further help in this regard.




Posted by: cheekybuddha Jun 13 2019, 04:12 AM

Just skimming your code ...

Where have you defined SCARD_SCOPE_USER? What's the constant's value?

Do you know whether the code is 32bit/64bit ?

Posted by: Zepha Jun 13 2019, 04:34 AM

The constant is defined here below

CODE
Public Const SCARD_SCOPE_USER As Long = &H0


I believe the code is 32bit


Thanks

Posted by: cheekybuddha Jun 13 2019, 06:55 AM

I'm afraid I don't have a lot of time to look in to this now.

I think you have maybe already seen a lot of the https://duckduckgo.com/?q=SCardEstablishContext+vba&t=vivaldi&ia=web

The ones that caught my eye that might help you are:
https://stackoverflow.com/questions/39585362/getting-started-with-smartcard-iso-7816-in-excel-vba-scardestablishcontext
https://www.excelforum.com/excel-programming-vba-macros/1191020-how-can-i-show-the-results-of-the-following-code.html
https://bytes.com/topic/access/answers/949708-can-ms-access-interface-smart-cards
http://www.UtterAccess.com/forum/Acccess-Card-Readers-t1986575.html
https://docs.microsoft.com/en-us/windows/desktop/api/winscard/nf-winscard-scardestablishcontext

I hope someone else can jump in and offer assistance.

d

Posted by: Zepha Jun 13 2019, 07:08 AM


Thanks for the links you have provided. I will go through them and hopefully get useful guidance to help me achieve my purpose


Posted by: Zepha Jul 10 2019, 02:32 AM

I have searched all over the internet and I was able to get Codes for communicating with Smart Card Readers created in VB6 which I have modified to VBA. I am getting quite close to make it work and I hope that once I succeed, I shall share the Smart Card Ms Access Project here in the forum for use by other people who have had similar challenges. However, I have encountered another obstacle with the Code which calls the SCardEstablishContext API. When I searched again on Internet, I found this explanation:

SCardEstablishContext API is returning Service Not Available error (SCARD_E_NO_SERVICE) because it gets an Access Denied error when trying to open an event called "Global\Microsoft Smart Card Resource Manager Started" with OpenEvent API. The default security for that event on Vista and Windows 7 specifies that only SYSTEM, LOCAL SERVICE and INTERACTIVE users have access to it. NETWORK SERVICE or non-interactive users won’t be able to access the event.


A work around to grant users access to the event was proposed through some Code, which I think was written in C++. I tried to convert the Code to VB.Net through an online code translator, but I cannot proceed further to translate it to VBA. I am therefore requesting again for support from anyone here who can help me to translate the Code below to VBA.

CODE
Private Function _tmain(ByVal argc As Integer, ByVal argv() As _TCHAR) As Integer
        Dim result As DWORD = AddAceToObjectsSecurityDescriptor(_T("Global\Microsoft Smart Card Resource Manager Started"), SE_KERNEL_OBJECT, _T("Everyone"), TRUSTEE_IS_NAME, GENERIC_ALL, GRANT_ACCESS, NO_INHERITANCE)
        _tprintf(_T("Result = %d"& vbLf), result)
    End Function


The AddAceToObjectsSecurityDescriptor translated to VB.Net is as follows:

CODE
#
include
#
Dim DWORD As include(Of stdio.h)
AddAceToObjectsSecurityDescriptor(LPTSTR, pszObjName, SE_OBJECT_TYPE, ObjectType, LPTSTR, pszTrustee, TRUSTEE_FORM, TrusteeForm, DWORD, dwAccessRights, ACCESS_MODE, AccessMode, DWORD, dwInheritance)
{Dim dwRes As DWORD = 0
Dim pOldDACL As PACL = NULL
,pNewDACL = NULL
Dim pSD As PSECURITY_DESCRIPTOR = NULL
Dim ea As EXPLICIT_ACCESS
If (NULL = pszObjName) Then
    Return ERROR_INVALID_PARAMETER
End If

' Get a pointer to the existing DACL.
dwRes = GetNamedSecurityInfo(pszObjName, ObjectType, DACL_SECURITY_INFORMATION, NULL, NULL, pOldDACL, NULL, pSD)
If (ERROR_SUCCESS <> dwRes) Then
    printf("GetNamedSecurityInfo Error %u"& vbLf, dwRes)
    goto Cleanup
End If

' Initialize an EXPLICIT_ACCESS structure for the new ACE.
ZeroMemory(ea, sizeof, EXPLICIT_ACCESS)
ea.grfAccessPermissions = dwAccessRights
ea.grfAccessMode = AccessMode
ea.grfInheritance = dwInheritance
ea.Trustee.TrusteeForm = TrusteeForm
ea.Trustee.ptstrName = pszTrustee
' Create a new ACL that merges the new ACE
' into the existing DACL.
dwRes = SetEntriesInAcl(1, ea, pOldDACL, pNewDACL)
If (ERROR_SUCCESS <> dwRes) Then
    printf("SetEntriesInAcl Error %u"& vbLf, dwRes)
    goto Cleanup
End If

' Attach the new ACL as the object's DACL.
dwRes = SetNamedSecurityInfo(pszObjName, ObjectType, DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL)
If (ERROR_SUCCESS <> dwRes) Then
    printf("SetNamedSecurityInfo Error %u"& vbLf, dwRes)
    goto Cleanup
End If

Cleanup:
    If (pSD <> NULL) Then
        LocalFree(CType(pSD,HLOCAL))
    End If
    
    If (pNewDACL <> NULL) Then
        LocalFree(CType(pNewDACL,HLOCAL))
    End If
    
    Return dwRes
    Unknown


Thank you in advance


Zepha