1. Jason Schultz
  2. PowerBuilder
  3. Monday, 29 November 2021 23:15 PM UTC

Prior to posting this question, I did already refer to these two excellent articles/tutorials by Bruce Armstrong and John Fauss:

   - https://community.appeon.com/index.php/articles-blogs/tutorials-articles/2-powerbuilder/158-communication-with-a-smart-card-from-powerbuilder

   - https://community.appeon.com/index.php/articles-blogs/tutorials-articles/2-powerbuilder/305-interfacing-pb-applications-with-the-windows-api-part-4

Using Bruce's smart card sample application as a reference point, I took his sample application and wanted to experiment with it. For the most part, it runs out of the box. So far, the only thing I've had to tweak so far were the values passed with specific APDU calls used when verifying the PIN. This was expected since the call values may differ depending on the make/manufacturer of the smart card being used/referenced. Aside from that, the sample application runs fine in 32-bit mode (running from within my PB IDE - 2019R2). After creating a 64-bit .exe, I'm experiencing some issues trying to establish a connection with the card, which leads to my questions. I'm hoping someone can point me in the right direction on this, I feel that it's something obvious, and I'm just not seeing it. As of now, my primary questions refer to some of the API calls being made against the winscard.dll.

Although it would be ideal to reference the sample application code itself, hopefully I can properly frame my specific questions without it.

Within a non-visual object, the following is defined: 

Instance Variables:

protected ulong context
protected string reader
protected ulong	card
protected ulong	protocol

CONSTANT LONG SCARD_S_SUCCESS = 0
CONSTANT ULONG SCARD_SCOPE_USER = 0

CONSTANT INT SUCCESS 		= 1
CONSTANT INT FAILURE 		= -1

CONSTANT LONG SCARD_SHARE_SHARED = 2
CONSTANT LONG SCARD_PROTOCOL_Tx  = 3

 

Within Local External Functions, we have various method calls to the winscard.dll:

Protected Function ulong SCardEstablishContext  ( &
	Long dwScope, &
	long pvReserved1, &
	long pvReserved2, &
	REF ulong phContext &
	) Library "winscard.dll"

Protected Function ulong SCardConnect  ( &
	long hContext, &
	String szReader, &
	Long dwShareMode, &
	Long dwPreferredProtocols, &
	REF ulong phCard, &
	REF ulong pdwActiveProtocol &
	) Library "winscard.dll" Alias For "SCardConnectW"

 

Before attempting to connect to the card, we first need to establish a reference or handle to the card itself. We make the following call through a function called of_establishcontext(). This will populate the 'context' argument. 

ulong	rc

// We should get a return value of 0 for successful call.
rc = scardestablishcontext( SCARD_SCOPE_USER, 0, 0, context )

IF rc = SCARD_S_SUCCESS THEN
	Return SUCCESS
ELSE
	Return FAILURE
END IF

 

After a successful call (and context value is identified), we then attempt to connect to the card via the of_connectcard() function. Assume the passed in as_reader argument value is correct:

ulong	rc
reader = as_reader

rc = SCardConnect ( context, &
		 reader, &
		 SCARD_SHARE_SHARED, &
		 SCARD_PROTOCOL_Tx, &
		 card, &
		 protocol )

IF rc = SCARD_S_SUCCESS THEN
	Return SUCCESS
ELSE
	Return FAILURE
END IF

 

As mentioned before, the above code snippets work fine in 32-bit mode (either 32-bit .exe or run via PB IDE). The of_establishcontext() results in a return value of 0 (success), and the context value is populated with a value of 3439394816. The of_connectcard() is also successful.

When run in 64-bit mode (running a 64-bit .exe), the of_establishcontext() results in a return value of 0 (success), and the context value is populated with a value of 0. The of_connectcard() is unsuccessful with a return value of 6 (invalid handle error).  

This is where I'm at a loss. I'm trying to establish a valid handle to the card (via the context) to successfully connect to the card. As of now, I assume the same winscard.dll calls apply to both 32-bit and 64-bit. Here are the Microsoft definitions of the two API calls in question:

https://docs.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardestablishcontext

https://docs.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardconnectw

