SCardCancel
3495 LONG SCardCancel(SCARDCONTEXT hContext) 3496 { 3497 LONG dwContextIndex; 3498 LONG rv = SCARD_S_SUCCESS; 3499 3500 PROFILE_START 3501 3502 dwContextIndex = SCardGetContextIndice(hContext); 3503 if (dwContextIndex == -1) 3504 return SCARD_E_INVALID_HANDLE; 3505 3506 /* 3507 * Set the block status for this Context so blocking calls will 3508 * complete 3509 */ 3510 psContextMap[dwContextIndex].contextBlockStatus = BLOCK_STATUS_RESUME; 3511 3512 if (StatSynchronizeContext(hContext)) 3513 rv = SCARD_F_INTERNAL_ERROR; 3514 3515 PROFILE_END(rv) 3516 3517 return rv; 3518 } |
SCardCancel 的作用,取消所有阻塞请求,当然了这些 SCard 前缀的函数里,只有
SCardGetStatusChange 是会发生阻塞的。
而在 SCardGetStatusChange 的实现里
有两处用到
2279 if (BLOCK_STATUS_RESUME 2280 == psContextMap[dwContextIndex].contextBlockStatus) 2281 break; 2301 if (psContextMap[dwContextIndex].contextBlockStatus == BLOCK_STATUS_RESUME) 2302 rv = SCARD_E_CANCELLED; |
也就是无条件跳出上面提到的 while(1) 循环体。从而实现取消阻塞请求。
前面提到的
3585 static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID) |
实现中也就是上下文初始化过程
3595 psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME; |
原来应用上下文初始化状态的上下文阻塞状态初始化为 BLOCK_STATUS_RESUME
根据搜索, readerfactory.c 也有一处,用到 BLOCK_STATUS_RESUME
1013 LONG RFUnblockReader(PREADER_CONTEXT rContext) 1014 { 1015 rContext->dwBlockStatus = BLOCK_STATUS_RESUME; 1016 return SCARD_S_SUCCESS; 1017 } |
从函数名称上看,绝对也是用于取消阻塞的。
这是函数属于服务端,而且服务端实际上正如它自己注释的,目前没有用到这个函数。
而 BLOCK_STATUS_BLOCKING 用到的地发有
在 SCardGetStatusChange 的实现中
1988 psContextMap[dwContextIndex].contextBlockStatus = BLOCK_STATUS_BLOCKING; |
1988 行后开始上面提到的 readerStates 和 currReader 的比对。
而后面的不断探测设备事件的循环体中,如果 contextBlockStatus 变为
BLOCK_STATUS_RESUME , ( 调用 SCardCancel ) ,则退出循环体。
SCardGetStatusChange 覆盖 1872~2312 行。
实现部分有些过长的。结束了。
“ 往事不要再提,人生几多风雨 ...”
可是目前,还要回去,回到 testpcsc.c
146 if (SCARD_E_NO_READERS_AVAILABLE == rv) 147 { 148 printf("Testing SCardGetStatusChange /n"); 149 printf("Please insert a working reader/t: "); 150 (void)fflush(stdout); 151 rgReaderStates[0].szReader = "?PnP?//Notification"; 152 rgReaderStates[0].dwCurrentState = SCARD_STATE_EMPTY; 153 154 rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1); 155 test_rv(rv, hContext, PANIC); 156 } |
明白了吧,很清楚了吧。
154 rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1); |
永久等待,直到有读卡器事件出现。
I'm here for you.
接下来
157 158 printf("Testing SCardListReaders/t: "); 159 #ifdef USE_AUTOALLOCATE 160 dwReaders = SCARD_AUTOALLOCATE; 161 rv = SCardListReaders(hContext, mszGroups, (LPSTR)&mszReaders, &dwReaders); 162 #else 163 rv = SCardListReaders(hContext, mszGroups, NULL, &dwReaders); 164 test_rv(rv, hContext, PANIC);
165 166 printf("Testing SCardListReaders/t: "); 167 mszReaders = calloc(dwReaders, sizeof(char)); 168 rv = SCardListReaders(hContext, mszGroups, mszReaders, &dwReaders); 169 #endif 170 test_rv(rv, hContext, DONT_PANIC); 171 172 /* 173 * Have to understand the multi-string here 174 */ 175 p = 0; 176 for (i = 0; i+1 < dwReaders; i++) 177 { 178 ++p; 179 printf(GREEN "Reader %02d: %s/n" NORMAL , p, &mszReaders[i]); 180 iList[p] = i; 181 while (mszReaders[++i] != 0) ; 182 } |
161 行,解释过了。
163 行,解释过了。
因为能过到 157 行的就是等到了读卡器事件。
175~182 行,打印出来到的读卡器的名称。
184 if (p > 1) 185 do 186 { 187 char input[80]; 188 189 printf("Enter the reader number/t/t: "); 190 (void)fgets(input, sizeof(input), stdin); 191 (void)sscanf(input, "%d", &iReader); 192 193 if (iReader > p || iReader <= 0) 194 printf("Invalid Value - try again/n"); 195 } 196 while (iReader > p || iReader <= 0); 197 else 198 iReader = 1; |
184~198 行,说明如果事件过后,来了 n 个读卡器,当然 n 必须大于等于1 .
如果 n 大于1,那么 testpcsc.c 也不知道怎么办。上报 APPLICATION ,让
APPLICATION 做出选择,挑选需要的读卡器。
如果 n 等于,那么只有一个读卡器来到,就是它了,不用选择了。
199 200 rgReaderStates[0].szReader = &mszReaders[iList[iReader]]; 201 rgReaderStates[0].dwCurrentState = SCARD_STATE_EMPTY; 202 203 printf("Waiting for card insertion/t: "); 204 (void)fflush(stdout); 205 rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1); 206 test_rv(rv, hContext, PANIC); 207 if (rgReaderStates[0].dwEventState & SCARD_STATE_UNKNOWN) 208 { 209 printf("/nA reader has been connected/disconnected/n"); 210 goto wait_for_card_again; 211 } |
正如 209 行所提示,有可能读卡器来后又走了。
如果读卡器没有拔出,而且读卡器内已经插入卡,则
212 213 printf("Testing SCardConnect/t/t: "); 214 rv = SCardConnect(hContext, &mszReaders[iList[iReader]], 215 SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, 216 &hCard, &dwPref); 217 test_rv(rv, hContext, PANIC); |