title: NFC Reader, Card Inserted/Ejected watcher
body: <p>I'm working on a project that needs NFC reader, Everything work perfect but I have a little issue.I have a method called <code>Watch</code>, This method triggered when card Read by NFC reader and when card ejected.</p>
  <p>I call this method on Form load, So when the card on the NFC reader I can do Action automatically, But this method working even when I close the form that loaded the method and it will trigger even when I'm trying to write on the card and do the action That is supposed to do in the other form.</p>
  <p>So how can I cancel the event for the method <code>watch</code> method when I want??</p>
  <p>This is the Method <code>watch</code> :</p>
  <pre><code>public void Watch()
      {
          this.RdrState = new Card.SCARD_READERSTATE();
          readername = GetReadersList()[0];
          this.RdrState.RdrName = readername;
  
          states = new Card.SCARD_READERSTATE[1];
          states[0] = new Card.SCARD_READERSTATE();
          states[0].RdrName = readername;
          states[0].UserData = 0;
          states[0].RdrCurrState = Card.SCARD_STATE_EMPTY;
          states[0].RdrEventState = 0;
          states[0].ATRLength = 0;
          states[0].ATRValue = null;
          this._worker = new BackgroundWorker();
          this._worker.WorkerSupportsCancellation = true;
          this._worker.DoWork += WaitChangeStatus;
          this._worker.RunWorkerAsync();
      }
  </code></pre>
  <p>And this is The Full Code :</p>
  <pre><code>class NFCReader
  {
      public int retCode, hCard, Protocol;
      int hContext;
      public bool connActive = false;
      public byte[] SendBuff = new byte[263];
      public byte[] RecvBuff = new byte[263];
      public int SendLen, RecvLen;
      internal enum SmartcardState
      {
          None = 0,
          Inserted = 1,
          Ejected = 2
      }
  
      public delegate void CardEventHandler();
      public event CardEventHandler CardInserted;
      public event CardEventHandler CardEjected;
      public event CardEventHandler DeviceDisconnected;
      private BackgroundWorker _worker;
      private Card.SCARD_READERSTATE RdrState;
      private string readername;
      private Card.SCARD_READERSTATE[] states;
      private void WaitChangeStatus(object sender, DoWorkEventArgs e)
      {
          while (!e.Cancel)
          {
              int nErrCode = Card.SCardGetStatusChange(hContext, 1000, ref states[0], 1);
  
              if (nErrCode == Card.SCARD_E_SERVICE_STOPPED)
              {
                  DeviceDisconnected();
                  e.Cancel = true;
              }
  
              //Check if the state changed from the last time.
              if ((this.states[0].RdrEventState &amp; 2) == 2)
              {
                  //Check what changed.
                  SmartcardState state = SmartcardState.None;
                  if ((this.states[0].RdrEventState &amp; 32) == 32 &amp;&amp; (this.states[0].RdrCurrState &amp; 32) != 32)
                  {
                      //The card was inserted. 
                      state = SmartcardState.Inserted;
                  }
                  else if ((this.states[0].RdrEventState &amp; 16) == 16 &amp;&amp; (this.states[0].RdrCurrState &amp; 16) != 16)
                  {
                      //The card was ejected.
                      state = SmartcardState.Ejected;
                  }
                  if (state != SmartcardState.None &amp;&amp; this.states[0].RdrCurrState != 0)
                  {
                      switch (state)
                      {
                          case SmartcardState.Inserted:
                              {
                                  //MessageBox.Show(&quot;Card inserted&quot;);
                                  CardInserted();
                                  break;
                              }
                          case SmartcardState.Ejected:
                              {
                                  //MessageBox.Show(&quot;Card ejected&quot;);
                                  CardEjected();
                                  break;
                              }
                          default:
                              {
                                  //MessageBox.Show(&quot;Some other state...&quot;);
                                  break;
                              }
                      }
                  }
                  //Update the current state for the next time they are checked.
                  this.states[0].RdrCurrState = this.states[0].RdrEventState;
              }
          }
      }
      public Card.SCARD_IO_REQUEST pioSendRequest;
      private int SendAPDUandDisplay(int reqType)
      {
          int indx;
          string tmpStr = &quot;&quot;;
  
          pioSendRequest.dwProtocol = Protocol;
          pioSendRequest.cbPciLength = 8;
  
          //Display Apdu In
          for (indx = 0; indx &lt;= SendLen - 1; indx++)
          {
              tmpStr = tmpStr + &quot; &quot; + string.Format(&quot;{0:X2}&quot;, SendBuff[indx]);
          }
  
          retCode = Card.SCardTransmit(hCard, ref pioSendRequest, ref SendBuff[0],
                               SendLen, ref pioSendRequest, ref RecvBuff[0], ref RecvLen);
  
          if (retCode != Card.SCARD_S_SUCCESS)
          {
              return retCode;
          }
  
          else
          {
              try
              {
                  tmpStr = &quot;&quot;;
                  switch (reqType)
                  {
                      case 0:
                          for (indx = (RecvLen - 2); indx &lt;= (RecvLen - 1); indx++)
                          {
                              tmpStr = tmpStr + &quot; &quot; + string.Format(&quot;{0:X2}&quot;, RecvBuff[indx]);
                          }
  
                          if ((tmpStr).Trim() != &quot;90 00&quot;)
                          {
                              //MessageBox.Show(&quot;Return bytes are not acceptable.&quot;);
                              return -202;
                          }
  
                          break;
  
                      case 1:
  
                          for (indx = (RecvLen - 2); indx &lt;= (RecvLen - 1); indx++)
                          {
                              tmpStr = tmpStr + string.Format(&quot;{0:X2}&quot;, RecvBuff[indx]);
                          }
  
                          if (tmpStr.Trim() != &quot;90 00&quot;)
                          {
                              tmpStr = tmpStr + &quot; &quot; + string.Format(&quot;{0:X2}&quot;, RecvBuff[indx]);
                          }
  
                          else
                          {
                              tmpStr = &quot;ATR : &quot;;
                              for (indx = 0; indx &lt;= (RecvLen - 3); indx++)
                              {
                                  tmpStr = tmpStr + &quot; &quot; + string.Format(&quot;{0:X2}&quot;, RecvBuff[indx]);
                              }
                          }
  
                          break;
  
                      case 2:
  
                          for (indx = 0; indx &lt;= (RecvLen - 1); indx++)
                          {
                              tmpStr = tmpStr + &quot; &quot; + string.Format(&quot;{0:X2}&quot;, RecvBuff[indx]);
                          }
  
                          break;
                  }
              }
              catch (IndexOutOfRangeException)
              {
                  return -200;
              }
          }
          return retCode;
      }
      private void ClearBuffers()
      {
          long indx;
  
          for (indx = 0; indx &lt;= 262; indx++)
          {
              RecvBuff[indx] = 0;
              SendBuff[indx] = 0;
          }
      }
      private bool AuthBlock(String block)
      {
          ClearBuffers();
          SendBuff[0] = 0xFF;                         // CLA
          SendBuff[2] = 0x00;                         // P1: same for all source types 
          SendBuff[1] = 0x86;                         // INS: for stored key input
          SendBuff[3] = 0x00;                         // P2 : Memory location;  P2: for stored key input
          SendBuff[4] = 0x05;                         // P3: for stored key input
          SendBuff[5] = 0x01;                         // Byte 1: version number
          SendBuff[6] = 0x00;                         // Byte 2
          SendBuff[7] = (byte)int.Parse(block);       // Byte 3: sectore no. for stored key input
          SendBuff[8] = 0x61;                         // Byte 4 : Key B for stored key input
          SendBuff[9] = (byte)int.Parse(&quot;1&quot;);         // Byte 5 : Session key for non-volatile memory
  
          SendLen = 0x0A;
          RecvLen = 0x02;
  
          retCode = SendAPDUandDisplay(0);
  
          if (retCode != Card.SCARD_S_SUCCESS)
          {
              //MessageBox.Show(&quot;FAIL Authentication! No:&quot; + retCode.ToString());
              return false;
          }
  
          return true;
      }
      public string GetCardUID()
      {
          string cardUID = &quot;&quot;;
          byte[] receivedUID = new byte[256];
          Card.SCARD_IO_REQUEST request = new Card.SCARD_IO_REQUEST();
          request.dwProtocol = Card.SCARD_PROTOCOL_T1;
          request.cbPciLength = System.Runtime.InteropServices.Marshal.SizeOf(typeof(Card.SCARD_IO_REQUEST));
          byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x00 };
          int outBytes = receivedUID.Length;
          int status = Card.SCardTransmit(hCard, ref request, ref sendBytes[0], sendBytes.Length, ref request, ref receivedUID[0], ref outBytes);
  
          if (status != Card.SCARD_S_SUCCESS)
              cardUID = &quot;&quot;;
          else
              cardUID = BitConverter.ToString(receivedUID.Take(4).ToArray()).Replace(&quot;-&quot;, string.Empty).ToLower();
          return cardUID;
      }
      public List&lt;string&gt; GetReadersList()
      {
          string ReaderList = &quot;&quot; + Convert.ToChar(0);
          int indx;
          int pcchReaders = 0;
          string rName = &quot;&quot;;
          List&lt;string&gt; lstReaders = new List&lt;string&gt;();
          //Establish Context
          retCode = Card.SCardEstablishContext(Card.SCARD_SCOPE_USER, 0, 0, ref hContext);
  
          if (retCode != Card.SCARD_S_SUCCESS)
          {
              throw new Exception(&quot;Error SCardEstablishContext&quot;);
          }
  
          // 2. List PC/SC card readers installed in the system
  
          retCode = Card.SCardListReaders(this.hContext, null, null, ref pcchReaders);
  
          if (retCode != Card.SCARD_S_SUCCESS)
          {
              throw new Exception(&quot;Error SCardListReaders&quot;);
          }
  
          byte[] ReadersList = new byte[pcchReaders];
  
          // Fill reader list
          retCode = Card.SCardListReaders(this.hContext, null, ReadersList, ref pcchReaders);
  
          if (retCode != Card.SCARD_S_SUCCESS)
          {
              throw new Exception(&quot;Error SCardListReaders&quot;);
          }
  
          rName = &quot;&quot;;
          indx = 0;
  
  
          while (ReadersList[indx] != 0)
          {
  
              while (ReadersList[indx] != 0)
              {
                  rName += (char)ReadersList[indx];
                  indx++;
              }
  
  
              lstReaders.Add(rName);
              rName = &quot;&quot;;
              indx++;
  
          }
          return lstReaders;
      }
      /*
      public bool CleanCard(int maxblock)
      {
          int i = 0;
          string clean = &quot;\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&quot;;
          while (i &lt; maxblock)
          {
              WriteBlock(clean, (i + 4).ToString());
              i++;
          }
          return true;
      }
      */
      public bool WriteBlock(String Text, String Block)
      {
  
          char[] tmpStr = Text.ToArray();
          int indx;
          if (AuthBlock(Block))
          {
              ClearBuffers();
              SendBuff[0] = 0xFF;                             // CLA
              SendBuff[1] = 0xD6;                             // INS
              SendBuff[2] = 0x00;                             // P1
              SendBuff[3] = (byte)int.Parse(Block);           // P2 : Starting Block No.
              SendBuff[4] = (byte)int.Parse(&quot;16&quot;);            // P3 : Data length
  
              for (indx = 0; indx &lt;= (tmpStr).Length - 1; indx++)
              {
                  SendBuff[indx + 5] = (byte)tmpStr[indx];
              }
              SendLen = SendBuff[4] + 5;
              RecvLen = 0x02;
  
              retCode = SendAPDUandDisplay(2);
  
              if (retCode != Card.SCARD_S_SUCCESS)
                  return false;
              else
                  return true;
          }
          else
              return false;
      }
      /*
      public string ReadString() 
      {
          int i = 0;
          string ret=&quot;&quot;;
          string tmpStr= String.Concat(ReadBlock((i + 4).ToString()));
          ret += String.Concat(tmpStr);
          i++;
          while (!(tmpStr.Contains(&quot;\0\0&quot;)))
          {
              tmpStr = String.Concat(ReadBlock((i + 4).ToString()));
              ret += tmpStr;
              i++;
          }
          return ret.Replace(&quot;\0&quot;, string.Empty);
  
      */
      /*
      public bool WriteString(String Text) 
      {
          string[] parts = Helper.SplitByLength(Text, 16).ToArray();
          double textlen = Text.Length, delim = 16;
          int blocklen = (int)Math.Ceiling(textlen / delim);
          for (int i = 0; i &lt; blocklen; i++)
          {
              if(!WriteBlock(parts[i],(i+4).ToString()))return false;
          }
          return true;
      }
      */
      public byte[] ReadBlock(String Block)
      {
          byte[] tmpStr;
          int indx;
  
          if (AuthBlock(Block))
          {
              ClearBuffers();
              SendBuff[0] = 0xFF; // CLA 
              SendBuff[1] = 0xB0;// INS
              SendBuff[2] = 0x00;// P1
              SendBuff[3] = (byte)int.Parse(Block);// P2 : Block No.
              SendBuff[4] = (byte)int.Parse(&quot;16&quot;);// Le
  
              SendLen = 5;
              RecvLen = SendBuff[4] + 2;
  
              retCode = SendAPDUandDisplay(2);
  
              if (retCode == -200)
              {
                  return new byte[] { };
              }
  
              if (retCode == -202)
              {
                  return new byte[] { };
              }
  
              if (retCode != Card.SCARD_S_SUCCESS)
              {
                  return new byte[] { };
              }
  
              // Display data in text format
              List&lt;byte&gt; t = new List&lt;byte&gt;();
              for (indx = 0; indx &lt;= RecvLen - 1; indx++)
              {
                  t.Add(RecvBuff[indx]);
              }
              tmpStr = t.ToArray();
              return tmpStr;
          }
          else return new byte[] { };
      }
      public bool Connect()
      {
          string readerName = GetReadersList()[0];
          connActive = true;
          retCode = Card.SCardConnect(hContext, readerName, Card.SCARD_SHARE_SHARED,
                               Card.SCARD_PROTOCOL_T0 | Card.SCARD_PROTOCOL_T1, ref hCard, ref Protocol);
          if (retCode != Card.SCARD_S_SUCCESS)
          {
              connActive = false;
              return false;
          }
          else
              return true;
      }
      public void Disconnect()
      {
          if (connActive)
          {
              retCode = Card.SCardDisconnect(hCard, Card.SCARD_UNPOWER_CARD);
          }
          //retCode = Card.SCardReleaseContext(hCard);
      }
      public string Transmit(byte[] buff)
      {
          string tmpStr = &quot;&quot;;
          int indx;
  
          ClearBuffers();
  
          for (int i = 0; i &lt; buff.Length; i++)
          {
              SendBuff[i] = buff[i];
          }
          SendLen = 5;
          RecvLen = SendBuff[SendBuff.Length - 1] + 2;
  
          retCode = SendAPDUandDisplay(2);
  
  
          // Display data in text format
          for (indx = 0; indx &lt;= RecvLen - 1; indx++)
          {
              tmpStr = tmpStr + Convert.ToChar(RecvBuff[indx]);
          }
  
          return tmpStr;
      }
      public void Watch()
      {
          this.RdrState = new Card.SCARD_READERSTATE();
          readername = GetReadersList()[0];
          this.RdrState.RdrName = readername;
  
          states = new Card.SCARD_READERSTATE[1];
          states[0] = new Card.SCARD_READERSTATE();
          states[0].RdrName = readername;
          states[0].UserData = 0;
          states[0].RdrCurrState = Card.SCARD_STATE_EMPTY;
          states[0].RdrEventState = 0;
          states[0].ATRLength = 0;
          states[0].ATRValue = null;
          this._worker = new BackgroundWorker();
          this._worker.WorkerSupportsCancellation = true;
          this._worker.DoWork += WaitChangeStatus;
          this._worker.RunWorkerAsync();
      }
      public NFCReader()
      {
      }
  }
  </code></pre>