Using John's article on API calls, it served as a valuable reference in cross-referencing datatypes between external calls and PowerBuilder. I assume my problem is with the initial context value serving as a reference/pointer.  The Microsoft API refers to it as a LPSCardContext or SCardContext. I'm not sure what that relates to in PowerBuilder. In 32-bit, it works as a ulong. In 64-bit, I've tried referencing context as ulong, LongPTR, and LongLong. Unfortunately, I can't yet get any of them to work, still resulting in an invalid handle error when attempting to connect.

Any ideas on what I'm doing wrong?

I appreciate any input.

Thanks,
Jason  

 

Accepted Answer
John Fauss Accepted Answer Pending Moderation
  1. Tuesday, 30 November 2021 03:28 AM UTC
  2. PowerBuilder
  3. # Permalink

Hi, Jason - 

A few thoughts and observations...

Let me say at the start that I have NOT attempted any of these API calls myself, so I cannot say with 100% certainty the cause(s) of your issue(s). Let me also express my appreciation for the kind words about the PB/WinAPI tutorial.

If you have not already read Part 2 of the tutorial, I suggest you do so as it explains what changes are needed when you transition from a 32-bit app to a 64-bit app. In your specific case, all Windows handles and all pointers expand from 4-byte integers to 8-byte integers. The Longptr datatype is ideally suited in an external function declaration (EFD) instead of ULong, as it will auto-magically "expand" to the appropriate size when the app is compiled for 64-bit. Therefore, in the SCardEstablishContext API call, I believe the first argument should remain declared as ULong and the other three should be declared as Longptr's. For the SCardConnectW API call, the first argument (hContext, or handle to a Context value)  should be a Longptr and the next to last argument (phCard, or pointer to a handle to a Card value) should be a REF Longptr (in 64-bit, the 8-byte "reference" address (pointer) of an 8-byte Longptr handle will be passed).

I have verified there is indeed a 64-bit version of WinSCard.dll on my Windows 10 Pro home system. It resides in the C:\Windows\System32 folder. The 32-bit version resides in C:\Windows\SysWOW64).

I hope this information helps you. Good luck! -John

Comment
  1. Jason Schultz
  2. Tuesday, 30 November 2021 03:59 AM UTC
Thanks John.

I was just replying to Mark's input when I saw your feedback appear as well.

Using ProcessMonitor, I created a dump file and it appears my 64-bit .exe is referencing the correct file (c:\windows\system32\WinSCard.dll).

I'll take another look at Part II as you suggested, and I do think you are correct about using LongPTR. I've tried different combos throughout the local external function calls, but I might have missed something along the way (forest/trees syndrome). Thanks again for the suggestions, I'll be sure to provide any updates as necessary.
  1. Helpful
  1. John Fauss
  2. Tuesday, 30 November 2021 14:36 PM UTC
winscard.h defines the type definition for SCARDCONTEXT as ULONG_PTR, which translates to a Longptr in PB. In the code snippet you posted, you defined the variable named "context" as ULong... this works for 32-bit, but not for 64-bit. You would specify an API function call argument that is either PSCARDCONTEXT or LPSCARDCONTEXT (Pointer to an SCARDCONTEXT or Long Pointer to an SCARDCONTEXT, respectively) as "Ref Longptr" in an external function declaration.



The type definition for SCARDHANDLE is also ULONG_PTR, so the same discussion applies to it. The protocol is a Windows DWORD or PB ULong, just as you have it coded.



HTH
  1. Helpful 2
There are no comments made yet.
Jason Schultz Accepted Answer Pending Moderation
  1. Friday, 3 December 2021 21:58 PM UTC
  2. PowerBuilder
  3. # 1

I wanted to expand upon my initial question and reference a different set of API calls I'm having difficulty with (in regards to making them 64-bit compatible) - SCardTransmit(), which is also reliant on doing GetProcAddress() and FreeLibrary(). As mentioned in my original post, I'm referencing sample code that Bruce had posted and attempting to revise any external function declarations to ensure 64-bit compatibility. After going through several iterations of wash/rinse/repeat with these above three, I'm still having difficulty. I'll try to describe the necessary pieces (in their original state) :

PowerBuilder Structure Object: 

global type scard_io_request from structure
	unsignedlong		dwprotocol
	unsignedlong		dbpcilength
end type

 

Within n_cst_winscard object:

Instance variables: 

protected longptr card

