SCardGetStatusChange
SCardGetStatusChange 定义在 winscard_clnt.c
实现如下:
1872 LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, 1873 LPSCARD_READERSTATE_A rgReaderStates, DWORD cReaders) 1874 { 1875 PSCARD_READERSTATE_A currReader; 1876 PREADER_STATE rContext; 1877 long dwTime = dwTimeout; 1878 DWORD dwState; 1879 DWORD dwBreakFlag = 0; 1880 int j; 1881 LONG dwContextIndex; 1882 int currentReaderCount = 0; 1883 LONG rv = SCARD_S_SUCCESS; 1884 1885 PROFILE_START 1886 1887 if ((rgReaderStates == NULL && cReaders > 0) 1888 || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS)) 1889 return SCARD_E_INVALID_PARAMETER; 1890 1891 /* Check the integrity of the reader states structures */ 1892 for (j = 0; j < cReaders; j++) 1893 { 1894 if (rgReaderStates[j].szReader == NULL) 1895 return SCARD_E_INVALID_VALUE; 1896 } |
1887~1889 行, 1892~1896 行,两组条件检查, easy ,不是吗?
1898 /* return if all readers are SCARD_STATE_IGNORE */ 1899 if (cReaders > 0) 1900 { 1901 int nbNonIgnoredReaders = cReaders; 1902 1903 for (j=0; j<cReaders; j++) 1904 if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1905 nbNonIgnoredReaders--; 1906 1907 if (0 == nbNonIgnoredReaders) 1908 return SCARD_S_SUCCESS; 1909 } |
1898~1909 行说明如果当前所有读卡器状态是 SCARD_STATE_IGNORE ,
则直接返回,因为这个标志,代表 APPLICATION 不想知道读卡器的状态。
不想知道,就不要再去获取读卡器的状态了。 APPLICATION 不想要,
ResourceManager 也不好意硬给。
SCARD_STATE_xxx 等 n 多状态,见上面的卷 5 分析。
1911 rv = SCardCheckDaemonAvailability(); 1912 if (rv != SCARD_S_SUCCESS) 1913 return rv; 1914 1915 /* 1916 * Make sure this context has been opened 1917 */ 1918 dwContextIndex = SCardGetContextIndice(hContext); 1919 if (dwContextIndex == -1) 1920 return SCARD_E_INVALID_HANDLE; 1921 1922 (void)SYS_MutexLock(psContextMap[dwContextIndex].mMutex); 1923 1924 /* check the context is still opened */ 1925 dwContextIndex = SCardGetContextIndice(hContext); 1926 if (dwContextIndex == -1) 1927 /* the context is now invalid 1928 * -> another thread may have called SCardReleaseContext 1929 * -> so the mMutex has been unlocked */ 1930 return SCARD_E_INVALID_HANDLE; |
1911~1930 行,略过,说了 n 次。
1938 if (cReaders == 0) 1939 { 1940 while (1) 1941 { 1942 int i;
1943 1944 rv = SCardCheckDaemonAvailability(); 1945 if (rv != SCARD_S_SUCCESS) 1946 goto end; 1947 1948 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 1949 { 1950 if ((readerStates[i])->readerID != 0) 1951 { 1952 /* Reader was found */ 1953 rv = SCARD_S_SUCCESS; 1954 goto end; 1955 } 1956 } |
1938 行,可是特殊情况, cReaders==0 ,表示想等待第一台可用的读卡器。
只要有一台可用,则 SCardGetStatusChange 成功返回。
1944 行,略过。
1948~1956 行, 再次查询 readerStates 状态,如果查到有可用的读卡器,
则成功返回。别忘记, readerStates 可是共享内存。
1958 if (dwTimeout == 0) 1959 { 1960 /* return immediately - no reader available */ 1961 rv = SCARD_E_READER_UNAVAILABLE; 1962 goto end; 1963 } |
1958 行表示即使目前没有可用的读卡器,函数也立刻返回,
不用进入超时等待可用的读卡器。
1965 dwTime = WaitForPcscdEvent(hContext, dwTime); 1966 if (dwTimeout != INFINITE) 1967 { 1968 if (dwTime <= 0) 1969 { 1970 rv = SCARD_E_TIMEOUT; 1971 goto end; 1972 } 1973 }
1974 } 1975 } |
1965~1975 行,在 dwTime 设定的时间内等待读卡器事件的出现。事件是通过文件 fifo 来实现的。
1877 long dwTime = dwTimeout; |
如果 dwTimeout 没有设置为 INFINITE ,则如果在设定时间内,
没有出现事件,则超时返回。
否则 WaitForPcscdEvent 将永远等待。
Waiting for events from Monday to Sunday.
1965 行, WaitForPcscdEvent 在 winscard_clnt.c 中定义
实现如下:
1724 static long WaitForPcscdEvent(SCARDCONTEXT hContext, long dwTime) 1725 { 1726 char filename[FILENAME_MAX]; 1727 char buf[1]; 1728 int fd, r; 1729 struct timeval tv, *ptv = NULL; 1730 struct timeval before, after; 1731 fd_set read_fd; 1732 1733 if (INFINITE != dwTime) 1734 { 1735 if (dwTime < 0) 1736 return 0; 1737 gettimeofday(&before, NULL); 1738 tv.tv_sec = dwTime/1000; 1739 tv.tv_usec = dwTime*1000 - tv.tv_sec*1000000; 1740 ptv = &tv; 1741 } 1742 1743 (void)snprintf(filename, sizeof(filename), "%s/event.%d.%ld", 1744 PCSCLITE_EVENTS_DIR, SYS_GetPID(), hContext); 1745 r = mkfifo(filename, 0644); 1746 if (-1 == r) 1747 { 1748 Log2(PCSC_LOG_CRITICAL, "Can't create event fifo: %s", strerror(errno)); 1749 goto exit; 1750 } 1751
1752 fd = SYS_OpenFile(filename, O_RDONLY | O_NONBLOCK, 0); 1753 1754 /* the file may have been removed between the mkfifo() and open() */ 1755 if (-1 != fd) 1756 { 1757 FD_ZERO(&read_fd); 1758 FD_SET(fd, &read_fd); 1759 1760 (void)select(fd+1, &read_fd, NULL, NULL, ptv); 1761 1762 (void)SYS_ReadFile(fd, buf, 1); 1763 (void)SYS_CloseFile(fd); 1764 } 1765 1766 (void)SYS_RemoveFile(filename); 1767 1768 if (INFINITE != dwTime) 1769 { 1770 long int diff; 1771 1772 gettimeofday(&after, NULL); 1773 diff = time_sub(&after, &before); 1774 dwTime -= diff/1000; 1775 } 1776 1777 exit: 1778 return dwTime; 1779 } |
1738 行, tv.tv_sec = dwTime/1000;
说明 dwTime 的粒度是 ms.
1745 行 mkfifo 明确地说明, event 就是 fifo ,文件 fifo 不是匿名 fifo 通讯。
1752 行 SYS_OpenFile 打开 fifo 文件,非阻塞方式。 fifo 文件存在于
PCSCLITE_EVENTS_DIR 也就是 /var/run/pcscd/pcscd.events
文件名以 APPLICATION 的 pid 和 hContext 组合。
1760 行 select 进行超时读取。
1768~1775 行 返回剩余的等待时间。当然如果是 dwTime==INFINITE ,
则 select 将永久等待,知道 fifo 可读。
select 永久等待。因为它知道,会有读卡器来。所以它一直等。
而在现实中呢?比如 select 某人,永久?那只是在歌词所咏颂的情景中才会出现的故事。
现实中的绝大部分故事解决注定是悲剧。
现实总是和理想相差太远。昨天盼今天,今天盼明天,年头盼年尾,
今年盼明年。所谓希望总是有的。哈哈 ...
问:想知道 fifo 是谁写入的。
答案是,继续看吧,到了第三章的服务端解说,就有知道的。
回头,继续。
回到 SCardGetStatusChange
1938~1975 完成。但是 1935~1936 有行,原版注释
1935 * This is DEPRECATED. Use the special reader name //?PnP?/Notification 1936 * instead |
也就是 1938~1975 已经放弃了,估计是为了兼容以前的版本,现在要探测
可用的读卡器,是使用特殊的读卡器名字来调用 SCardGetStatusChange 。
这个名字就是 //?PnP?/Notification
。多 in 的名字呀, PnP ,
这和 ms 有很大的关系呀,和大佬攀上关系。那当然好。现实中也有很多
这样高攀的例子。别抱怨,你有背景吗?你有天线吗?没有,那么请 take a hike.
继续。
1882 int currentReaderCount = 0; currentReaderCount 当前系统中的读卡器数量初始化为0 . 1976 1977 /* 1978 * End of search for readers 1979 */ 1980 1981 /* Clear the event state for all readers */ 1982 for (j = 0; j < cReaders; j++) 1983 rgReaderStates[j].dwEventState = 0; 1984 1985 /* Now is where we start our event checking loop */ 1986 Log1(PCSC_LOG_DEBUG, "Event Loop Start"); 1987 1988 psContextMap[dwContextIndex].contextBlockStatus = BLOCK_STATUS_BLOCKING; 1989
|
1976~1989 行,正如注释说。
1990 /* Get the initial reader count on the system */
1991 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1992 if ((readerStates[j])->readerID != 0)
1993 currentReaderCount++; |
1990~1993 获取系统中目前可用的读卡器数量 . 目的是准备和参数中传入
的给定名字的读卡器进行比对,确定状态变化。
1995 j = 0; 1996 do 1997 { 1998 rv = SCardCheckDaemonAvailability(); 1999 if (rv != SCARD_S_SUCCESS) 2000 { 2001 if (psContextMap[dwContextIndex].mMutex) 2002 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2003 2004 PROFILE_END(rv) 2005 2006 return rv; 2007 } 2008 2009 currReader = &rgReaderStates[j]; |
接下来就逐个比对了。
1998 行,再次判断服务端是否存在。
2009 行,从参数获取第 j 个读卡器状态。要开始比对了。
2012 if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE)) 2013 { 2014 LPSTR lpcReaderName; 2015 int i; 2016 2017 /************ Looks for correct readernames *********************/ 2018 2019 lpcReaderName = (char *) currReader->szReader; 2020
2021 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++) 2022 { 2023 if (strcmp(lpcReaderName, (readerStates[i])->readerName) == 0) 2024 break; 2025 } |
2012 行, SCARD_STATE_IGNORE ,前面提过了。
2023 行,开始比对名字,把参数传入的读卡器数组名字逐个和所有的 readerStates 的 readerName 进行比较。
2028 if (i == PCSCLITE_MAX_READERS_CONTEXTS) 2029 { |
2028~2029 说明参数传入的读卡器 currReader 当前不存在于系统中。
存在两种可能,就是 currReader 的名字是否是 "?PnP?//Notification" ,正如上面所说的,
如果和 ms 有莫大关系,自然要特殊情况特殊处理呀。
特殊关照如下
2031 if (strcasecmp(lpcReaderName, "?PnP?//Notification") == 0) 2032 { 2033 int k, newReaderCount = 0; 2034 2035 for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++) 2036 if ((readerStates[k])->readerID != 0) 2037 newReaderCount++; 2038 2039 if (newReaderCount != currentReaderCount) 2040 { 2041 Log1(PCSC_LOG_INFO, "Reader list changed"); 2042 currentReaderCount = newReaderCount; 2043 2044 currReader->dwEventState |= SCARD_STATE_CHANGED; 2045 dwBreakFlag = 1; 2046 } 2047 } |
2031~2047 看来有些着急,毕竟是 ms 委托的。
原先在 1993 的时候,已经获得了 currentReaderCount 。
现在立刻再次获取当前的 ReaderCount ,也就是 newReaderCount 。
如果相比 currentReaderCount ,有变化,不管少了还是多了。赶紧上报。并标志
currReader->dwEventState.
2048 else 2049 { 2050 currReader->dwEventState = SCARD_STATE_UNKNOWN | SCARD_STATE_UNAVA ILABLE; 2051 if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN)) 2052 { 2053 currReader->dwEventState |= SCARD_STATE_CHANGED; 2054 /* 2055 * Spec says use SCARD_STATE_IGNORE but a removed USB 2056 * reader with eventState fed into currentState will 2057 * be ignored forever 2058 */ 2059 dwBreakFlag = 1; 2060 } 2061 } |
2048 行说明对于 currReader 没有比对成功。修改 currReader->dwEventState.
SCARD_STATE_xxx ,前面提过了,卷 5 也提过了。
接下来是什么呢?当然是比对成功情况下的具体处理。
更新 currReaderd 的 dwEventState.
2063 else 2064 { 2065 /* The reader has come back after being away */ 2066 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN) 2067 { 2068 currReader->dwEventState |= SCARD_STATE_CHANGED;
2069 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN; 2070 Log0(PCSC_LOG_DEBUG); 2071 dwBreakFlag = 1; 2072 } 2073 2074 /*****************************************************************/ 2075 2076 /* Set the reader status structure */ 2077 rContext = readerStates[i]; 2078 2076 /* Set the reader status structure */ 2077 rContext = readerStates[i]; 2078 2079 /* Now we check all the Reader States */ 2080 dwState = rContext->readerState; 2081 2082 /* only if current state has an non null event counter */ 2083 if (currReader->dwCurrentState & 0xFFFF0000) 2084 { 2085 int currentCounter, stateCounter; 2086 2087 stateCounter = (dwState >> 16) & 0xFFFF; 2088 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF; 2089 2090 /* has the event counter changed since the last call? */ 2091 if (stateCounter != currentCounter) 2092 { 2093 currReader->dwEventState |= SCARD_STATE_CHANGED; 2094 Log0(PCSC_LOG_DEBUG); 2095 dwBreakFlag = 1; 2096 } 2097 2098 /* add an event counter in the upper word of dwEventState */ 2099 currReader->dwEventState = 2100 ((currReader->dwEventState & 0xffff ) 2101 | (stateCounter << 16)); 2102 } |
原来 currReader->dwCurrentState 的类型是 unsigned long(4 字节 , 由体系结构决定 ), 高 16 位 (31~16bit) 用来装 currReader 的当前事件计数。
2083~2102 行,把 currReader 和前面找到的和 currReader 读卡器名字相同的 readerStates
进行计数比较,确定系统中原本已经存在的读卡器是否发生了新的事件。原本就存在于系统中的读卡器,是否发生状态变化,还得依靠计数。
把当前计数更新到 currReader->dwEventState.
接着从 readerStates 也就是共享内存中进一步获取当前读卡器当前状态,与 currReader->dwCurrentState 也就是 APPLICATION 传入的状态,进行比对,进一步确定发生的具体事件。
2104 /*********** Check if the reader is in the correct state ********/ 2105 if (dwState & SCARD_UNKNOWN) 2106 { 2107 /* reader is in bad state */ 2108 currReader->dwEventState = SCARD_STATE_UNAVAILABLE; 2109 if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE)) 2110 { 2111 /* App thinks reader is in good state and it is not */ 2112 currReader->dwEventState |= SCARD_STATE_CHANGED; 2113 Log0(PCSC_LOG_DEBUG); 2114 dwBreakFlag = 1; 2115 } 2116 } 2117 else 2118 { 2119 /* App thinks reader in bad state but it is not */ 2120 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE) 2121 { 2122 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE; 2123 currReader->dwEventState |= SCARD_STATE_CHANGED; 2124 Log0(PCSC_LOG_DEBUG); 2125 dwBreakFlag = 1; 2126 } 2127 } 2128 2129 /********** Check for card presence in the reader **************/
2130 2131 if (dwState & SCARD_PRESENT) 2132 { 2133 /* card present but not yet powered up */ 2134 if (0 == rContext->cardAtrLength) 2135 /* Allow the status thread to convey information */ 2136 (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10); 2137 2138 currReader->cbAtr = rContext->cardAtrLength; 2139 memcpy(currReader->rgbAtr, rContext->cardAtr, 2140 currReader->cbAtr); 2141 } 2142 else 2143 currReader->cbAtr = 0; 2144 2145 /* Card is now absent */ 2146 if (dwState & SCARD_ABSENT) 2147 { 2148 currReader->dwEventState |= SCARD_STATE_EMPTY; 2149 currReader->dwEventState &= ~SCARD_STATE_PRESENT; 2150 currReader->dwEventState &= ~SCARD_STATE_UNAWARE; 2151 currReader->dwEventState &= ~SCARD_STATE_IGNORE; 2152 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN; 2153 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE; 2154 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH; 2155 currReader->dwEventState &= ~SCARD_STATE_MUTE; 2156 currReader->dwEventState &= ~SCARD_STATE_INUSE; 2157 2158 /* After present the rest are assumed */ 2159 if (currReader->dwCurrentState & SCARD_STATE_PRESENT) 2160 { 2161 currReader->dwEventState |= SCARD_STATE_CHANGED; 2162 Log0(PCSC_LOG_DEBUG); 2163 dwBreakFlag = 1;
2164 } 2165 } 2166 /* Card is now present */ 2167 else if (dwState & SCARD_PRESENT) 2168 { 2169 currReader->dwEventState |= SCARD_STATE_PRESENT; 2170 currReader->dwEventState &= ~SCARD_STATE_EMPTY; 2171 currReader->dwEventState &= ~SCARD_STATE_UNAWARE; 2172 currReader->dwEventState &= ~SCARD_STATE_IGNORE; 2173 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN; 2174 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE; 2175 currReader->dwEventState &= ~SCARD_STATE_MUTE; 2176 2177 if (currReader->dwCurrentState & SCARD_STATE_EMPTY) 2178 { 2179 currReader->dwEventState |= SCARD_STATE_CHANGED; 2180 Log0(PCSC_LOG_DEBUG); 2181 dwBreakFlag = 1; 2182 } 2183 2184 if (dwState & SCARD_SWALLOWED) 2185 { 2186 currReader->dwEventState |= SCARD_STATE_MUTE; 2187 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE)) 2188 { 2189 currReader->dwEventState |= SCARD_STATE_CHANGED; 2190 Log0(PCSC_LOG_DEBUG); 2191 dwBreakFlag = 1; 2192 } 2193 } 2194 else 2195 {
2196 /* App thinks card is mute but it is not */ 2197 if (currReader->dwCurrentState & SCARD_STATE_MUTE) 2198 { 2199 currReader->dwEventState |= SCARD_STATE_CHANGED; 2200 Log0(PCSC_LOG_DEBUG); 2201 dwBreakFlag = 1; 2202 } 2203 } 2204 } |
2104~2204 都很好理解的,主要目的就是更新 currReader->dwEventState.
2205 2206 /* Now figure out sharing modes */ 2207 if (rContext->readerSharing == -1) 2208 { 2209 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE; 2210 currReader->dwEventState &= ~SCARD_STATE_INUSE; 2211 if (currReader->dwCurrentState & SCARD_STATE_INUSE) 2212 { 2213 currReader->dwEventState |= SCARD_STATE_CHANGED; 2214 Log0(PCSC_LOG_DEBUG); 2215 dwBreakFlag = 1; 2216 } 2217 } 2218 else if (rContext->readerSharing >= 1) 2219 { 2220 /* A card must be inserted for it to be INUSE */ 2221 if (dwState & SCARD_PRESENT) 2222 { 2223 currReader->dwEventState |= SCARD_STATE_INUSE; 2224 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE; 2225 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2226 { 2227 currReader->dwEventState |= SCARD_STATE_CHANGED; 2228 Log0(PCSC_LOG_DEBUG); 2229 dwBreakFlag = 1; 2230 } 2231 } 2232 } 2233 else if (rContext->readerSharing == 0) 2234 { 2235 currReader->dwEventState &= ~SCARD_STATE_INUSE; 2236 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE; 2237 2238 if (currReader->dwCurrentState & SCARD_STATE_INUSE) 2239 { 2240 currReader->dwEventState |= SCARD_STATE_CHANGED; 2241 Log0(PCSC_LOG_DEBUG); 2242 dwBreakFlag = 1; 2243 } 2244 else if (currReader-> dwCurrentState 2245 & SCARD_STATE_EXCLUSIVE) 2246 { 2247 currReader->dwEventState |= SCARD_STATE_CHANGED; 2248 Log0(PCSC_LOG_DEBUG); 2249 dwBreakFlag = 1; 2250 } 2251 } |
2205~2251 行,对共享模式进行特殊处理。
rContext->readerSharing ==-1 表示目前读卡器处于排它模式,但是没有任何一个 APPLICATION 在使用读卡器。
rContext->readerSharing >= 1 表示目前读卡器处于共享模式。且有多个应用同时在使用
读卡器。而 rContext->readerSharing 的值就是当前在该读卡器上所打开的上下文数量。
rContext->readerSharing == 0
rContext->readerSharing == 0 表示当前的 readerStates 已经处于初始状态。发生在 reader
被移除。
2252
2253 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE) 2254 { 2255 /* 2256 * Break out of the while .. loop and return status 2257 * once all the status's for all readers is met 2258 */ 2259 currReader->dwEventState |= SCARD_STATE_CHANGED; 2260 Log0(PCSC_LOG_DEBUG); 2261 dwBreakFlag = 1; 2262 } 2263 } /* End of SCARD_STATE_UNKNOWN */ 2264 } /* End of SCARD_STATE_IGNORE */ |
2253 行 表示应用不知道目前读卡器的状态。
2259 行 表示告知应用读卡器状态发生变化了。
2265 2266 /* Counter and resetter */ 2267 j++; 2268 if (j == cReaders) 2269 { 2270 /* go back to the first reader */ 2271 j = 0; 2272 2273 /* Declare all the break conditions */ 2274 2275 /* Break if UNAWARE is set and all readers have been checked */ 2276 if (dwBreakFlag == 1) 2277 break; 2278 2279 if (BLOCK_STATUS_RESUME 2280 == psContextMap[dwContextIndex].contextBlockStatus) 2281 break; 2282 2283 /* Only sleep once for each cycle of reader checks. */ 2284 dwTime = WaitForPcscdEvent(hContext, dwTime); 2285 2286 if (dwTimeout != INFINITE) 2287 { 2288 /* If time is greater than timeout and all readers have been
2289 * checked 2290 */ 2291 if (dwTime <= 0) 2292 { 2293 rv = SCARD_E_TIMEOUT; 2294 goto end; 2295 } 2296 } 2297 } 2298 } 2299 while (1); |
2265~2299 行,很好理解。
2284 行, WaitForPcscdEvent ,在每一次 while(1) 大循环中,等待事件。发生变化,更新
currReader 的各状态。这就是 while(1) 内部循环体的任务。
2300 2301 if (psContextMap[dwContextIndex].contextBlockStatus == BLOCK_STATUS_RESUME) 2302 rv = SCARD_E_CANCELLED; 2303 2304 end: 2305 Log1(PCSC_LOG_DEBUG, "Event Loop End"); 2306 2307 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex); 2308 2309 PROFILE_END(rv) 2310 2311 return rv; 2312 } |
在 SCardGetStatusChange 解说结束前,说说
contextBlockStatus ,这个存在于
175 static struct _psContextMap 176 { 177 DWORD dwClientID; /**< Client Connection ID */ 178 SCARDCONTEXT hContext; /**< Application Context ID */ 179 DWORD contextBlockStatus; 180 PCSCLITE_MUTEX_T mMutex; /**< Mutex for this context */
181 CHANNEL_MAP psChannelMap[PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS]; 182 } psContextMap[PCSCLITE_MAX_APPLICATION_CONTEXTS]; |
没有注释说明 contextBlockStatus 做什么的。
搜索整个工程 , 只有 winscard_clnt.c 用到 , 且只有 9 个地方用到。
这是一个状态值 , 且只有两个状态 , 定义于 pcscd.h
#define BLOCK_STATUS_RESUME 0x00FF /**< Normal resume */ # define BLOCK_STATUS_BLOCKING 0x00FA /**< Function is blocking */ |
猜到了吧。
如果还没有,那么请看