/*++ Copyright (C) Microsoft Corporation, 1996 - 1999 Module Name: WinSCard Abstract: This module supplies the UNICODE version of the API for the Calais Smartcard Service Manager. The Calais Service Manager does the work of coordinating the protocols, readers, drivers, and smartcards on behalf of the application. The following services are provided as part of a library to simplify access to the Service Manager. These routines are the documented, exposed APIs. These routines merely package the requests and forward them to the Calais Service Manager, allowing the actual implementation of Calais to vary over time. At no time does the API library make security decisions. All security-related functions must be performed by the Service Manager, running in its own address space, or in the operating system kernel. However, some utility routines may be implemented in the API library for speed, as long as they do not involve security decisions. Author: Doug Barlow (dbarlow) 10/23/1996 Environment: Win32, C++ w/ Exceptions Notes: ?Notes? --*/ #define __SUBROUTINE__ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include "client.h" #include "redirect.h" extern HANDLE g_hUnifiedStartedEvent; // //////////////////////////////////////////////////////////////////////////////// // // Calais Database Query Services // // These services all are oriented towards reading the Calais database. // They provide the option for listing a Smartcard Context (see Section // 4.1.1), but do not require one. Note that without a context, some or // all information may be inaccessable due to security restrictions. // /*++ SCardListReaderGroups: This service provides the list of named card reader groups that have previously been defined to the system. The group 'SCard$DefaultReaders' is only returned if it contains at least one reader. The group 'SCard$AllReaders' is not returned, as it implicitly exists. Arguments: hContext supplies the handle identifying the Service Manager Context established previously via the SCardEstablishContext() service, or is NULL if this query is not directed towards a specific context. mszGroups receives a multi-string listing the reader groups defined to this system and available to the current user on the current terminal. If this value is NULL, the supplied buffer length in pcchGroups is ignored, the length of the buffer that would have been returned had this parameter not been null is written to pcchGroups, and a success code is returned. pcchGroups supplies the length of the mszGroups buffer in characters, and receives the actual length of the multi-string structure, including all trailing Null characters. If the buffer length is specified as SCARD_AUTOALLOCATE, then szGroups is converted to a pointer to a string pointer, and receives the address of a block of memory containing the multi-string structure. This block of memory must be deallocated via the SCardFreeMemory() service. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/23/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardListReaderGroupsW") WINSCARDAPI LONG WINAPI SCardListReaderGroupsW( IN SCARDCONTEXT hContext, OUT LPWSTR mszGroups, IN OUT LPDWORD pcchGroups) { LONG nReturn = SCARD_S_SUCCESS; try { CSCardUserContext *pCtx = NULL; DWORD dwScope = SCARD_SCOPE_SYSTEM; CBuffer bfGroups; SCARDCONTEXT hRedirContext = NULL; if (NULL != hContext) { pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); if (pCtx->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } dwScope = pCtx->Scope(); hRedirContext = pCtx->GetRedirContext(); } if (hRedirContext || InTSRedirectMode()) { if (!TS_REDIRECT_READY) { throw (DWORD)SCARD_E_NO_SERVICE; } nReturn = pfnSCardListReaderGroupsW(hRedirContext, mszGroups, pcchGroups); } else { ListReaderGroups(dwScope, bfGroups); PlaceMultiResult(pCtx, bfGroups, mszGroups, pcchGroups); } } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardListReaders: This service provides the list of readers within a set of named reader groups, eliminating duplicates. The caller supplies a multistring listing the name of a set of pre-defined group of readers, and receives the list of smartcard readers within the named groups. Unrecognized group names are ignored. Arguments: hContext supplies the handle identifying the Service Manager Context established previously via the SCardEstablishContext() service, or is NULL if this query is not directed towards a specific context. mszGroups supplies the names of the reader groups defined to the system, as a multi-string. A NULL value is used to indicate that all readers in the system be listed (i.e., the SCard$AllReaders group). mszReaders receives a multi-string listing the card readers within the supplied reader groups. If this value is NULL, the supplied buffer length in pcchReaders is ignored, the length of the buffer that would have been returned had this parameter not been null is written to pcchReaders, and a success code is returned. pcchReaders supplies the length of the mszReaders buffer in characters, and receives the actual length of the multi-string structure, including all trailing Null characters. If the buffer length is specified as SCARD_AUTOALLOCATE, then mszReaders is converted to a pointer to a string pointer, and receives the address of a block of memory containing the multi-string structure. This block of memory must be deallocated via the SCardFreeMemory() service. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/23/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardListReadersW") WINSCARDAPI LONG WINAPI SCardListReadersW( IN SCARDCONTEXT hContext, IN LPCWSTR mszGroups, OUT LPWSTR mszReaders, IN OUT LPDWORD pcchReaders) { LONG nReturn = SCARD_S_SUCCESS; try { CSCardUserContext *pCtx = NULL; DWORD dwScope = SCARD_SCOPE_SYSTEM; CBuffer bfReaders; CTextMultistring mtzGroups; SCARDCONTEXT hRedirContext = NULL; if (NULL != hContext) { pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); if (pCtx->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } dwScope = pCtx->Scope(); hRedirContext = pCtx->GetRedirContext(); } if (hRedirContext || InTSRedirectMode()) { if (!TS_REDIRECT_READY) { throw (DWORD)SCARD_E_NO_SERVICE; } nReturn = pfnSCardListReadersW(hRedirContext, mszGroups, mszReaders, pcchReaders); } else { mtzGroups = mszGroups; ListReaders(dwScope, mtzGroups, bfReaders); if (NULL != pCtx) pCtx->StripInactiveReaders(bfReaders); PlaceMultiResult(pCtx, bfReaders, mszReaders, pcchReaders); } } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardListCards: This service provides a list of named cards previously introduced to the system by this user which match an optionally supplied ATR string. Arguments: hContext supplies the handle identifying the Service Manager Context established previously via the SCardEstablishContext() service, or is NULL if this query is not directed towards a specific context. pbAtr supplies the address of an ATR string to compare to known cards, or NULL if all card names are to be returned. rgguidInterfaces supplies an array of GUIDs, or the value NULL. When an array is supplied, a card name will be returned only if this set of GUIDs is a (possibly improper) subset of the set of GUIDs supported by the card. cguidInterfaceCount supplies the number of entries in the rgguidInterfaces array. If rgguidInterfaces is NULL, then this value is ignored. mszCards receives a multi-string listing the smartcards introduced to the system by this user which match the supplied ATR string. If this value is NULL, the supplied buffer length in pcchCards is ignored, the length of the buffer that would have been returned had this parameter not been null is written to pcchCards, and a success code is returned. pcchCards supplies the length of the mszCards buffer in characters, and receives the actual length of the multi-string structure, including all trailing Null characters. If the buffer length is specified as SCARD_AUTOALLOCATE, then mszCards is converted to a pointer to a string pointer, and receives the address of a block of memory containing the multi-string structure. This block of memory must be deallocated via he SCardFreeMemory() service. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/23/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardListCardsW") WINSCARDAPI LONG WINAPI SCardListCardsW( IN SCARDCONTEXT hContext, IN LPCBYTE pbAtr, IN LPCGUID rgquidInterfaces, IN DWORD cguidInterfaceCount, OUT LPWSTR mszCards, IN OUT LPDWORD pcchCards) { LONG nReturn = SCARD_S_SUCCESS; try { DWORD dwScope = SCARD_SCOPE_SYSTEM; CBuffer bfCards; CSCardUserContext *pCtx = NULL; if (NULL != hContext) { pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); dwScope = pCtx->Scope(); } ListCards( dwScope, pbAtr, rgquidInterfaces, cguidInterfaceCount, bfCards); PlaceMultiResult(pCtx, bfCards, mszCards, pcchCards); } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardListInterfaces: This service provides a list of interfaces known to be supplied by a given card. The caller supplies the name of a smartcard previously introduced to the system, and receives the list of interfaces supported by the card. Arguments: hContext supplies the handle identifying the Service Manager Context established previously via the SCardEstablishContext() service, or is NULL if this query is not directed towards a specific context. szCard supplies the name of the card defined to the system. pguidInterfaces receives an array of GUIDs indicating the interfaces supported by the named smartcard. If this value is NULL, the supplied array length in pcguidInterfaces is ignored, the size of the array that would have been returned had this parameter not been null is written to pcguidInterfaces, and a success code is returned. pcguidInterfaces supplies the size of the pguidInterfaces array, and receives the actual size of the returned array. If the array size is specified as SCARD_AUTOALLOCATE, then pguidInterfaces is converted to a pointer to a GUID pointer, and receives the address of a block of memory containing the array. This block of memory must be deallocated via he SCardFreeMemory() service. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/23/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardListInterfacesW") WINSCARDAPI LONG WINAPI SCardListInterfacesW( IN SCARDCONTEXT hContext, IN LPCWSTR szCard, OUT LPGUID pguidInterfaces, IN OUT LPDWORD pcguidInterfaces) { LONG nReturn = SCARD_S_SUCCESS; try { BOOL fSts; CTextString tzCard; DWORD dwScope = SCARD_SCOPE_SYSTEM; DWORD cbInterfaces; CBuffer bfInterfaces; CSCardUserContext *pCtx = NULL; if (NULL != hContext) { pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); dwScope = pCtx->Scope(); } tzCard = szCard; fSts = GetCardInfo( dwScope, tzCard, NULL, NULL, &bfInterfaces, NULL); if (!fSts) throw (DWORD)SCARD_E_UNKNOWN_CARD; if (SCARD_AUTOALLOCATE == *pcguidInterfaces) cbInterfaces = SCARD_AUTOALLOCATE; else cbInterfaces = *pcguidInterfaces * sizeof(GUID); PlaceResult( pCtx, bfInterfaces, (LPBYTE)pguidInterfaces, &cbInterfaces); *pcguidInterfaces = cbInterfaces / sizeof(GUID); } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardGetProviderId: This service returns the GUID of the Primary Service Provider for the given card. The caller supplies the name of a smartcard previously introduced to the system, and receives the registered Primary Service Provider GUID, if any. Arguments: hContext supplies the handle identifying the Service Manager Context established previously via the SCardEstablishContext() service, or is NULL if this query is not directed towards a specific context. szCard supplies the name of the card defined to the system. pguidInterfaces receives the GUID of the Primary Service Provider of the indicated card. This provider may be activated via COM, and will supply access to other services in the card. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/23/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardGetProviderIdW") WINSCARDAPI LONG WINAPI SCardGetProviderIdW( IN SCARDCONTEXT hContext, IN LPCWSTR szCard, OUT LPGUID pguidProviderId) { LONG nReturn = SCARD_S_SUCCESS; try { BOOL fSts; CTextString tzCard; DWORD dwScope = SCARD_SCOPE_SYSTEM; CBuffer bfProvider; if (NULL != hContext) { CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); dwScope = pCtx->Scope(); } tzCard = szCard; fSts = GetCardInfo( dwScope, tzCard, NULL, NULL, NULL, &bfProvider); if (!fSts) throw (DWORD)SCARD_E_UNKNOWN_CARD; if (sizeof(GUID) != bfProvider.Length()) throw (DWORD)SCARD_E_INVALID_TARGET; CopyMemory(pguidProviderId, bfProvider.Access(), bfProvider.Length()); } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardGetCardTypeProviderName: This service returns the value of a given Provider Name, by Id number, for the identified card type. The caller supplies the name of a smartcard previously introduced to the system, and receives the registered Service Provider of that type, if any, as a string. Arguments: hContext supplies the handle identifying the Service Manager Context established previously via the SCardEstablishContext() service, or is NULL if this query is not directed towards a specific context. szCardName supplies the name of the card type with which this provider name is associated. dwProviderId supplies the identifier for the provider associated with this card type. Possible values are: SCARD_PROVIDER_SSP - The Primary SSP identifier, as a GUID string. SCARD_PROVIDER_CSP - The CSP name. Other values < 0x80000000 are reserved for use by Microsoft. Values over 0x80000000 are available for use by the smart card vendors, and are card-specific. szProvider receives the string identifying the provider. pcchProvider supplies the length of the szProvider buffer in characters, and receives the actual length of the returned string, including the trailing null character. If the buffer length is specified as SCARD_AUTOALLOCATE, then szProvider is converted to a pointer to a string pointer, and receives the address of a block of memory containing the string. This block of memory must be deallocated via the SCardFreeMemory() service. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Throws: Errors as DWORD status codes Author: Doug Barlow (dbarlow) 1/19/1998 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardGetCardTypeProviderNameW") WINSCARDAPI LONG WINAPI SCardGetCardTypeProviderNameW( IN SCARDCONTEXT hContext, IN LPCWSTR szCardName, IN DWORD dwProviderId, OUT LPWSTR szProvider, IN OUT LPDWORD pcchProvider) { LONG nReturn = SCARD_S_SUCCESS; try { DWORD dwScope = SCARD_SCOPE_SYSTEM; CTextString tzCardName; CBuffer bfProvider; CSCardUserContext *pCtx = NULL; if (NULL != hContext) { pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); dwScope = pCtx->Scope(); } tzCardName = szCardName; GetCardTypeProviderName( dwScope, tzCardName, dwProviderId, bfProvider); PlaceResult(pCtx, bfProvider, szProvider, pcchProvider); } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } // //////////////////////////////////////////////////////////////////////////////// // // Calais Database Management Services // // The following services provide for managing the Calais Database. These // services actually update the database, and require a smartcard context. // /*++ SCardIntroduceReaderGroup: This service provides means for introducing a new smartcard reader group to Calais. Arguments: hContext supplies the handle identifying the Service Manager Context, which must have been previously established via the SCardEstablishContext() service. szGroupName supplies the friendly name to be assigned to the new reader group. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/25/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardIntroduceReaderGroupW") WINSCARDAPI LONG WINAPI SCardIntroduceReaderGroupW( IN SCARDCONTEXT hContext, IN LPCWSTR szGroupName) { LONG nReturn = SCARD_S_SUCCESS; try { CTextString tzGroupName; CSCardUserContext *pCtx = NULL; DWORD dwScope = SCARD_SCOPE_SYSTEM; SCARDCONTEXT hRedirContext = NULL; if (NULL != hContext) { pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); if (pCtx->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } dwScope = pCtx->Scope(); hRedirContext = pCtx->GetRedirContext(); } if (hRedirContext || InTSRedirectMode()) { if (!TS_REDIRECT_READY) { throw (DWORD)SCARD_E_NO_SERVICE; } nReturn = pfnSCardIntroduceReaderGroupW(hRedirContext, szGroupName); } else { tzGroupName = szGroupName; IntroduceReaderGroup( dwScope, tzGroupName); } } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardForgetReaderGroup: This service provides means for removing a previously defined smartcard reader group from the Calais Subsystem. This service automatically clears all readers from the group before forgetting it. It does not affect the existence of the readers in the database. Arguments: hContext supplies the handle identifying the Service Manager Context, which must have been previously established via the SCardEstablishContext() service. szGroupName supplies the friendly name of the reader group to be forgotten. The Calais-defined default reader groups may not be forgotten. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/25/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardForgetReaderGroupW") WINSCARDAPI LONG WINAPI SCardForgetReaderGroupW( IN SCARDCONTEXT hContext, IN LPCWSTR szGroupName) { LONG nReturn = SCARD_S_SUCCESS; try { CTextString tzGroupName; CSCardUserContext *pCtx = NULL; DWORD dwScope = SCARD_SCOPE_SYSTEM; SCARDCONTEXT hRedirContext = NULL; if (NULL != hContext) { pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); if (pCtx->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } dwScope = pCtx->Scope(); hRedirContext = pCtx->GetRedirContext(); } if (hRedirContext || InTSRedirectMode()) { if (!TS_REDIRECT_READY) { throw (DWORD)SCARD_E_NO_SERVICE; } nReturn = pfnSCardForgetReaderGroupW(hRedirContext, szGroupName); } else { tzGroupName = szGroupName; ForgetReaderGroup( dwScope, tzGroupName); } } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardIntroduceReader: This service provides means for introducing an existing smartcard reader device to Calais. Once introduced, Calais will assume responsibility for managing access to that reader. Arguments: hContext supplies the handle identifying the Service Manager Context, which must have been previously established via the SCardEstablishContext() service. szReaderName supplies the friendly name to be assigned to the reader. SzDeviceName supplies the system name of the smartcard reader device. (Example: "VendorX ModelY Z".) Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/25/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardIntroduceReaderW") WINSCARDAPI LONG WINAPI SCardIntroduceReaderW( IN SCARDCONTEXT hContext, IN LPCWSTR szReaderName, IN LPCWSTR szDeviceName) { LONG nReturn = SCARD_S_SUCCESS; try { CTextString tzReaderName; CTextString tzDeviceName; CSCardUserContext *pCtx = NULL; DWORD dwScope = SCARD_SCOPE_SYSTEM; SCARDCONTEXT hRedirContext = NULL; if (NULL != hContext) { pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); if (pCtx->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } dwScope = pCtx->Scope(); hRedirContext = pCtx->GetRedirContext(); } if (hRedirContext || InTSRedirectMode()) { if (!TS_REDIRECT_READY) { throw (DWORD)SCARD_E_NO_SERVICE; } nReturn = pfnSCardIntroduceReaderW(hRedirContext, szReaderName, szDeviceName); } else { tzReaderName = szReaderName; tzDeviceName = szDeviceName; IntroduceReader( dwScope, tzReaderName, tzDeviceName); } } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardForgetReader: This service provides means for removing previously defined smartcard readers from control by the Calais Subsystem. It is automatically removed from any groups it may have been added to. Arguments: hContext supplies the handle identifying the Service Manager Context, which must have been previously established via the SCardEstablishContext() service. szReaderName supplies the friendly name of the reader to be forgotten. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/25/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardForgetReaderW") WINSCARDAPI LONG WINAPI SCardForgetReaderW( IN SCARDCONTEXT hContext, IN LPCWSTR szReaderName) { LONG nReturn = SCARD_S_SUCCESS; try { CTextString tzReaderName; CSCardUserContext *pCtx = NULL; DWORD dwScope = SCARD_SCOPE_SYSTEM; SCARDCONTEXT hRedirContext = NULL; if (NULL != hContext) { pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); if (pCtx->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } dwScope = pCtx->Scope(); hRedirContext = pCtx->GetRedirContext(); } if (hRedirContext || InTSRedirectMode()) { if (!TS_REDIRECT_READY) { throw (DWORD)SCARD_E_NO_SERVICE; } nReturn = pfnSCardForgetReaderW(hRedirContext, szReaderName); } else { tzReaderName = szReaderName; ForgetReader( dwScope, tzReaderName); } } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardAddReaderToGroup: This service provides means for adding existing an reader into an existing reader group. Arguments: hContext supplies the handle identifying the Service Manager Context, which must have been previously established via the SCardEstablishContext() service. szReaderName supplies the friendly name of the reader to be added. szGroupName supplies the friendly name of the group to which the reader should be added. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/25/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardAddReaderToGroupW") WINSCARDAPI LONG WINAPI SCardAddReaderToGroupW( IN SCARDCONTEXT hContext, IN LPCWSTR szReaderName, IN LPCWSTR szGroupName) { LONG nReturn = SCARD_S_SUCCESS; try { CTextString tzReaderName; CTextString tzGroupName; CSCardUserContext *pCtx = NULL; DWORD dwScope = SCARD_SCOPE_SYSTEM; SCARDCONTEXT hRedirContext = NULL; if (NULL != hContext) { pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); if (pCtx->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } dwScope = pCtx->Scope(); hRedirContext = pCtx->GetRedirContext(); } if (hRedirContext || InTSRedirectMode()) { if (!TS_REDIRECT_READY) { throw (DWORD)SCARD_E_NO_SERVICE; } nReturn = pfnSCardAddReaderToGroupW(hRedirContext, szReaderName, szGroupName); } else { tzReaderName = szReaderName; tzGroupName = szGroupName; AddReaderToGroup( dwScope, tzReaderName, tzGroupName); } } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardRemoveReaderFromGroup: This service provides means for removing an existing reader from an existing reader group. It does not affect the existence of either the reader or the group in the Calais database. Arguments: hContext supplies the handle identifying the Service Manager Context, which must have been previously established via the SCardEstablishContext() service. szReaderName supplies the friendly name of the reader to be removed. szGroupName supplies the friendly name of the group to which the reader should be removed. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/25/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardRemoveReaderFromGroupW") WINSCARDAPI LONG WINAPI SCardRemoveReaderFromGroupW( IN SCARDCONTEXT hContext, IN LPCWSTR szReaderName, IN LPCWSTR szGroupName) { LONG nReturn = SCARD_S_SUCCESS; try { CTextString tzReaderName; CTextString tzGroupName; CSCardUserContext *pCtx = NULL; DWORD dwScope = SCARD_SCOPE_SYSTEM; SCARDCONTEXT hRedirContext = NULL; if (NULL != hContext) { pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); if (pCtx->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } dwScope = pCtx->Scope(); hRedirContext = pCtx->GetRedirContext(); } if (hRedirContext || InTSRedirectMode()) { if (!TS_REDIRECT_READY) { throw (DWORD)SCARD_E_NO_SERVICE; } nReturn = pfnSCardRemoveReaderFromGroupW(hRedirContext, szReaderName, szGroupName); } else { tzReaderName = szReaderName; tzGroupName = szGroupName; RemoveReaderFromGroup( dwScope, tzReaderName, tzGroupName); } } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardIntroduceCardType: This service provides means for introducing new smartcards to the Calais Subsystem for the active user. Arguments: hContext supplies the handle identifying the Service Manager Context, which must have been previously established via the SCardEstablishContext() service. szCardName supplies the name by which the user can recognize this card. PguidPrimaryProvider supplies a pointer to a GUID used to identify the Primary Service Provider for the card. rgguidInterfaces supplies an array of GUIDs identifying the smartcard interfaces supported by this card. dwInterfaceCount supplies the number of GUIDs in the pguidInterfaces array. pbAtr supplies a string against which card ATRs will be compared to determine a possible match for this card. The length of this string is determined by normal ATR parsing. pbAtrMask supplies an optional bitmask to use when comparing the ATRs of smartcards to the ATR supplied in pbAtr. If this value is non-NULL, it must point to a string of bytes the same length as the ATR string supplied in pbAtr. Then when a given ATR A is compared to the ATR supplied in pbAtr B, it matches if and only if A & M = B, where M is the supplied mask, and & represents bitwise logical AND. cbAtrLen supplies the length of the ATR and Mask. This value may be zero if the lentgh is obvious from the ATR. However, it may be required if there is a Mask value that obscures the actual ATR. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/23/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardIntroduceCardTypeW") WINSCARDAPI LONG WINAPI SCardIntroduceCardTypeW( IN SCARDCONTEXT hContext, IN LPCWSTR szCardName, IN LPCGUID pguidPrimaryProvider, IN LPCGUID rgguidInterfaces, IN DWORD dwInterfaceCount, IN LPCBYTE pbAtr, IN LPCBYTE pbAtrMask, IN DWORD cbAtrLen) { LONG nReturn = SCARD_S_SUCCESS; try { CTextString tzCardName; DWORD dwScope = SCARD_SCOPE_SYSTEM; if (NULL != hContext) { CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); dwScope = pCtx->Scope(); } tzCardName = szCardName; IntroduceCard( dwScope, tzCardName, pguidPrimaryProvider, rgguidInterfaces, dwInterfaceCount, pbAtr, pbAtrMask, cbAtrLen); } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardSetCardTypeProviderName: This service provides means for adding additional service providers to a specified card type. Arguments: hContext supplies the handle identifying the Service Manager Context, which must have been previously established via the SCardEstablishContext() service. szCardName supplies the name of the card type with which this provider name is to be associated. dwProviderId supplies the identifier for the provider to be associated with this card type. Possible values are: SCARD_PROVIDER_SSP - The Primary SSP identifier, as a GUID string. SCARD_PROVIDER_CSP - The CSP name. Other values < 0x80000000 are reserved for use by Microsoft. Values over 0x80000000 are available for use by the smart card vendors, and are card-specific. szProvider supplies the string identifying the provider. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 1/19/1998 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardSetCardTypeProviderNameW") WINSCARDAPI LONG WINAPI SCardSetCardTypeProviderNameW( IN SCARDCONTEXT hContext, IN LPCWSTR szCardName, IN DWORD dwProviderId, IN LPCWSTR szProvider) { LONG nReturn = SCARD_S_SUCCESS; try { CTextString tzCardName; CTextString tzProvider; DWORD dwScope = SCARD_SCOPE_SYSTEM; if (NULL != hContext) { CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); dwScope = pCtx->Scope(); } tzCardName = szCardName; tzProvider = szProvider; SetCardTypeProviderName( dwScope, tzCardName, dwProviderId, tzProvider); } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardForgetCardType: This service provides means for removing previously defined smartcards from the Calais Subsystem. Arguments: hContext supplies the handle identifying the Service Manager Context, which must have been previously established via the SCardEstablishContext() service. szCardName supplies the friendly name of the card to be forgotten. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/23/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardForgetCardTypeW") WINSCARDAPI LONG WINAPI SCardForgetCardTypeW( IN SCARDCONTEXT hContext, IN LPCWSTR szCardName) { LONG nReturn = SCARD_S_SUCCESS; try { CTextString tzCardName; DWORD dwScope = SCARD_SCOPE_SYSTEM; if (NULL != hContext) { CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); dwScope = pCtx->Scope(); } tzCardName = szCardName; ForgetCard( dwScope, tzCardName); } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } // //////////////////////////////////////////////////////////////////////////////// // // Reader Services // // The following services supply means for tracking cards within readers. // /*++ SCardLocateCards: This service searches the readers listed in the lpReaderStates parameter for any containing a card with an ATR string matching one of the card supplied names. This service returns immediately with the result. If no matching cards are found, the calling application may use the SCardGetStatusChange service to wait for card availability changes. Arguments: hContext supplies the handle identifying the Service Manager Context established previously via the SCardEstablishContext() service. mszCards supplies the names of the cards to search for, as a multi-string. rgReaderStates supplies an array of SCARD_READERSTATE structures controlling the search, and receives the result. cReaders supplies the number of elements in the rgReaderStates array. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/23/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardLocateCardsW") WINSCARDAPI LONG WINAPI SCardLocateCardsW( IN SCARDCONTEXT hContext, IN LPCWSTR mszCards, IN OUT LPSCARD_READERSTATE_W rgReaderStates, IN DWORD cReaders) { LONG nReturn = SCARD_S_SUCCESS; LPSCARD_ATRMASK rgAtrMasks = NULL; try { LPCSTR szCard; CTextMultistring mtzCards; DWORD dwIndex; DWORD dwScope; CBuffer bfXlate1(36), bfXlate2(36); // Rough guess of name & ATR lengths BOOL fSts; CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); if (pCtx->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } dwScope = pCtx->Scope(); if (0 == *mszCards) throw (DWORD)SCARD_E_INVALID_VALUE; mtzCards = mszCards; rgAtrMasks = new SCARD_ATRMASK[MStringCount(mtzCards)]; if (rgAtrMasks == NULL) { CalaisWarning( __SUBROUTINE__, DBGT("WinSCard Client has no memory")); throw (DWORD)SCARD_E_NO_MEMORY; } dwIndex = 0; for (szCard = FirstString(mtzCards); NULL != szCard; szCard = NextString(szCard)) { fSts = GetCardInfo( dwScope, szCard, &bfXlate1, // ATR &bfXlate2, // Mask NULL, NULL); if (!fSts) throw (DWORD)SCARD_E_UNKNOWN_CARD; ASSERT(33 >= bfXlate1.Length()); // Biggest an ATR can be. rgAtrMasks[dwIndex].cbAtr = bfXlate1.Length(); memcpy(rgAtrMasks[dwIndex].rgbAtr, bfXlate1.Access(), rgAtrMasks[dwIndex].cbAtr); ASSERT(rgAtrMasks[dwIndex].cbAtr == bfXlate2.Length()); memcpy(rgAtrMasks[dwIndex].rgbMask, bfXlate2.Access(), rgAtrMasks[dwIndex].cbAtr); dwIndex ++; } nReturn = SCardLocateCardsByATRW( hContext, rgAtrMasks, dwIndex, rgReaderStates, cReaders); // If the remote client does not implement the new API // retry with the old one. it might succeed if its DB is good enough if ((nReturn == ERROR_CALL_NOT_IMPLEMENTED) && (pCtx->GetRedirContext())) { nReturn = pfnSCardLocateCardsW(pCtx->GetRedirContext(), mszCards, rgReaderStates, cReaders); } } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } if (rgAtrMasks != NULL) { try { delete[] rgAtrMasks; } catch (...) { } } return nReturn; } /*++ SCardLocateCardsByATR: This service searches the readers listed in the lpReaderStates parameter for any containing a card with an ATR string matching one of the supplied ATRs This service returns immediately with the result. If no matching cards are found, the calling application may use the SCardGetStatusChange service to wait for card availability changes. Arguments: hContext supplies the handle identifying the Service Manager Context established previously via the SCardEstablishContext() service. rgAtrMasks supplies the ATRs to search for, as an array of structs. cAtrs supplies the number of elements in the rgAtrMasks array. rgReaderStates supplies an array of SCARD_READERSTATE structures controlling the search, and receives the result. cReaders supplies the number of elements in the rgReaderStates array. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardLocateCardsByATRW") WINSCARDAPI LONG WINAPI SCardLocateCardsByATRW( IN SCARDCONTEXT hContext, IN LPSCARD_ATRMASK rgAtrMasks, IN DWORD cAtrs, IN OUT LPSCARD_READERSTATE_W rgReaderStates, IN DWORD cReaders) { LONG nReturn = SCARD_S_SUCCESS; try { CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); if (pCtx->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } if (pCtx->GetRedirContext()) { nReturn = pfnSCardLocateCardsByATRW(pCtx->GetRedirContext(), rgAtrMasks, cAtrs, rgReaderStates, cReaders); } else { CBuffer bfReaders; DWORD dwIndex; for (dwIndex = 0; dwIndex < cReaders; dwIndex += 1) MStrAdd(bfReaders, rgReaderStates[dwIndex].szReader); pCtx->LocateCards( bfReaders, rgAtrMasks, cAtrs, (LPSCARD_READERSTATE)rgReaderStates, cReaders); } } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardGetStatusChange: This service is used to block execution until such time as the current availability of cards in a given set of readers changes. The caller supplies a list of readers to be monitored via an SCARD_READERSTATE array, and the maximum amount of time, in seconds, that it is willing to wait for an action to occur on one of the listed readers. Zero in this parameter indicates that no timeout is specified. The service returns when there is a change in availability, having filled in the dwEventState fields of the rgReaderStates parameter appropriately. Arguments: hContext supplies the handle identifying the Service Manager Context established previously via the SCardEstablishContext() service. dwTimeOut supplies the maximum amount of time to wait for an action, in seconds. A zero value implies that the wait will never timeout. rgReaderStates supplies an array of SCARD_READERSTATE structures controlling the wait, and receives the result. cReaders supplies the number of elements in the rgReaderStates array. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/23/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardGetStatusChangeW") BOOL SetStartedEventAfterTestingConnectedState(); WINSCARDAPI LONG WINAPI SCardGetStatusChangeW( IN SCARDCONTEXT hContext, IN DWORD dwTimeout, IN OUT LPSCARD_READERSTATE_W rgReaderStates, IN DWORD cReaders) { LONG nReturn = SCARD_S_SUCCESS; try { CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); if (pCtx->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } if (pCtx->GetRedirContext()) { nReturn = pfnSCardGetStatusChangeW(pCtx->GetRedirContext(), dwTimeout, rgReaderStates, cReaders); // // See if there is an indication that the client's scardsvr service was shutdown // if (SCARD_E_SYSTEM_CANCELLED == nReturn) { //OutputDebugString("WINSCARD: SCardEstablishContext: got E_NO_SERVICE!\n"); SetStartedEventAfterTestingConnectedState(); } } else { CBuffer bfReaders; DWORD dwIndex; for (dwIndex = 0; dwIndex < cReaders; dwIndex += 1) MStrAdd(bfReaders, rgReaderStates[dwIndex].szReader); pCtx->GetStatusChange( bfReaders, (LPSCARD_READERSTATE)rgReaderStates, cReaders, dwTimeout); } } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; if (SCARD_E_SYSTEM_CANCELLED == nReturn) { ResetEvent(g_hUnifiedStartedEvent); } } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } // //////////////////////////////////////////////////////////////////////////////// // // Card/Reader Access Services // // The following services provide means for establishing communication with // the card. // /*++ SCardConnect: This service establishes a connection from the calling application to the smartcard in the designated reader. If no card exists in the specified reader, an error is returned. Arguments: hContext supplies the handle identifying the Service Manager Context established previously via the SCardEstablishContext() service. szReader supplies the name of the reader containing the target card. DwShareMode supplies a flag indicating whether or not other applications may form connections to this card. Possible values are: SCARD_SHARE_SHARED - This application is willing to share this card with other applications. SCARD_SHARE_EXCLUSIVE - This application is not willing to share this card with other applications. SCARD_SHARE_DIRECT - This application is taking control of the reader. DwPreferredProtocols supplies a bit mask of acceptable protocols for this connection. Possible values, which may be combined via the OR operation, are: SCARD_PROTOCOL_T0 - T=0 is an acceptable protocol. SCARD_PROTOCOL_T1 - T=1 is an acceptable protocol. phCard receives a handle identifying the connection to the smartcard in the designated reader. pdwActiveProtocol receives a flag indicating the established active protocol. Possible values are: SCARD_PROTOCOL_T0 - T=0 is the active protocol. SCARD_PROTOCOL_T1 - T=1 is the active protocol. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/23/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardConnectW") WINSCARDAPI LONG WINAPI SCardConnectW( IN SCARDCONTEXT hContext, IN LPCWSTR szReader, IN DWORD dwShareMode, IN DWORD dwPreferredProtocols, OUT LPSCARDHANDLE phCard, OUT LPDWORD pdwActiveProtocol) { LONG nReturn = SCARD_S_SUCCESS; CReaderContext *pRdr = NULL; CSCardSubcontext *pSubCtx = NULL; try { *phCard = NULL; // Touch it to be sure it's real. CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]); CTextString tzReader; if (pCtx->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } tzReader = szReader; pRdr = new CReaderContext; if (NULL == pRdr) { CalaisWarning( __SUBROUTINE__, DBGT("WinSCard Client has no memory")); throw (DWORD)SCARD_E_NO_MEMORY; } SCARDCONTEXT hRedirContext = pCtx->GetRedirContext(); if (hRedirContext) { SCARDHANDLE hCard = g_phlReaders->Add(pRdr); // do it first to avoid out of memory condition nReturn = pfnSCardConnectW(hRedirContext, szReader, dwShareMode, dwPreferredProtocols, phCard, pdwActiveProtocol); if (nReturn == SCARD_S_SUCCESS) { pRdr->SetRedirCard(*phCard); *phCard = hCard; } else { g_phlReaders->Close(hCard); delete pRdr; } } else { pSubCtx = pCtx->AcquireSubcontext(TRUE); pRdr->Connect( pSubCtx, tzReader, dwShareMode, dwPreferredProtocols); pSubCtx = NULL; pRdr->Context()->ReleaseSubcontext(); if (NULL != pdwActiveProtocol) *pdwActiveProtocol = pRdr->Protocol(); pRdr->Context()->m_hReaderHandle = g_phlReaders->Add(pRdr); *phCard = pRdr->Context()->m_hReaderHandle; } } catch (DWORD dwStatus) { if (NULL != pSubCtx) { pSubCtx->Deallocate(); pSubCtx->ReleaseSubcontext(); } if (NULL != pRdr) delete pRdr; nReturn = (LONG)dwStatus; } catch (...) { if (NULL != pSubCtx) { pSubCtx->Deallocate(); pSubCtx->ReleaseSubcontext(); } if (NULL != pRdr) delete pRdr; nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } /*++ SCardStatus: This routine provides the current status of the reader. It may be used at any time following a successful call to SCardConnect or SCardOpenReader, and prior to a successful call to SCardDisconnect. It does not effect the state of the reader or driver. Arguments: hCard - This is the reference value returned from the SCardConnect or SCardOpenReader service. mszReaderNames - This receives a list of friendly names by which the currently connected reader is known. This list is returned as a multistring. pcchReaderLen - This supplies the length of the mszReader buffer, in characters, and receives the actual returned length of the reader friendly name list, in characters, including the trailing NULL characters. pdwState - This receives the current state of the reader. Upon success, it receives one of the following state indicators: SCARD_ABSENT - This value implies there is no card in the reader. SCARD_PRESENT - This value implies there is a card is present in the reader, but that it has not been moved into position for use. SCARD_SWALLOWED - This value implies there is a card in the reader in position for use. The card is not powered. SCARD_POWERED - This value implies there is power is being provided to the card, but the Reader Driver is unaware of the mode of the card. SCARD_NEGOTIABLEMODE - This value implies the card has been reset and is awaiting PTS negotiation. SCARD_SPECIFICMODE - This value implies the card has been reset and specific communication protocols have been established. pdwProtocol - This receives the current protocol, if any. Possible returned values are listed below. Other values may be added in the future. The returned value is only meaningful if the returned state is SCARD_SPECIFICMODE. SCARD_PROTOCOL_RAW - The Raw Transfer Protocol is in use. SCARD_PROTOCOL_T0 - The ISO 7816/3 T=0 Protocol is in use. SCARD_PROTOCOL_T1 - The ISO 7816/3 T=1 Protocol is in use. pbAtr - This parameter points to a 32-byte buffer which receives the ATR string from the currently inserted card, if available. pbcAtrLen - This points to a DWORD which supplies the length of the pbAtr buffer, and receives the actual number of bytes in the ATR string. Return Value: A 32-bit value indicating whether or not the service completed successfully. SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value represents an error condition. Author: Doug Barlow (dbarlow) 10/23/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("SCardStatusW") WINSCARDAPI LONG WINAPI SCardStatusW( IN SCARDHANDLE hCard, OUT LPWSTR mszReaderNames, IN OUT LPDWORD pcchReaderLen, OUT LPDWORD pdwState, OUT LPDWORD pdwProtocol, OUT LPBYTE pbAtr, IN OUT LPDWORD pcbAtrLen) { LONG nReturn = SCARD_S_SUCCESS; try { CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]); if (pRdr->IsBad()) { throw (DWORD)SCARD_E_SERVICE_STOPPED; } if (pRdr->GetRedirCard()) { nReturn = pfnSCardStatusW(pRdr->GetRedirCard(), mszReaderNames, pcchReaderLen, pdwState, pdwProtocol, pbAtr, pcbAtrLen); } else { CBuffer bfAtr, bfReader; DWORD dwLocalState, dwLocalProtocol; pRdr->Status(&dwLocalState, &dwLocalProtocol, bfAtr, bfReader); if (NULL != pdwState) *pdwState = dwLocalState; if (NULL != pdwProtocol) *pdwProtocol = dwLocalProtocol; if (NULL != pcchReaderLen) PlaceMultiResult( pRdr->Context()->Parent(), bfReader, mszReaderNames, pcchReaderLen); if (NULL != pcbAtrLen) PlaceResult(pRdr->Context()->Parent(), bfAtr, pbAtr, pcbAtrLen); } } catch (DWORD dwStatus) { nReturn = (LONG)dwStatus; } catch (...) { nReturn = SCARD_E_INVALID_PARAMETER; } return nReturn; } // /////////////////////////////////////////////////////////////////////////////// // // Utility Routines // /*++ PlaceResult: This set of routines places the result of an operation into the user's output buffer, supporting SCARD_AUTO_ALLOCATE, invalid buffer sizes, etc. Arguments: pCtx supplies the context under which this operation is being performed. bfResult supplies the result to be returned to the user. pbOutput receives the result for the user, as a byte stream. szOutput receives the result as an ANSI or UNICODE string. pcbLength supplies the length of the user's output buffer in bytes, and receives how much of it was used. pcchLength supplies the length of the user's output buffer in characters, and receives how much of it was used. Return Value: None Throws: Error conditions are thrown as DWORD status codes. Author: Doug Barlow (dbarlow) 12/7/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("PlaceResult") void PlaceResult( CSCardUserContext *pCtx, CBuffer &bfResult, LPWSTR szOutput, LPDWORD pcchLength) { LPWSTR szForUser = NULL; LPWSTR szOutBuf = szOutput; DWORD cchSrcLength = bfResult.Length() / sizeof(TCHAR); try { if (NULL == szOutput) *pcchLength = 0; switch (*pcchLength) { case 0: // They just want the length. *pcchLength = cchSrcLength; break; case SCARD_AUTOALLOCATE: if (0 < cchSrcLength) { if (NULL == pCtx) { szForUser = (LPWSTR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, cchSrcLength * sizeof(WCHAR)); } else szForUser = (LPWSTR)pCtx->AllocateMemory( cchSrcLength * sizeof(WCHAR)); if (NULL == szForUser) { CalaisWarning( __SUBROUTINE__, DBGT("Client can't get return memory")); throw (DWORD)SCARD_E_NO_MEMORY; } *(LPWSTR *)szOutput = szForUser; szOutBuf = szForUser; // Fall through intentionally } else { *pcchLength = cchSrcLength; *(LPWSTR *)szOutput = (LPWSTR)g_wszBlank; break; // Do terminate the case now. } default: if (*pcchLength < cchSrcLength) { *pcchLength = cchSrcLength; throw (DWORD)SCARD_E_INSUFFICIENT_BUFFER; } MoveToUnicodeString( szOutBuf, (LPCTSTR)bfResult.Access(), cchSrcLength); *pcchLength = cchSrcLength; break; } } catch (...) { if (NULL != szForUser) { if (NULL == pCtx) HeapFree(GetProcessHeap(), 0, szForUser); else pCtx->FreeMemory(szForUser); } throw; } } /*++ PlaceMultiResult: This set of routines places a Multistring result of an operation into the user's output buffer, supporting SCARD_AUTO_ALLOCATE, invalid buffer sizes, etc. Arguments: pCtx supplies the context under which this operation is being performed. bfResult supplies the TCHAR multistring result to be returned to the user. mszOutput receives the result as an ANSI or UNICODE multistring. pcchLength supplies the length of the user's output buffer in characters, and receives how much of it was used. Return Value: None Throws: Error conditions are thrown as DWORD status codes. Author: Doug Barlow (dbarlow) 12/7/1996 --*/ #undef __SUBROUTINE__ #define __SUBROUTINE__ DBGT("PlaceMultiResult") void PlaceMultiResult( CSCardUserContext *pCtx, CBuffer &bfResult, LPWSTR mszOutput, LPDWORD pcchLength) { LPWSTR mszForUser = NULL; LPWSTR mszOutBuf = mszOutput; DWORD cchSrcLength = bfResult.Length() / sizeof(TCHAR); try { if (NULL == mszOutput) *pcchLength = 0; switch (*pcchLength) { case 0: // They just want the length. *pcchLength = cchSrcLength; break; case SCARD_AUTOALLOCATE: if (0 < cchSrcLength) { if (NULL == pCtx) { mszForUser = (LPWSTR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, cchSrcLength * sizeof(WCHAR)); } else mszForUser = (LPWSTR)pCtx->AllocateMemory( cchSrcLength * sizeof(WCHAR)); if (NULL == mszForUser) { CalaisWarning( __SUBROUTINE__, DBGT("Client can't get return memory")); throw (DWORD)SCARD_E_NO_MEMORY; } *(LPWSTR *)mszOutput = mszForUser; mszOutBuf = mszForUser; // Fall through intentionally } else { *pcchLength = cchSrcLength; *(LPWSTR *)mszOutput = (LPWSTR)g_wszBlank; break; // Do terminate the case now. } default: if (*pcchLength < cchSrcLength) { *pcchLength = cchSrcLength; throw (DWORD)SCARD_E_INSUFFICIENT_BUFFER; } MoveToUnicodeMultiString( mszOutBuf, (LPCTSTR)bfResult.Access(), cchSrcLength); *pcchLength = cchSrcLength; break; } } catch (...) { if (NULL != mszForUser) { if (NULL == pCtx) HeapFree(GetProcessHeap(), 0, mszForUser); else pCtx->FreeMemory(mszForUser); } throw; } }