4

我正在尝试检测卡何时插入读卡器。如果我像这样进行讨厌的轮询循环:

      public struct SCARD_READERSTATE
        {
            [MarshalAs(UnmanagedType.LPWStr)]
            public string szReader;
            public byte[] pvUserData;
            public byte[] rgbAtr;
            public uint dwCurrentState;
            public uint dwEventState;
            public uint cbAtr;
        }

   byte[] atr = null;
   SCARD_READERSTATE[] rs = new SCARD_READERSTATE[1];
   rs[0].szReader = readersList[0];
   rs[0].dwCurrentState = SCARD_STATE_UNAWARE;
   rs[0].dwEventState = SCARD_STATE_PRESENT;
   int hctx = hContext.ToInt32();
   var cardResult = SCardGetStatusChange(hctx, 100, rs, 1);
   if (cardResult == 0 && rs[0].cbAtr > 0 && rs[0].rgbAtr != null)
   {
       atr = new byte[rs[0].cbAtr];
       Array.Copy(rs[0].rgbAtr, atr, rs[0].cbAtr);
   }

  while ( (rs[0].dwCurrentState & SCARD_STATE_PRESENT) == 0)
  {
       rs = new SCARD_READERSTATE[1];
       rs[0].szReader = readersList[0];
       //rs[0].dwCurrentState = SCARD_STATE_PRESENT;
       //rs[0].dwEventState = SCARD_STATE_PRESENT;
       SCardGetStatusChange(hctx, 100000000, rs, 1);
       System.Threading.Thread.Sleep(1000);
  }

它有效,但它有一个讨厌的线程睡眠。理想情况下,我想在后台线程上对 SCardGetStatusChange 进行阻塞调用,然后显示事件。

显然,通过将 szReader 设置为值 "\\?PnP?\Notification" 它应该阻塞,只要结构中的其他所有内容都是 0。

我已将代码更改为

   rs[0].szReader = "\\\\?PnP?\\Notification";
   rs[0].cbAtr = 0;
   rs[0].dwCurrentState = 0;
   rs[0].dwEventState = 0;
   rs[0].pvUserData = new byte[0];
   rs[0].rgbAtr = new byte0];
   SCardGetStatusChange(hctx, 100000000, rs, 1);

但它只是立即返回成功结果。那里的任何 pInvoke 大师都可以看到问题所在吗?

4

1 回答 1

5
  1. 在您的示例中,如果您将 dwEventState 复制到 dwCurrentState 然后重置 dwEventState,则第二次调用SCardGetStatusChange应该阻塞,因此不需要睡眠。

  2. "\\?PnP?\Notification" 结构是告诉您何时连接了新的智能卡读卡器,而不是何时插入卡。从 SCardGetStatusChange 上的 MSDN 页面

    要收到新智能卡读卡器到达的通知,请将 SCARD_READERSTATE 结构的 szReader 成员设置为“\\?PnP?\Notification”,并将该结构的所有其他成员设置为零。

  3. 使用“\\?PnP?\Notification”结构时:

    • 和字段应设置pvUserDatargbAttrnull
      • anew byte[0]是一个指向零长度数组的有效指针,但这里的 API 需要的是空指针或零值)
    • dwCurrentState 的高 16 位应包含当前阅读器计数
      • IErs[0].dwCurrentState = (readerCount << 16);
      • MSDN 页面目前在这一点上不准确。
于 2013-05-09T17:15:54.697 回答