// Tracking Functions
        public void Cancel()
        {
            if (this.m_hContext == IntPtr.Zero)
            {
                throw new InvalidOperationException();
            }
            uint nErrCode = WinSCard.SCardCancel(this.m_hContext);

            if (nErrCode != 0)
            {
                //SCardException.RaiseWin32ResponseCode(nErrCode);
            }
        }
        /// <summary>
        /// Wait until one of the specified status changes occur (or timeout)
        /// </summary>
        /// <param name="nTimeout"></param>
        /// <param name="vaSCStates"></param>
        /// <returns></returns>
        public bool GetStatusChange(int nTimeout, SCStateInfo[] vaSCStates)
        {
            int nLen = vaSCStates.Length;

            // Create the array for the API call
            WinSCard.SCARD_READERSTATE[] statearray = new WinSCard.SCARD_READERSTATE[nLen];

            for (int nIter = 0; nIter < nLen; nIter++)
            {
                statearray[nIter].szReader       = vaSCStates[nIter].sReaderName;
                statearray[nIter].pvUserData     = IntPtr.Zero;
                statearray[nIter].dwCurrentState = (uint)vaSCStates[nIter].nCurrentState;
                statearray[nIter].dwEventState   = (uint)SCStates.Unaware;
                statearray[nIter].cbAtr          = 0;
                statearray[nIter].rgbAtr         = null;
            }

            uint nErrCode = WinSCard.SCardGetStatusChange(this.m_hContext, (uint)nTimeout, statearray, (uint)statearray.Length);

            if (nErrCode == 0)
            {
                for (int nLoopCnt = 0; nLoopCnt < nLen; nLoopCnt++)
                {
                    vaSCStates[nLoopCnt].nEventState = (SCStates)statearray[nLoopCnt].dwEventState;
                    if ((statearray[nLoopCnt].cbAtr > 0) && (statearray[nLoopCnt].rgbAtr != null))
                    {
                        vaSCStates[nLoopCnt].vbATR = new byte[statearray[nLoopCnt].cbAtr];
                        Buffer.BlockCopy(statearray[nLoopCnt].rgbAtr, 0, vaSCStates[nLoopCnt].vbATR, 0, (int)statearray[nLoopCnt].cbAtr);
                    }
                    else
                    {
                        vaSCStates[nLoopCnt].vbATR = null;
                    }
                }
                return(true);
            }

            // If Timeout or SCardCancel happened just bail out
            if ((nErrCode == 0x8010000a) || (nErrCode == 0x80100002))
            {
                return(false);
            }
            // If we reach here there is a problem
            //SCardException.RaiseWin32ResponseCode(nErrCode);
            throw new InvalidProgramException();
        }
        public SCardReaderState Status(out byte[] byteATR, out SCardReaderState eState, out SCardProtocolIdentifiers eProtocol)
        {
            if (this.m_fDisposed)
            {
                throw new ObjectDisposedException(base.GetType().FullName);
            }
            if (this.m_hCard == IntPtr.Zero)
            {
                throw new InvalidOperationException();
            }
            StringBuilder builder1 = new StringBuilder(0x100);
            uint          num3     = (uint)builder1.Capacity;

            byte[] atr  = new byte[0x20];
            uint   num4 = (uint)atr.Length;
            uint   dwState;
            uint   dwProtocol;
            uint   dwATRLength = (uint)atr.Length;

            uint num5 = WinSCard.SCardStatus(this.m_hCard, builder1, ref num3 /*builder1.Capacity*/, out dwState /*pdwState*/, out dwProtocol /*pdwProtocol*/, atr /*pbATR*/, ref dwATRLength /*pbcATRLen*/);

            if (num5 != 0)
            {
                //SmartCardException.RaiseWin32ResponseCode(num5);
            }
            eState    = (SCardReaderState)dwState;
            eProtocol = (SCardProtocolIdentifiers)dwProtocol;
            if (dwATRLength > 0)
            {
                // copy only the valid portion of the ATR to the return buffer.
                byteATR = new byte[dwATRLength];
                for (int i = 0; i < dwATRLength; i++)
                {
                    byteATR[i] = atr[i];
                }
            }
            else
            {
                byteATR    = new byte[1];
                byteATR[0] = 0;// return an invalid state.
            }

            return((SCardReaderState)dwState);
        }
        // Database Functions

        /// <summary>
        /// List the reader groups.
        /// </summary>
        /// <param name="aReaderGroupsList">List of reader groups</param>
        /// <returns></returns>
        public int ListReaderGroups(IList aReaderGroupsList)
        {
            // Sanity Check
            if (this.m_fDisposed)
            {
                throw new ObjectDisposedException(base.GetType().FullName);
            }
            // Sanity Check
            if (this.m_hContext == IntPtr.Zero)
            {
                throw new InvalidOperationException();
            }

            int    nRet       = 0;
            IntPtr ptrRMgrMem = IntPtr.Zero;
            uint   nMax       = uint.MaxValue;
            uint   nErrCode   = WinSCard.SCardListReaderGroups(this.m_hContext, ref ptrRMgrMem, ref nMax);

            // Success
            //if (nErrCode == 0)
            if (nErrCode == (uint)SCardReturnValues.SCARD_S_SUCCESS)
            {
                string text = Marshal.PtrToStringAuto(ptrRMgrMem, (int)nMax);
                nRet     = this._SplitMultiString(text, aReaderGroupsList);
                nErrCode = WinSCard.SCardFreeMemory(this.m_hContext, ptrRMgrMem);
                return(nRet);
            }

            // Error
            //if (nErrCode == 2148532270)
            if (nErrCode == (uint)SCardReturnValues.SCARD_E_NO_READERS_AVAILABLE)
            {
                return(0);
            }

            // Exception
            //SCardException.RaiseWin32ResponseCode(nErrCode);
            return(nRet);
        }
        /// <summary>
        /// Disconnect from the PCSC reader
        /// </summary>
        /// <param name="nDisposition"></param>
        public void Disconnect(SCardDisposition nDisposition)
        {
            if (this.m_fDisposed)
            {
                throw new ObjectDisposedException(base.GetType().FullName);
            }
            if ((this.m_hCard == IntPtr.Zero) || !this.m_fIsConnected)
            {
                throw new InvalidOperationException();
            }

            // Terminate the connection with this SmartCard
            uint num1 = WinSCard.SCardDisconnect(this.m_hCard, (uint)nDisposition);

            this.m_hCard            = IntPtr.Zero;
            this.m_dwActiveProtocol = 0;
            this.m_fIsConnected     = false;
            //this.m_fInTransaction = false;
            if (num1 != 0)
            {
                //SCardException.RaiseWin32ResponseCode(num1);
            }
        }
        public bool IsValidContext()
        {
            // Sanity Check
            if (this.m_fDisposed)
            {
                throw new ObjectDisposedException(base.GetType().FullName);
            }

            // Verify Context exists
            if (this.m_hContext == IntPtr.Zero)
            {
                throw new InvalidOperationException();
            }

            // Call native fxn and return appropriately
            uint nErrCode = WinSCard.SCardIsValidContext(this.m_hContext);

            if (nErrCode == 0)
            {
                return(true);
            }
            return(false);
        }
        /// <summary>
        /// Send a control code to the reader
        /// </summary>
        /// <param name="nControlCode"></param>
        /// <param name="vbInBuffer"></param>
        /// <param name="vbOutBuffer"></param>
        public void Control(int nControlCode, byte[] vbInBuffer, out byte[] vbOutBuffer)
        {
            if (m_fDisposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }
            if (m_hCard == IntPtr.Zero || !m_fIsConnected)
            {
                throw new InvalidOperationException();
            }

            byte[] bArr = new byte[65538];
            uint   ui1  = 0;

            // Send the control code using the PCSC interface to the reader
            uint ui2 = WinSCard.SCardControl(m_hCard, (uint)nControlCode, vbInBuffer, (uint)vbInBuffer.Length, bArr, (uint)bArr.Length, out ui1);

            // If the call was successful, get the response
            if ((int)ui2 == 0)
            {
                // Any bytes returned?
                if ((int)ui1 > 0)
                {
                    // Get the response
                    vbOutBuffer = new byte[ui1];
                    Buffer.BlockCopy(bArr, 0, vbOutBuffer, 0, (int)ui1);
                    return;
                }
                vbOutBuffer = null;
                return;
            }

            // Error code
            //SCardException.RaiseWin32ResponseCode(ui2);
            throw new InvalidProgramException();
        }
        /// <summary>
        /// Connect the application to the PCSC driver
        /// </summary>
        /// <param name="sReader">The reader name</param>
        /// <param name="nAccessMode">Access mode (Direct, Exclusive or Shared).</param>
        /// <param name="nPreferredProtocols">Protocols the driver should use to communicate with the reader.</param>
        /// <returns>True if successfully connected, False if card removed.</returns>
        public bool Connect(string sReader, SCardAccessMode nAccessMode, SCardProtocolIdentifiers nPreferredProtocols)
        {
            if (this.m_fDisposed)
            {
                throw new ObjectDisposedException(base.GetType().FullName);
            }
            if (((this.m_hCard != IntPtr.Zero) || (this.Context == IntPtr.Zero)) || this.m_fIsConnected)
            {
                throw new InvalidOperationException();
            }

            // Share mode and protocols from caller.
            uint num1 = (uint)nAccessMode;
            uint num2 = (uint)nPreferredProtocols;

            // Establish a connection between application and card docked in the reader.
            // (Gets the handle to the card and the active protocol of the connection)
            uint num3 = WinSCard.SCardConnect(this.Context, sReader, num1, num2, out this.m_hCard, out this.m_dwActiveProtocol);

            // Check error code - either successfully connected or the card was removed are ok.
            switch (num3)
            {
            case (uint)SCardErrorCodes.SCARD_S_SUCCESS:
                //case 0:
                this.m_fIsConnected = true;
                return(true);

            case (uint)SCardErrorCodes.SCARD_W_REMOVED_CARD:
                //case 0x80100069:
                return(false);
            }

            // Any other error codes are raised.
            //SCardException.RaiseWin32ResponseCode(num3);
            throw new InvalidProgramException();
        }
        /// <summary>
        /// List the installed readers within the given list of groups.
        /// </summary>
        /// <param name="vsGroups">List of reader groups</param>
        /// <param name="aReadersList">Provided list object</param>
        /// <returns></returns>
        public int ListReaders(string[] vsGroups, IList aReadersList)
        {
            // Sanity Check
            if (this.m_fDisposed)
            {
                throw new ObjectDisposedException(base.GetType().FullName);
            }

            // A handle to the context had to be established prior to this.
            // (i.e. by calling EstablishContext)
            if (this.m_hContext == IntPtr.Zero)
            {
                throw new InvalidOperationException();
            }

            // Assume no readers yet
            int    nReaders = 0;
            string text     = null;

            // If a list of readers groups was provided then concatenate them
            // into a multi-string.  If not then all reader groups will be read.
            if ((vsGroups != null) && (vsGroups.Length > 0))
            {
                string[] textArray = vsGroups;
                for (int nIter = 0; nIter < textArray.Length; nIter++)
                {
                    string strTemp = textArray[nIter];
                    text = text + strTemp;
                    text = text + '\0';
                }
                text = text + '\0';
            }

            // NULL pointer - indicates to allocate the buffer internally.
            IntPtr ptrMem = IntPtr.Zero;

            // Autoallocate: SCARD_AUTOALLOCATE (which is -1).  See Winscard.h within the DDK.
            uint nMax = uint.MaxValue;

            // List the reader names within the given groups.
            //
            // If pointer to the readers list (3rd parm) is NULL, SCardListReaders ignores the buffer length supplied
            // in the 4th parm, writes the length of the buffer that would have been returned if this parameter had not
            // been NULL to that passed in pointer, and returns a success code.
            //
            // The 4th parameter 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 byte pointer, and receives the address of a block of memory containing the multi-string
            // structure. This block of memory must be deallocated with SCardFreeMemory.
            uint nErrCode = WinSCard.SCardListReaders(this.m_hContext, text, ref ptrMem, ref nMax);

            // If the call returned OK then can interpret the results.
            if (nErrCode == (uint)SCardReturnValues.SCARD_S_SUCCESS)
            {
                // Marshall the list of readers to a string
                string sReaders = Marshal.PtrToStringAuto(ptrMem, (int)nMax);

                // Split the string into the ArrayList object provided by caller.
                nReaders = this._SplitMultiString(sReaders, aReadersList);

                // Free Autoallocate
                nErrCode = WinSCard.SCardFreeMemory(this.m_hContext, ptrMem);

                // Return the number of items in the ArrayList.
                return(nReaders);
            }

            // Not successfully read
            if (nErrCode == (uint)SCardReturnValues.SCARD_E_NO_READERS_AVAILABLE)
            {
                return(0);
            }

            // Report Error
            //SCardException.RaiseWin32ResponseCode(nErrCode);
            return(nReaders);
        }