getStatusChange method

  1. @override
Tuple2<SCardResult, List<SCardReaderState>> getStatusChange(
  1. int hContext,
  2. int dwTimeout,
  3. List<SCardReaderState> rgReaderStates
)
override

Implementation

@override
Tuple2<SCardResult, List<SCardReaderState>> getStatusChange(int hContext, int dwTimeout, List<SCardReaderState> rgReaderStates) {
  // Define the maximum size of the ATR buffer.
  final atrBufferSize = MAX_ATR_SIZE;

  // Create a list of native string pointers for each reader name.
  final List<ffi.Pointer<ffi.Char>> nativeReaderNames = rgReaderStates.map((state) => _allocateNativeString(state.szReader)).toList();

  // Allocate memory for an array of SCARD_READERSTATE structures.
  final nativeReaderStates = calloc<SCARD_READERSTATE>(rgReaderStates.length);

  try {
    // Copy each Dart reader state into its native counterpart.
    for (int i = 0; i < rgReaderStates.length; i++) {
      final state = rgReaderStates[i];
      nativeReaderStates[i].szReader = nativeReaderNames[i];
      nativeReaderStates[i].pvUserData = ffi.nullptr;
      nativeReaderStates[i].dwCurrentState = state.dwCurrentState;
      nativeReaderStates[i].dwEventState = 0;
      nativeReaderStates[i].cbAtr = atrBufferSize;

      // Copy any initial ATR bytes if provided (up to the available length and buffer size).
      for (int j = 0; j < state.rgbAtr.length && j < atrBufferSize; j++) {
        nativeReaderStates[i].rgbAtr[j] = state.rgbAtr[j];
      }
    }

    // Call the native SCardGetStatusChange() function.
    // This call will block until a reader event occurs or the timeout expires.
    final response = _winscard.SCardGetStatusChange( hContext, dwTimeout, nativeReaderStates, rgReaderStates.length );
    final result = SCardResult(response);

    // If the call failed, return immediately with an empty state list.
    if (!result.isSuccess) {
      return Tuple2(result, []);
    }

    // Build the updated list of SCardReaderState objects based on the native structure values.
    List<SCardReaderState> updatedStates = [];

    for (int i = 0; i < rgReaderStates.length; i++) {
      // The native structure's cbAtr should now contain the actual ATR length.
      final int actualAtrLength = nativeReaderStates[i].cbAtr;
      List<int> atrBytes = [];

      // Copy only the valid ATR bytes.
      for (int j = 0; j < actualAtrLength && j < atrBufferSize; j++) {
        atrBytes.add(nativeReaderStates[i].rgbAtr[j]);
      }

      // Convert the native reader name back into a Dart string.
      final readerName = _convertNativeString(nativeReaderStates[i].szReader);

      // Create a new SCardReaderState with updated values from the native structure.
      updatedStates.add( SCardReaderState( readerName, nativeReaderStates[i].dwCurrentState, nativeReaderStates[i].dwEventState, atrBytes ));
    }

    // Return the result code along with the updated list of reader states.
    return Tuple2(result, updatedStates);
  }
  finally {
    // Free each native string allocated for the reader names.
    for (final ptr in nativeReaderNames) {
      calloc.free(ptr);
    }
    // Free the allocated array of SCARD_READERSTATE.
    calloc.free(nativeReaderStates);
  }
}