Local External Functions Declarations (followed by it's corresponding Windows API definition):

 

Private Function ulong GetProcAddress ( &
ulong dllhandle, &
string procName &
) Library "kernel32.dll" Alias For "GetProcAddress;Ansi"

// Relates to:
/*

FARPROC GetProcAddress(
[in] HMODULE hModule,
[in] LPCSTR lpProcName
);

https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress

*/

Private SubRoutine FreeLibrary ( &
ulong dllhandle &
) Library "kernel32.dll"

// Relates to: 
/*

BOOL FreeLibrary(
[in] HMODULE hLibModule
);

https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-freelibrary

*/


// Two EFD for SCardTransmit):

Protected Function ulong SCardTransmit( &
longptr hCard, &
ulong pioSendPci, &
byte pbSendBuffer[], &
Long cbSendLength, &
ulong pioRecvPci, &
REF byte pbRecvBuffer[], &
REF long pcbRecvLength &
) Library "winscard.dll"

Protected Function ulong SCardTransmit( &
longptr hCard, &
scard_io_request pioSendPci, &
byte pbSendBuffer[], &
Long cbSendLength, &
REF scard_io_request pioRecvPci, &
REF byte pbRecvBuffer[], &
REF long pcbRecvLength &
) Library "winscard.dll"

// Relates to:
/*

LONG SCardTransmit(
[in] SCARDHANDLE hCard,
[in] LPCSCARD_IO_REQUEST pioSendPci,
[in] LPCBYTE pbSendBuffer,
[in] DWORD cbSendLength,
[in, out, optional] LPSCARD_IO_REQUEST pioRecvPci,
[out] LPBYTE pbRecvBuffer,
[in, out] LPDWORD pcbRecvLength
);

https://docs.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardtransmit

*/

 

Code snippet demonstrating how the API calls in questions are initiated within of_sendapdu( string apdu[] ): 

integer	i
ulong	rc
ulong	pioSendPci
ulong   dllhandle 
ulong   pci
byte	sendBuffer[]
byte 	pbRecvBuffer[]
long 	pcbRecvLength
long	cbSendLength
byte	getdata[5]
string	respSW1
string	respSW2

cbSendLength = UpperBound ( apdu )
FOR i = 1 TO cbSendLength
	sendBuffer[i] = of_hextobyte ( apdu[i] )
NEXT

pcbRecvLength = 2
FOR i = 1 TO pcbRecvLength
	pbRecvBuffer[i] = 0 ;
NEXT

dllhandle = LoadLibrary ( "WinSCard.dll" ) ;
pioSendPci = GetProcAddress ( dllhandle, "g_rgSCardT0Pci" ) ;
FreeLibrary(dllhandle) ;

rc = SCardTransmit ( card, &
  	pioSendPci, &
	sendBuffer, &
  	cbSendLength, &
  	0, &
  	pbRecvBuffer, &
 	pcbRecvLength )

IF rc <> scard_s_success THEN 
	return ""
END IF

respSW1 = of_bytetohex ( pbRecvBuffer[1] )
respSW2 = of_bytetohex ( pbRecvBuffer[2] )

//This means there is more data to come
IF respSW1 = "61" THEN
	getdata[1] = of_hextobyte ( "00" )
	getdata[2] = of_hextobyte ( "C0" )
	getdata[3] = of_hextobyte ( "00" )
	getdata[4] = of_hextobyte ( "00" )
	getdata[5] = pbRecvBuffer[2]

	cbSendLength = 5
	
	pcbRecvLength = pbRecvBuffer[2] + 2 // We need two extra bytes for the status bits
	FOR i = 1 TO pcbRecvLength
		pbRecvBuffer[i] = 0 ;
	NEXT

	rc = SCardTransmit ( card, &
		pioSendPci, &
		getdata, &
		cbSendLength, &
		0, &
		pbRecvBuffer, &
		pcbRecvLength )

	IF rc <> SCARD_S_SUCCESS THEN Return ""

	respSW1 = of_bytetohex ( pbRecvBuffer[pcbRecvLength - 1] )
	respSW2 = of_bytetohex ( pbRecvBuffer[pcbRecvLength] )
END IF

Return respSW1 + respSW2

 Sorry for all the copy/paste. I wanted to properly demonstrate how some of the calls in question are made, as well as reference to pieces that contribute to the GetProcAddress(), FreeLibrary(), and SCardTransmit() calls. The most challenging part of these API calls is not only properly cross-referencing the PB reference to the appropriate c++/Windows reference, but also identifying those that truly need to be reassigned. It's not always an apples to apples translation, nor does it appear to be consistent at times. Again, thanks for any input.

 

Comment
  1. John Fauss
  2. Saturday, 4 December 2021 05:16 AM UTC
I provided you a few days ago with some suggestions in regards to the SCardTransmit API call, which you apparently did not see (it's above Bruce's comment), so rather than retyping it here I will simply suggest you scan this thread for it. As for GetProcAddress and FreeLibrary, personally, I always search for examples first that use the API functions I'm interested in, and a terrific resource that is my first "go to" is Roland Smith's TopWixProgramming.com web site free code samples. In regards to these two API functions, his IconTray sample app happens to call them, so download, try out, then study his sample app to see what you can learn from it. Good luck!
  1. Helpful 1
  1. Jason Schultz
  2. Monday, 6 December 2021 15:04 PM UTC
John,

Yes, I missed it - sorry for the redundancy. Your additional suggestion of checking out Roland's site/sample code was helpful, and a great resource. I discovered I was missing a ulong to longptr reference on LoadLibrary (in addition to the return value), so I think that was the culprit. Feeling stupid now... Thanks again!
  1. Helpful
  1. John Fauss
  2. Tuesday, 7 December 2021 02:40 AM UTC
No problem. Glad to have helped! If you have additional questions, please post them in separate posts so that others can search for and more easily find them.
  1. Helpful 1
There are no comments made yet.
Jason Schultz Accepted Answer Pending Moderation
  1. Tuesday, 30 November 2021 17:34 PM UTC
  2. PowerBuilder
  3. # 2

I wanted to provide an update and share the solution.

John provided some insight in one of his responses (tagged as Answer).

Thanks to all who provided feedback.

I made the following changes:


Instance variables (both changed from ulong to LongPTR):

protected longptr context
protected longptr card


Within the external function declarations:

Within SCardEstablishContext(), pvReserved1, pvReserved2, and phContext all changed to longptr.

Within SCardConnect(), hContext and phCard changed to longptr. 

Protected Function ulong SCardEstablishContext ( &
   ulong dwScope, &
   longptr pvReserved1, &
   longptr pvReserved2, &
   REF longptr phContext &
) Library "winscard.dll"

Protected Function ulong SCardConnect ( &
   longptr hContext, &
   String szReader, &
   Long dwShareMode, &
   Long dwPreferredProtocols, &
   REF longptr phCard, &
   REF ulong pdwActiveProtocol &
) Library "winscard.dll" Alias For "SCardConnectW"

I think when I had originally tried changing ulong to longptr, I was strictly focused on changing it for 'hContext', and neglected to change the 'phCard' parameter, causing the SCardConnect() to still fail.

I'm still in the process of making additional tweaks as I encounter any errors.
Currently looking into an external function declaration that contains byte arrays. This is where I need to refer to John's WIN API guide Parts 2 and 4.

Example:

Protected Function ulong SCardTransmit( &
   longptr hCard, &
   scard_io_request pioSendPci, &
   byte pbSendBuffer[], &
   Long cbSendLength, &
   REF scard_io_request pioRecvPci, &
   REF byte pbRecvBuffer[], &
   REF long pcbRecvLength &
) Library "winscard.dll"


// The Microsoft reference for this API call is as follows:

LONG SCardTransmit(
   [in] SCARDHANDLE hCard,
   [in] LPCSCARD_IO_REQUEST pioSendPci,
   [in] LPCBYTE pbSendBuffer,
   [in] DWORD cbSendLength,
   [in, out, optional] LPSCARD_IO_REQUEST pioRecvPci,
   [out] LPBYTE pbRecvBuffer,
   [in, out] LPDWORD pcbRecvLength
);

According to Part 4, byte arrays equate to Blob in PowerBuilder. I may also need to expand any of the array contents (I believe Part 2 talks about this). Research pending. Again, thanks for all the excellent feedback! 

Jason

Comment
  1. Bruce Armstrong
  2. Friday, 10 December 2021 03:58 AM UTC
Further update. I've got validate PIN working in 64 bit. It looks like the issue is trying to pass a null to that pioRecvPci argument. If you declare it as long and pass 0 PowerBuilder sends a null to that argument. It looks like something else is happening in 64 bit though.



What I did is created a scard_io_request as follows:



global type scard_io_request from structure

long dwprotocol

long dbpcilength

end type



Then instead of using the LoadLibrary and ProcAddress to get a pci, I created it as follows:



scard_io_request pci

pci.dwprotocol = protocol

pci.dbpcilength = 8



Modify the SCardTransmit to take the structure for the data in and out:



Protected Function ulong SCardTransmit( &

longptr hCard, &

scard_io_request pioSendPci, &

byte pbSendBuffer[], &

Long cbSendLength, &

REF scard_io_request pioRecvPci, &

REF byte pbRecvBuffer[], &

REF long pcbRecvLength &

) Library "winscard.dll"



And then when I want to send an apdu I create two pci bojects (one for send and recieve) and pass then in the SCardTransmit)



