From 3f325721c3b1d72dca475dc1fa2ad4063f663f69 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Thu, 16 Feb 2023 10:50:32 +0100 Subject: [PATCH] winscard: Implement SCardGetStatusChangeA/W(). --- dlls/winscard/unixlib.c | 8 ++ dlls/winscard/unixlib.h | 20 +++++ dlls/winscard/winscard.c | 147 ++++++++++++++++++++++++++++++++++++ dlls/winscard/winscard.spec | 4 +- 4 files changed, 177 insertions(+), 2 deletions(-) diff --git a/dlls/winscard/unixlib.c b/dlls/winscard/unixlib.c index 032b148af8f..98de78a6d2b 100644 --- a/dlls/winscard/unixlib.c +++ b/dlls/winscard/unixlib.c @@ -34,6 +34,7 @@ LONG SCardEstablishContext( UINT64, const void *, const void *, UINT64 * ); LONG SCardReleaseContext( UINT64 ); LONG SCardIsValidContext( UINT64 ); +LONG SCardGetStatusChange( UINT64, UINT64, struct reader_state *, UINT64 ); static NTSTATUS scard_establish_context( void *args ) { @@ -53,9 +54,16 @@ static NTSTATUS scard_is_valid_context( void *args ) return SCardIsValidContext( params->handle ); } +static NTSTATUS scard_get_status_change( void *args ) +{ + struct scard_get_status_change_params *params = args; + return SCardGetStatusChange( params->handle, params->timeout, params->states, params->count ); +} + const unixlib_entry_t __wine_unix_call_funcs[] = { scard_establish_context, scard_release_context, scard_is_valid_context, + scard_get_status_change, }; diff --git a/dlls/winscard/unixlib.h b/dlls/winscard/unixlib.h index b8ba940f5b2..0607596bf2c 100644 --- a/dlls/winscard/unixlib.h +++ b/dlls/winscard/unixlib.h @@ -35,9 +35,29 @@ struct scard_is_valid_context_params UINT64 handle; }; +#define MAX_ATR_SIZE 33 +struct reader_state +{ + UINT64 reader; + UINT64 userdata; + UINT64 current_state; + UINT64 event_state; + UINT64 atr_size; + unsigned char atr[MAX_ATR_SIZE]; +}; + +struct scard_get_status_change_params +{ + UINT64 handle; + UINT64 timeout; + struct reader_state *states; + UINT64 count; +}; + enum winscard_funcs { unix_scard_establish_context, unix_scard_release_context, unix_scard_is_valid_context, + unix_scard_get_status_change, }; diff --git a/dlls/winscard/winscard.c b/dlls/winscard/winscard.c index 4f4cbcfed2f..3fefff5f755 100644 --- a/dlls/winscard/winscard.c +++ b/dlls/winscard/winscard.c @@ -37,6 +37,40 @@ const SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, 8 }; const SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, 8 }; const SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, 8 }; +static inline char *utf16_to_utf8( const WCHAR *src ) +{ + char *dst = NULL; + if (src) + { + int len = WideCharToMultiByte( CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL ); + if ((dst = malloc( len ))) WideCharToMultiByte( CP_UTF8, 0, src, -1, dst, len, NULL, NULL ); + } + return dst; +} + +static inline WCHAR *ansi_to_utf16( const char *src ) +{ + WCHAR *dst = NULL; + if (src) + { + int len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 ); + if ((dst = malloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len ); + } + return dst; +} + +static inline char *ansi_to_utf8( const char *src ) +{ + char *dst = NULL; + if (src) + { + WCHAR *tmp; + if ((tmp = ansi_to_utf16( src ))) dst = utf16_to_utf8( tmp ); + free( tmp ); + } + return dst; +} + HANDLE WINAPI SCardAccessStartedEvent(void) { return g_startedEvent; @@ -174,6 +208,119 @@ LONG WINAPI SCardCancel(SCARDCONTEXT context) return SCARD_F_INTERNAL_ERROR; } +static LONG map_states_inA( const SCARD_READERSTATEA *src, struct reader_state *dst, DWORD count ) +{ + DWORD i; + for (i = 0; i < count; i++) + { + if (src[i].szReader && !(dst[i].reader = (UINT64)(ULONG_PTR)ansi_to_utf8( src[i].szReader ))) + return SCARD_E_NO_MEMORY; + dst[i].current_state = src[i].dwCurrentState; + dst[i].event_state = src[i].dwEventState; + dst[i].atr_size = src[i].cbAtr; + memcpy( dst[i].atr, src[i].rgbAtr, src[i].cbAtr ); + } + return SCARD_S_SUCCESS; +} + +static void map_states_out( const struct reader_state *src, SCARD_READERSTATEA *dst, DWORD count ) +{ + DWORD i; + for (i = 0; i < count; i++) + { + dst[i].dwCurrentState = src[i].current_state; + dst[i].dwEventState = src[i].event_state; + dst[i].cbAtr = src[i].atr_size; + memcpy( dst[i].rgbAtr, src[i].atr, src[i].atr_size ); + } +} + +static void free_states( struct reader_state *states, DWORD count ) +{ + DWORD i; + for (i = 0; i < count; i++) free( (void *)(ULONG_PTR)states[i].reader ); + free( states ); +} + +LONG WINAPI SCardGetStatusChangeA( SCARDCONTEXT context, DWORD timeout, SCARD_READERSTATEA *states, DWORD count ) +{ + struct handle *handle = (struct handle *)context; + struct scard_get_status_change_params params; + struct reader_state *states_utf8 = NULL; + LONG ret; + + TRACE( "%Ix, %lu, %p, %lu\n", context, timeout, states, count ); + + if (!handle || handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; + + if (!(states_utf8 = calloc( count, sizeof(*states_utf8) ))) return SCARD_E_NO_MEMORY; + if ((ret = map_states_inA( states, states_utf8, count ))) + { + free_states( states_utf8, count ); + return ret; + } + + params.handle = handle->unix_handle; + params.timeout = timeout; + params.states = states_utf8; + params.count = count; + if (!(ret = UNIX_CALL( scard_get_status_change, ¶ms )) && states) + { + map_states_out( states_utf8, states, count ); + } + + free_states( states_utf8, count ); + TRACE( "returning %#lx\n", ret ); + return ret; +} + +static LONG map_states_inW( SCARD_READERSTATEW *src, struct reader_state *dst, DWORD count ) +{ + DWORD i; + for (i = 0; i < count; i++) + { + if (src[i].szReader && !(dst[i].reader = (UINT64)(ULONG_PTR)utf16_to_utf8( src[i].szReader ))) + return SCARD_E_NO_MEMORY; + dst[i].current_state = src[i].dwCurrentState; + dst[i].event_state = src[i].dwEventState; + dst[i].atr_size = src[i].cbAtr; + memcpy( dst[i].atr, src[i].rgbAtr, src[i].cbAtr ); + } + return SCARD_S_SUCCESS; +} + +LONG WINAPI SCardGetStatusChangeW( SCARDCONTEXT context, DWORD timeout, SCARD_READERSTATEW *states, DWORD count ) +{ + struct handle *handle = (struct handle *)context; + struct scard_get_status_change_params params; + struct reader_state *states_utf8; + LONG ret; + + TRACE( "%Ix, %lu, %p, %lu\n", context, timeout, states, count ); + + if (!handle || handle->magic != CONTEXT_MAGIC) return ERROR_INVALID_HANDLE; + + if (!(states_utf8 = calloc( count, sizeof(*states_utf8) ))) return SCARD_E_NO_MEMORY; + if ((ret = map_states_inW( states, states_utf8, count ))) + { + free_states( states_utf8, count ); + return ret; + } + + params.handle = handle->unix_handle; + params.timeout = timeout; + params.states = states_utf8; + params.count = count; + if (!(ret = UNIX_CALL( scard_get_status_change, ¶ms ))) + { + map_states_out( states_utf8, (SCARD_READERSTATEA *)states, count ); + } + + free_states( states_utf8, count ); + TRACE( "returning %#lx\n", ret ); + return ret; +} + BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved ) { switch (reason) diff --git a/dlls/winscard/winscard.spec b/dlls/winscard/winscard.spec index 037d3bef903..ff320bae424 100644 --- a/dlls/winscard/winscard.spec +++ b/dlls/winscard/winscard.spec @@ -25,8 +25,8 @@ @ stub SCardGetCardTypeProviderNameW @ stub SCardGetProviderIdA @ stub SCardGetProviderIdW -@ stub SCardGetStatusChangeA -@ stub SCardGetStatusChangeW +@ stdcall SCardGetStatusChangeA(long long ptr long) +@ stdcall SCardGetStatusChangeW(long long ptr long) @ stub SCardIntroduceCardTypeA @ stub SCardIntroduceCardTypeW @ stub SCardIntroduceReaderA