/[openpgpmdrv]/trunk/OpenPGPminidriver/CardPinOperation.c
ViewVC logotype

Contents of /trunk/OpenPGPminidriver/CardPinOperation.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Tue Feb 23 19:18:59 2010 UTC (15 years, 2 months ago) by vletoux
File MIME type: text/plain
File size: 18100 byte(s)


1 /* OpenPGP Smart Card Mini Driver
2 Copyright (C) 2009 Vincent Le Toux
3
4 This library is Free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License version 2.1 as published by the Free Software Foundation.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Lesser General Public License for more details.
12
13 You should have received a copy of the GNU Lesser General Public
14 License along with this library; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include <windows.h>
19 #include <cardmod.h>
20 #include "Tracing.h"
21 #include "Context.h"
22 #include "SmartCard.h"
23 #include "PinOperations.h"
24
25
26 // 4.2 Card PIN Operations
27
28 /** The CardAuthenticatePin function submits a PIN value as a string
29 to the card to establish the user’s identity and to satisfy access
30 conditions for an operation to be undertaken on the user’s behalf.
31 Submission of a PIN to the card may involve some processing by the card
32 minidriver to render the PIN information to a card-specific form. */
33
34 DWORD WINAPI CardAuthenticatePin(
35 __in PCARD_DATA pCardData,
36 __in LPWSTR pwszUserId,
37 __in_bcount(cbPin) PBYTE pbPin,
38 __in DWORD cbPin,
39 __out_opt PDWORD pcAttemptsRemaining
40 )
41 {
42 DWORD dwReturn = 0;
43 Trace(WINEVENT_LEVEL_VERBOSE, L"Enter authenticate %s", pwszUserId);
44 __try
45 {
46 if ( pCardData == NULL )
47 {
48 Trace(WINEVENT_LEVEL_ERROR, L"pCardData == NULL");
49 dwReturn = SCARD_E_INVALID_PARAMETER;
50 __leave;
51 }
52 if ( pwszUserId == NULL )
53 {
54 Trace(WINEVENT_LEVEL_ERROR, L"pwszUserId == NULL");
55 dwReturn = SCARD_E_INVALID_PARAMETER;
56 __leave;
57 }
58 if ( pbPin == NULL )
59 {
60 Trace(WINEVENT_LEVEL_ERROR, L"pbPin == NULL");
61 dwReturn = SCARD_E_INVALID_PARAMETER;
62 __leave;
63 }
64 dwReturn = CheckContext(pCardData);
65 if ( dwReturn )
66 {
67 Trace(WINEVENT_LEVEL_ERROR, L"GetContext dwReturn == 0x%08X", dwReturn);
68 dwReturn = SCARD_E_INVALID_PARAMETER;
69 __leave;
70 }
71 if ( wcscmp(pwszUserId, wszCARD_USER_USER) == 0 )
72 {
73 dwReturn = CheckPinLength(pCardData, ROLE_USER, cbPin);
74 if (dwReturn)
75 {
76 __leave;
77 }
78 dwReturn = VerifyPIN(pCardData, ROLE_USER, pbPin, cbPin);
79 if (pcAttemptsRemaining)
80 {
81 GetRemainingPin(pCardData, ROLE_USER, pcAttemptsRemaining);
82 }
83 }
84 else if ( wcscmp(pwszUserId, wszCARD_USER_ADMIN) == 0)
85 {
86 dwReturn = CheckPinLength(pCardData, ROLE_ADMIN, cbPin);
87 if (dwReturn)
88 {
89 __leave;
90 }
91 dwReturn = VerifyPIN(pCardData, ROLE_ADMIN, pbPin, cbPin);
92 if (pcAttemptsRemaining)
93 {
94 GetRemainingPin(pCardData, ROLE_ADMIN, pcAttemptsRemaining);
95 }
96 }
97 else
98 {
99 Trace(WINEVENT_LEVEL_ERROR, L"pwszUserId unknown : %s", pwszUserId);
100 dwReturn = SCARD_E_INVALID_PARAMETER;
101 __leave;
102 }
103
104 }
105 __finally
106 {
107 }
108 Trace(WINEVENT_LEVEL_VERBOSE, L"dwReturn = 0x%08X",dwReturn);
109 return dwReturn;
110 }
111
112 /** A card principal can be authenticated by using either a PIN
113 or a challenge/response protocol in which the card generates a block
114 of challenge data by using its administrative key. The authenticating
115 caller must compute the response to the challenge by using shared
116 knowledge of that key and submit the response back to the card.
117 If the response is correct, the principal is authenticated to the card. */
118
119 DWORD WINAPI CardGetChallenge(
120 __in PCARD_DATA pCardData,
121 __deref_out_bcount(*pcbChallengeData) PBYTE *ppbChallengeData,
122 __out PDWORD pcbChallengeData
123 )
124 {
125 Trace(WINEVENT_LEVEL_VERBOSE, L"Enter");
126 return SCARD_E_UNSUPPORTED_FEATURE;
127 }
128
129 /** The CardAuthenticateChallenge function performs authentication of
130 a card principal by using a challenge/response protocol. The caller of
131 this function must have previously called CardGetChallenge to retrieve
132 the challenge data from the card and computed the correct response data
133 to submit with this call. */
134
135 DWORD WINAPI CardAuthenticateChallenge(
136 __in PCARD_DATA pCardData,
137 __in_bcount(cbResponseData) PBYTE pbResponseData,
138 __in DWORD cbResponseData,
139 __out_opt PDWORD pcAttemptsRemaining
140 )
141 {
142 Trace(WINEVENT_LEVEL_VERBOSE, L"Enter");
143 return SCARD_E_UNSUPPORTED_FEATURE;
144 }
145
146 /** The CardDeauthenticate function is an optional export that should be
147 provided if it is possible within the card minidriver to efficiently reverse
148 the effect of authenticating a user or administrator without resetting
149 the card. If this function is not implemented, the card minidriver should
150 put NULL in the CARD_DATA structure pointer for this function.
151 The Base CSP/KSP tests this pointer for NULL value before calling it. If it
152 is found NULL, the Base CSP/KSP deauthenticates a user by resetting the
153 card. Because a card reset is a time-consuming operation, the card minidriver
154 should implement this function if it can be done.
155 */
156
157 DWORD WINAPI CardDeauthenticate(
158 __in PCARD_DATA pCardData,
159 __in LPWSTR pwszUserId,
160 __in DWORD dwFlags
161 )
162 {
163 DWORD dwReturn = 0;
164 Trace(WINEVENT_LEVEL_VERBOSE, L"Enter");
165 __try
166 {
167 if ( pCardData == NULL )
168 {
169 Trace(WINEVENT_LEVEL_ERROR, L"pCardData == NULL");
170 dwReturn = SCARD_E_INVALID_PARAMETER;
171 __leave;
172 }
173 if ( pwszUserId == NULL )
174 {
175 Trace(WINEVENT_LEVEL_ERROR, L"pwszUserId == NULL");
176 dwReturn = SCARD_E_INVALID_PARAMETER;
177 __leave;
178 }
179 if ( dwFlags != 0 )
180 {
181 Trace(WINEVENT_LEVEL_ERROR, L"dwFlags != 0 : %d", dwFlags);
182 dwReturn = SCARD_E_INVALID_PARAMETER;
183 __leave;
184 }
185 dwReturn = CheckContext(pCardData);
186 if ( dwReturn )
187 {
188 Trace(WINEVENT_LEVEL_ERROR, L"GetContext dwReturn == 0x%08X", dwReturn);
189 dwReturn = SCARD_E_INVALID_PARAMETER;
190 __leave;
191 }
192 dwReturn = Deauthenticate(pCardData);
193 }
194 __finally
195 {
196 }
197 Trace(WINEVENT_LEVEL_VERBOSE, L"dwReturn = 0x%08X",dwReturn);
198 return dwReturn;
199 }
200
201 /** The CardAuthenticateEx function handles PIN authentication operations to the card.
202 This function replaces the CardAuthenticate function of earlier versions of these
203 specifications and adds support for the following PIN types:
204 • External PINs, which are PINs that are accessed from a device that is connected to the computer.
205 • Challenge/response PINs.
206 • Secure PIN channels.
207 • Session PINs.
208 */
209 DWORD WINAPI CardAuthenticateEx(
210 __in PCARD_DATA pCardData,
211 __in PIN_ID PinId,
212 __in DWORD dwFlags,
213 __in_bcount(cbPinData) PBYTE pbPinData,
214 __in DWORD cbPinData,
215 __deref_opt_out_bcount(*pcbSessionPin) PBYTE *ppbSessionPin,
216 __out_opt PDWORD pcbSessionPin,
217 __out_opt PDWORD pcAttemptsRemaining
218 )
219 {
220 DWORD dwReturn = 0;
221 Trace(WINEVENT_LEVEL_VERBOSE, L"Enter authenticate %d", PinId);
222 __try
223 {
224 if ( pCardData == NULL )
225 {
226 Trace(WINEVENT_LEVEL_ERROR, L"pCardData == NULL");
227 dwReturn = SCARD_E_INVALID_PARAMETER;
228 __leave;
229 }
230 if ( pbPinData == NULL )
231 {
232 Trace(WINEVENT_LEVEL_ERROR, L"pbPinData == NULL");
233 dwReturn = SCARD_E_INVALID_PARAMETER;
234 __leave;
235 }
236 if ((dwFlags & CARD_AUTHENTICATE_GENERATE_SESSION_PIN)
237 || (dwFlags & CARD_AUTHENTICATE_SESSION_PIN))
238 {
239 if ( ( ppbSessionPin == NULL ) ||
240 ( pcbSessionPin == NULL ) )
241 {
242 Trace(WINEVENT_LEVEL_ERROR, L"ppbSessionPin == NULL");
243 dwReturn = SCARD_E_INVALID_PARAMETER;
244 __leave;
245 }
246 else
247 {
248 Trace(WINEVENT_LEVEL_ERROR, L"SESSION_PIN SCARD_E_UNSUPPORTED_FEATURE");
249 dwReturn = SCARD_E_UNSUPPORTED_FEATURE;
250 __leave;
251 }
252 }
253 dwReturn = CheckContext(pCardData);
254 if ( dwReturn )
255 {
256 Trace(WINEVENT_LEVEL_ERROR, L"GetContext dwReturn == 0x%08X", dwReturn);
257 dwReturn = SCARD_E_INVALID_PARAMETER;
258 __leave;
259 }
260 dwReturn = CheckPinLength(pCardData, PinId, cbPinData);
261 if (dwReturn)
262 {
263 __leave;
264 }
265 dwReturn = VerifyPIN(pCardData, PinId, pbPinData, cbPinData);
266 if (pcAttemptsRemaining)
267 {
268 GetRemainingPin(pCardData, PinId, pcAttemptsRemaining);
269 }
270 }
271 __finally
272 {
273 }
274 Trace(WINEVENT_LEVEL_VERBOSE, L"dwReturn = 0x%08X",dwReturn);
275 return dwReturn;
276 }
277
278 /** Besides authentication by using a PIN, a card principal can be authenticated
279 by using a challenge/response protocol in which the card generates a block of challenge data.
280 The authenticating caller must compute the response to the challenge by using
281 shared knowledge of a key and submit the response back to the card by calling
282 CardGetChallengeEx. If the response is correct, the principal is authenticated to the card.
283 */
284
285 DWORD WINAPI CardGetChallengeEx(
286 __in PCARD_DATA pCardData,
287 __in PIN_ID PinId,
288 __deref_out_bcount(*pcbChallengeData) PBYTE *ppbChallengeData,
289 __out PDWORD pcbChallengeData,
290 __in DWORD dwFlags
291 )
292 {
293 Trace(WINEVENT_LEVEL_VERBOSE, L"Enter");
294 return SCARD_E_UNSUPPORTED_FEATURE;
295 }
296
297 /** The CardDeauthenticateEx function must always be provided. If it is not
298 possible within the card minidriver to efficiently reverse the effect of an
299 authentication operation without resetting the card, the call must return
300 SCARD_E_UNSUPPORTED_FEATURE. In this situation, the Base CSP/KSP performs
301 deauthentication by resetting the card. Because a card reset is a time-consuming
302 operation, the card minidriver must implement this function if it can be done.*/
303
304 DWORD WINAPI CardDeauthenticateEx(
305 __in PCARD_DATA pCardData,
306 __in PIN_SET PinId,
307 __in DWORD dwFlags
308 )
309 {
310 DWORD dwReturn = 0;
311 Trace(WINEVENT_LEVEL_VERBOSE, L"Enter");
312 __try
313 {
314 if ( pCardData == NULL )
315 {
316 Trace(WINEVENT_LEVEL_ERROR, L"pCardData == NULL");
317 dwReturn = SCARD_E_INVALID_PARAMETER;
318 __leave;
319 }
320 if ( dwFlags != 0 )
321 {
322 Trace(WINEVENT_LEVEL_ERROR, L"dwFlags != 0 : %d", dwFlags);
323 dwReturn = SCARD_E_INVALID_PARAMETER;
324 __leave;
325 }
326 dwReturn = CheckContext(pCardData);
327 if ( dwReturn )
328 {
329 Trace(WINEVENT_LEVEL_ERROR, L"GetContext dwReturn == 0x%08X", dwReturn);
330 dwReturn = SCARD_E_INVALID_PARAMETER;
331 __leave;
332 }
333 dwReturn = Deauthenticate(pCardData);
334 }
335 __finally
336 {
337 }
338 Trace(WINEVENT_LEVEL_VERBOSE, L"dwReturn = 0x%08X",dwReturn);
339 return dwReturn;
340 }
341
342 /** The CardUnblockPin function is used to unblock a card that has become
343 blocked by too many incorrect PIN entry attempts. The unblock function is
344 atomic in that authentication and unblocking the card must occur as a single
345 operation. Therefore, authentication information and the new user PIN must
346 be presented when the call is made.*/
347
348 DWORD WINAPI CardUnblockPin(
349 __in PCARD_DATA pCardData,
350 __in LPWSTR pwszUserId,
351 __in_bcount(cbAuthenticationData) PBYTE pbAuthenticationData,
352 __in DWORD cbAuthenticationData,
353 __in_bcount(cbNewPinData) PBYTE pbNewPinData,
354 __in DWORD cbNewPinData,
355 __in DWORD cRetryCount,
356 __in DWORD dwFlags
357 )
358 {
359 DWORD dwReturn = 0;
360
361 Trace(WINEVENT_LEVEL_VERBOSE, L"Enter");
362 __try
363 {
364 if ( pCardData == NULL )
365 {
366 Trace(WINEVENT_LEVEL_ERROR, L"pCardData == NULL");
367 dwReturn = SCARD_E_INVALID_PARAMETER;
368 __leave;
369 }
370 if ( pwszUserId == NULL )
371 {
372 Trace(WINEVENT_LEVEL_ERROR, L"pwszUserId == NULL");
373 dwReturn = SCARD_E_INVALID_PARAMETER;
374 __leave;
375 }
376 if ( pbAuthenticationData == NULL )
377 {
378 Trace(WINEVENT_LEVEL_ERROR, L"pbAuthenticationData == NULL");
379 dwReturn = SCARD_E_INVALID_PARAMETER;
380 __leave;
381 }
382 if ( pbNewPinData == NULL )
383 {
384 Trace(WINEVENT_LEVEL_ERROR, L"pbNewPinData == NULL");
385 dwReturn = SCARD_E_INVALID_PARAMETER;
386 __leave;
387 }
388 if (!(dwFlags & CARD_AUTHENTICATE_PIN_PIN))
389 {
390 dwReturn = SCARD_E_UNSUPPORTED_FEATURE;
391 Trace(WINEVENT_LEVEL_ERROR, L"dwFlags = 0x%08X", dwFlags);
392 __leave;
393 }
394 dwReturn = CheckContext(pCardData);
395 if ( !dwReturn )
396 {
397 Trace(WINEVENT_LEVEL_ERROR, L"GetContext dwReturn == 0x%08X", dwReturn);
398 dwReturn = SCARD_E_INVALID_PARAMETER;
399 __leave;
400 }
401 if ( wcscmp(pwszUserId, wszCARD_USER_USER) == 0 )
402 {
403 dwReturn = ResetUserPIN(pCardData, ROLE_PUK,
404 pbAuthenticationData, cbAuthenticationData,
405 pbNewPinData, cbNewPinData);
406 }
407 else if ( wcscmp(pwszUserId, wszCARD_USER_ADMIN) == 0)
408 {
409 dwReturn = SCARD_E_UNSUPPORTED_FEATURE;
410 Trace(WINEVENT_LEVEL_ERROR, L"wszCARD_USER_ADMIN");
411 __leave;
412 }
413 else
414 {
415 Trace(WINEVENT_LEVEL_ERROR, L"pwszUserId unknown : %s", pwszUserId);
416 dwReturn = SCARD_E_INVALID_PARAMETER;
417 __leave;
418 }
419 }
420 __finally
421 {
422 }
423 Trace(WINEVENT_LEVEL_VERBOSE, L"dwReturn = 0x%08X",dwReturn);
424 return dwReturn;
425 }
426
427 /** This function changes the authenticator for the affected card principal.
428 It can be used to change a user’s PIN or to change the challenge/response key.
429 The two usages are distinguished by use of a flag value.*/
430
431 DWORD WINAPI CardChangeAuthenticator(
432 __in PCARD_DATA pCardData,
433 __in LPWSTR pwszUserId,
434 __in_bcount(cbCurrentAuthenticator)
435 PBYTE pbCurrentAuthenticator,
436 __in DWORD cbCurrentAuthenticator,
437 __in_bcount(cbNewAuthenticator) PBYTE pbNewAuthenticator,
438 __in DWORD cbNewAuthenticator,
439 __in DWORD cRetryCount,
440 __in DWORD dwFlags,
441 __out_opt PDWORD pcAttemptsRemaining
442 )
443 {
444 DWORD dwReturn = 0;
445
446 Trace(WINEVENT_LEVEL_VERBOSE, L"Enter");
447 __try
448 {
449 if ( pCardData == NULL )
450 {
451 Trace(WINEVENT_LEVEL_ERROR, L"pCardData == NULL");
452 dwReturn = SCARD_E_INVALID_PARAMETER;
453 __leave;
454 }
455 if ( pwszUserId == NULL )
456 {
457 Trace(WINEVENT_LEVEL_ERROR, L"pwszUserId == NULL");
458 dwReturn = SCARD_E_INVALID_PARAMETER;
459 __leave;
460 }
461 if ( pbCurrentAuthenticator == NULL )
462 {
463 Trace(WINEVENT_LEVEL_ERROR, L"pbCurrentAuthenticator == NULL");
464 dwReturn = SCARD_E_INVALID_PARAMETER;
465 __leave;
466 }
467 if ( pbNewAuthenticator == NULL )
468 {
469 Trace(WINEVENT_LEVEL_ERROR, L"pbNewAuthenticator == NULL");
470 dwReturn = SCARD_E_INVALID_PARAMETER;
471 __leave;
472 }
473 if (!(dwFlags & CARD_AUTHENTICATE_PIN_PIN))
474 {
475 dwReturn = SCARD_E_UNSUPPORTED_FEATURE;
476 Trace(WINEVENT_LEVEL_ERROR, L"dwFlags = 0x%08X", dwFlags);
477 __leave;
478 }
479 dwReturn = CheckContext(pCardData);
480 if ( !dwReturn )
481 {
482 Trace(WINEVENT_LEVEL_ERROR, L"GetContext dwReturn == 0x%08X", dwReturn);
483 dwReturn = SCARD_E_INVALID_PARAMETER;
484 __leave;
485 }
486 if ( wcscmp(pwszUserId, wszCARD_USER_USER) == 0 )
487 {
488 dwReturn = ChangePIN(pCardData, ROLE_USER,
489 pbCurrentAuthenticator, cbCurrentAuthenticator,
490 pbNewAuthenticator, cbNewAuthenticator);
491 if (pcAttemptsRemaining)
492 {
493 GetRemainingPin(pCardData, ROLE_USER, pcAttemptsRemaining);
494 }
495 }
496 else if ( wcscmp(pwszUserId, wszCARD_USER_ADMIN) == 0)
497 {
498 dwReturn = ChangePIN(pCardData, ROLE_ADMIN,
499 pbCurrentAuthenticator, cbCurrentAuthenticator,
500 pbNewAuthenticator, cbNewAuthenticator);
501 if (pcAttemptsRemaining)
502 {
503 GetRemainingPin(pCardData,ROLE_ADMIN, pcAttemptsRemaining);
504 }
505 }
506 else
507 {
508 Trace(WINEVENT_LEVEL_ERROR, L"pwszUserId unknown : %s", pwszUserId);
509 dwReturn = SCARD_E_INVALID_PARAMETER;
510 __leave;
511 }
512 }
513 __finally
514 {
515 }
516 Trace(WINEVENT_LEVEL_VERBOSE, L"dwReturn = 0x%08X",dwReturn);
517 return dwReturn;
518 }
519
520
521 /** This function changes the authenticator for the affected card principal.
522 It can be used to change a PIN or unblock a PIN. The usages are distinguished
523 by use of a flag value.*/
524
525 DWORD WINAPI CardChangeAuthenticatorEx(
526 __in PCARD_DATA pCardData,
527 __in DWORD dwFlags,
528 __in PIN_ID dwAuthenticatingPinId,
529 __in_bcount(cbAuthenticatingPinData)
530 PBYTE pbAuthenticatingPinData,
531 __in DWORD cbAuthenticatingPinData,
532 __in PIN_ID dwTargetPinId,
533 __in_bcount(cbTargetData) PBYTE pbTargetData,
534 __in DWORD cbTargetData,
535 __in DWORD cRetryCount,
536 __out_opt PDWORD pcAttemptsRemaining
537 )
538 {
539 DWORD dwReturn = 0;
540
541 Trace(WINEVENT_LEVEL_VERBOSE, L"Enter");
542 __try
543 {
544 if ( pCardData == NULL )
545 {
546 Trace(WINEVENT_LEVEL_ERROR, L"pCardData == NULL");
547 dwReturn = SCARD_E_INVALID_PARAMETER;
548 __leave;
549 }
550 if ( pbAuthenticatingPinData == NULL )
551 {
552 Trace(WINEVENT_LEVEL_ERROR, L"pbAuthenticatingPinData == NULL");
553 dwReturn = SCARD_E_INVALID_PARAMETER;
554 __leave;
555 }
556 if ( pbTargetData == NULL )
557 {
558 Trace(WINEVENT_LEVEL_ERROR, L"pbTargetData == NULL");
559 dwReturn = SCARD_E_INVALID_PARAMETER;
560 __leave;
561 }
562 if (!(dwFlags & CARD_AUTHENTICATE_PIN_PIN))
563 {
564 dwReturn = SCARD_E_UNSUPPORTED_FEATURE;
565 Trace(WINEVENT_LEVEL_ERROR, L"dwFlags = 0x%08X", dwFlags);
566 __leave;
567 }
568 dwReturn = CheckContext(pCardData);
569 if ( !dwReturn )
570 {
571 Trace(WINEVENT_LEVEL_ERROR, L"GetContext dwReturn == 0x%08X", dwReturn);
572 dwReturn = SCARD_E_INVALID_PARAMETER;
573 __leave;
574 }
575 if ( dwAuthenticatingPinId == dwTargetPinId)
576 {
577 dwReturn = ChangePIN(pCardData, dwAuthenticatingPinId,
578 pbAuthenticatingPinData, cbAuthenticatingPinData,
579 pbTargetData, cbTargetData);
580 if (pcAttemptsRemaining)
581 {
582 GetRemainingPin(pCardData, dwAuthenticatingPinId, pcAttemptsRemaining);
583 }
584 }
585 else if ( dwAuthenticatingPinId == ROLE_ADMIN && dwTargetPinId == ROLE_USER)
586 {
587 dwReturn = ResetUserPIN(pCardData, ROLE_ADMIN,
588 pbAuthenticatingPinData, cbAuthenticatingPinData,
589 pbTargetData, cbTargetData);
590 if (pcAttemptsRemaining)
591 {
592 GetRemainingPin(pCardData,dwTargetPinId, pcAttemptsRemaining);
593 }
594 }
595 else
596 {
597 Trace(WINEVENT_LEVEL_ERROR, L"unknown role match: %d %d", dwAuthenticatingPinId, dwTargetPinId);
598 dwReturn = SCARD_E_INVALID_PARAMETER;
599 __leave;
600 }
601 }
602 __finally
603 {
604 }
605 Trace(WINEVENT_LEVEL_VERBOSE, L"dwReturn = 0x%08X",dwReturn);
606 return dwReturn;
607 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26