I've still got some pointer issues with the functions that pull the data off the cac, like the dsn name. When I get that all resolved I'll update the blog article once more.







  1. Helpful 1
  1. Jason Schultz
  2. Friday, 10 December 2021 14:14 PM UTC
Thanks for follow-up Bruce. In order to get the 64-bit Read Certificate working, most of the local external functions in n_cst_winscard needed to be tweaked a bit how you described (pointers and handles needing to change from ulong to longptr, as well as some long to ulong). I currently have both Verify and Read Certificate working in 64-bit, but there are some underlying issues I'm trying to resolve. In both 32 and 64 bit, the Issue date and expiration date read are not correct (crazy datetime values instead). Obviously, changing some datatypes caused this, trying to determine where things are amiss in/around of_copycertcontext().



-
  1. Helpful
  1. Bruce Armstrong
  2. Monday, 27 December 2021 03:21 AM UTC
I've got everything working now. I just posted sample code in CodeXchange at: https://community.appeon.com/index.php/codeexchange/powerbuilder/306-reading-a-smard-card-from-powerbuilder. It's probably easier to access that and see what I changed.
  1. Helpful 3
There are no comments made yet.
Mark Goldsmith Accepted Answer Pending Moderation
  1. Tuesday, 30 November 2021 02:18 AM UTC
  2. PowerBuilder
  3. # 3

