PCSC那事儿(十七--SCardGetStatusChange)
来源:互联网 发布:java 字符串搜索 编辑:程序博客网 时间:2024/05/17 00:17
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 eventsfrom 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的类型是unsignedlong(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 */
猜到了吧。
如果还没有,那么请看
- PCSC那事儿(十七--SCardGetStatusChange)
- PCSC那事儿(二十七--开始服务端代码分析)
- PCSC那事儿(一)
- PCSC那事儿(二)
- PCSC那事儿(三)
- PCSC那事儿(四)
- PCSC那事儿(五)
- PCSC那事儿(六)
- PCSC那事儿(七)
- PCSC那事儿(八--SCardEstablishContext)
- PCSC那事儿(九--SCardEstablishContext)
- PCSC那事儿(十--SCardEstablishContext)
- PCSC那事儿(十一--SCardEstablishContext)
- PCSC那事儿(十二--SCardIsValidContext)
- PCSC那事儿(十三--SCardListReaderGroups)
- PCSC那事儿(十四--SCardReleaseContext)
- PCSC那事儿(十五--SCardFreeMemory)
- PCSC那事儿(十六--SCardListReaders)
- 第二章 C#基本概念
- java 字符大小写(中文)转换
- PCSC那事儿(十六--SCardListReaders)
- 100Base-T,100Base-TX等的含义与区别
- 主从表设计和编程的几种实现办法
- PCSC那事儿(十七--SCardGetStatusChange)
- 人生感悟
- WCF 通信
- 移植 u-boot 1.1.6 到 S3C2440 (nand 启动)
- XML 解析c++源码(头文件)
- 职场
- Visual C++ 使用的文件(转)
- VSS 错误:File names.dat may be corrupt 修复
- VC-Project/Settings说明