Hi Jason,

I understand that you may have tried this already but I do believe the correct data type for hContext in a 64 bit application is Longptr.

You should also check as to whether WinSCard.dll exists in C:\Windows\System32 (and it's C:\Windows\SysWOW64 for a 32 bit app, but I suspect it's there and registered since the 32 bit app is working for you). If it's not then I think that may be the source of your problem. I'm pretty sure that WinSCard.dll is not a 3rd party DLL, it's provided by Microsoft as part of the OS.

HTH...regards,

Mark

Comment
  1. Jason Schultz
  2. Tuesday, 30 November 2021 03:48 AM UTC
Hi Mark,

Thanks for the input. When running my .exe and also running ProcessExplorer, I created a dump file and it specifies the WinSCard.dll as the 64-bit version being referenced (residing in c:\windows\system32). It also doesn't appear to be register-able (if that's a word). I assume because it's not a 3rd party .dll and appears to be part of Windows API. I suspected LongPTR was the correct datatype for 64-bit, will take another crack at it.

Thanks!
  1. Helpful
  1. Mark Goldsmith
  2. Tuesday, 30 November 2021 18:28 PM UTC
You're welcome Jason and glad to see, from your other follow-up posts, that you now have this resolved.
  1. Helpful
There are no comments made yet.
Jason Schultz Accepted Answer Pending Moderation
  1. Tuesday, 30 November 2021 01:38 AM UTC
  2. PowerBuilder
  3. # 4

Thanks for the suggestions. Out of curiosity, is there a quick/dirty way of identifying which version of the winscard.dll is being used during runtime?  I'll also check out the migration guide that Armeen mentioned to review those topics as well.

Thanks,
Jason 

Comment
There are no comments made yet.
Chris Pollach @Appeon Accepted Answer Pending Moderation
  1. Tuesday, 30 November 2021 00:10 AM UTC
  2. PowerBuilder
  3. # 5

Hi Jason;

   Do you have a 64bit version of the winscard.dll? If not, your 64 bit PB app would never work.

Regards ... Chris

Comment
  1. Armeen Mazda @Appeon
  2. Tuesday, 30 November 2021 00:18 AM UTC
Adding to what Chris said, generally speaking you can't simple take 32-bit app and recompile into 64-bit. We created migration guide because so many customers make this wrong assumption. https://docs.appeon.com/pb2021/migrating_32bit_applications_to_64bit/index.html
  1. Helpful
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.