Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

event.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 event.c 00008 00009 Abstract: 00010 00011 This module implements the executive event object. Functions are provided 00012 to create, open, set, reset, pulse, and query event objects. 00013 00014 Author: 00015 00016 David N. Cutler (davec) 8-May-1989 00017 00018 Environment: 00019 00020 Kernel mode only. 00021 00022 Revision History: 00023 00024 --*/ 00025 00026 #include "exp.h" 00027 00028 // 00029 // Temporary so boost is patchable 00030 // 00031 00032 ULONG ExpEventBoost = EVENT_INCREMENT; 00033 00034 // 00035 // Address of event object type descriptor. 00036 // 00037 00038 POBJECT_TYPE ExEventObjectType; 00039 00040 // 00041 // Structure that describes the mapping of generic access rights to object 00042 // specific access rights for event objects. 00043 // 00044 00045 GENERIC_MAPPING ExpEventMapping = { 00046 STANDARD_RIGHTS_READ | 00047 EVENT_QUERY_STATE, 00048 STANDARD_RIGHTS_WRITE | 00049 EVENT_MODIFY_STATE, 00050 STANDARD_RIGHTS_EXECUTE | 00051 SYNCHRONIZE, 00052 EVENT_ALL_ACCESS 00053 }; 00054 00055 #ifdef ALLOC_PRAGMA 00056 #pragma alloc_text(INIT, ExpEventInitialization) 00057 #pragma alloc_text(PAGE, NtClearEvent) 00058 #pragma alloc_text(PAGE, NtCreateEvent) 00059 #pragma alloc_text(PAGE, NtOpenEvent) 00060 #pragma alloc_text(PAGE, NtPulseEvent) 00061 #pragma alloc_text(PAGE, NtQueryEvent) 00062 #pragma alloc_text(PAGE, NtResetEvent) 00063 #pragma alloc_text(PAGE, NtSetEvent) 00064 #endif 00065 00066 BOOLEAN 00067 ExpEventInitialization ( 00068 ) 00069 00070 /*++ 00071 00072 Routine Description: 00073 00074 This function creates the event object type descriptor at system 00075 initialization and stores the address of the object type descriptor 00076 in global storage. 00077 00078 Arguments: 00079 00080 None. 00081 00082 Return Value: 00083 00084 A value of TRUE is returned if the event object type descriptor is 00085 successfully initialized. Otherwise a value of FALSE is returned. 00086 00087 --*/ 00088 00089 { 00090 00091 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 00092 NTSTATUS Status; 00093 UNICODE_STRING TypeName; 00094 00095 // 00096 // Initialize string descriptor. 00097 // 00098 00099 RtlInitUnicodeString(&TypeName, L"Event"); 00100 00101 // 00102 // Create event object type descriptor. 00103 // 00104 00105 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 00106 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 00107 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; 00108 ObjectTypeInitializer.GenericMapping = ExpEventMapping; 00109 ObjectTypeInitializer.PoolType = NonPagedPool; 00110 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KEVENT); 00111 ObjectTypeInitializer.ValidAccessMask = EVENT_ALL_ACCESS; 00112 Status = ObCreateObjectType(&TypeName, 00113 &ObjectTypeInitializer, 00114 (PSECURITY_DESCRIPTOR)NULL, 00115 &ExEventObjectType); 00116 00117 // 00118 // If the event object type descriptor was successfully created, then 00119 // return a value of TRUE. Otherwise return a value of FALSE. 00120 // 00121 00122 return (BOOLEAN)(NT_SUCCESS(Status)); 00123 } 00124 00125 NTSTATUS 00126 NtClearEvent ( 00127 IN HANDLE EventHandle 00128 ) 00129 00130 /*++ 00131 00132 Routine Description: 00133 00134 This function sets an event object to a Not-Signaled state. 00135 00136 Arguments: 00137 00138 EventHandle - Supplies a handle to an event object. 00139 00140 Return Value: 00141 00142 TBS 00143 00144 --*/ 00145 00146 { 00147 00148 PVOID Event; 00149 NTSTATUS Status; 00150 00151 // 00152 // Reference event object by handle. 00153 // 00154 00155 Status = ObReferenceObjectByHandle(EventHandle, 00156 EVENT_MODIFY_STATE, 00157 ExEventObjectType, 00158 KeGetPreviousMode(), 00159 &Event, 00160 NULL); 00161 00162 // 00163 // If the reference was successful, then set the state of the event 00164 // object to Not-Signaled and dereference event object. 00165 // 00166 00167 if (NT_SUCCESS(Status)) { 00168 KeClearEvent((PKEVENT)Event); 00169 ObDereferenceObject(Event); 00170 } 00171 00172 // 00173 // Return service status. 00174 // 00175 00176 return Status; 00177 } 00178 00179 NTSTATUS 00180 NtCreateEvent ( 00181 OUT PHANDLE EventHandle, 00182 IN ACCESS_MASK DesiredAccess, 00183 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 00184 IN EVENT_TYPE EventType, 00185 IN BOOLEAN InitialState 00186 ) 00187 00188 /*++ 00189 00190 Routine Description: 00191 00192 This function creates an event object, sets it initial state to the 00193 specified value, and opens a handle to the object with the specified 00194 desired access. 00195 00196 Arguments: 00197 00198 EventHandle - Supplies a pointer to a variable that will receive the 00199 event object handle. 00200 00201 DesiredAccess - Supplies the desired types of access for the event object. 00202 00203 ObjectAttributes - Supplies a pointer to an object attributes structure. 00204 00205 EventType - Supplies the type of the event (autoclearing or notification). 00206 00207 InitialState - Supplies the initial state of the event object. 00208 00209 Return Value: 00210 00211 TBS 00212 00213 --*/ 00214 00215 { 00216 00217 PVOID Event; 00218 HANDLE Handle; 00219 KPROCESSOR_MODE PreviousMode; 00220 NTSTATUS Status; 00221 00222 // 00223 // Establish an exception handler, probe the output handle address, and 00224 // attempt to create an event object. If the probe fails, then return the 00225 // exception code as the service status. Otherwise return the status value 00226 // returned by the object insertion routine. 00227 // 00228 00229 try { 00230 00231 // 00232 // Get previous processor mode and probe output handle address if 00233 // necessary. 00234 // 00235 00236 PreviousMode = KeGetPreviousMode(); 00237 if (PreviousMode != KernelMode) { 00238 ProbeForWriteHandle(EventHandle); 00239 } 00240 00241 // 00242 // Check argument validity. 00243 // 00244 00245 if ((EventType != NotificationEvent) && (EventType != SynchronizationEvent)) { 00246 return STATUS_INVALID_PARAMETER; 00247 } 00248 00249 // 00250 // Allocate event object. 00251 // 00252 00253 Status = ObCreateObject(PreviousMode, 00254 ExEventObjectType, 00255 ObjectAttributes, 00256 PreviousMode, 00257 NULL, 00258 sizeof(KEVENT), 00259 0, 00260 0, 00261 (PVOID *)&Event); 00262 00263 // 00264 // If the event object was successfully allocated, then initialize the 00265 // event object and attempt to insert the event object in the current 00266 // process' handle table. 00267 // 00268 00269 if (NT_SUCCESS(Status)) { 00270 KeInitializeEvent((PKEVENT)Event, EventType, InitialState); 00271 Status = ObInsertObject(Event, 00272 NULL, 00273 DesiredAccess, 00274 0, 00275 (PVOID *)NULL, 00276 &Handle); 00277 00278 // 00279 // If the event object was successfully inserted in the current 00280 // process' handle table, then attempt to write the event object 00281 // handle value. If the write attempt fails, then do not report 00282 // an error. When the caller attempts to access the handle value, 00283 // an access violation will occur. 00284 // 00285 00286 if (NT_SUCCESS(Status)) { 00287 try { 00288 *EventHandle = Handle; 00289 00290 } except(ExSystemExceptionFilter()) { 00291 } 00292 } 00293 } 00294 00295 // 00296 // If an exception occurs during the probe of the output handle address, 00297 // then always handle the exception and return the exception code as the 00298 // status value. 00299 // 00300 00301 } except(ExSystemExceptionFilter()) { 00302 return GetExceptionCode(); 00303 } 00304 00305 // 00306 // Return service status. 00307 // 00308 00309 return Status; 00310 } 00311 00312 NTSTATUS 00313 NtOpenEvent ( 00314 OUT PHANDLE EventHandle, 00315 IN ACCESS_MASK DesiredAccess, 00316 IN POBJECT_ATTRIBUTES ObjectAttributes 00317 ) 00318 00319 /*++ 00320 00321 Routine Description: 00322 00323 This function opens a handle to an event object with the specified 00324 desired access. 00325 00326 Arguments: 00327 00328 EventHandle - Supplies a pointer to a variable that will receive the 00329 event object handle. 00330 00331 DesiredAccess - Supplies the desired types of access for the event object. 00332 00333 ObjectAttributes - Supplies a pointer to an object attributes structure. 00334 00335 Return Value: 00336 00337 TBS 00338 00339 --*/ 00340 00341 { 00342 00343 HANDLE Handle; 00344 KPROCESSOR_MODE PreviousMode; 00345 NTSTATUS Status; 00346 00347 00348 // 00349 // Establish an exception handler, probe the output handle address, and 00350 // attempt to open the event object. If the probe fails, then return the 00351 // exception code as the service status. Otherwise return the status value 00352 // returned by the object open routine. 00353 // 00354 00355 try { 00356 00357 // 00358 // Get previous processor mode and probe output handle address 00359 // if necessary. 00360 // 00361 00362 PreviousMode = KeGetPreviousMode(); 00363 if (PreviousMode != KernelMode) { 00364 ProbeForWriteHandle(EventHandle); 00365 } 00366 00367 // 00368 // Open handle to the event object with the specified desired access. 00369 // 00370 00371 Status = ObOpenObjectByName(ObjectAttributes, 00372 ExEventObjectType, 00373 PreviousMode, 00374 NULL, 00375 DesiredAccess, 00376 NULL, 00377 &Handle); 00378 00379 // 00380 // If the open was successful, then attempt to write the event object 00381 // handle value. If the write attempt fails, then do not report an 00382 // error. When the caller attempts to access the handle value, an 00383 // access violation will occur. 00384 // 00385 00386 if (NT_SUCCESS(Status)) { 00387 try { 00388 *EventHandle = Handle; 00389 00390 } except(ExSystemExceptionFilter()) { 00391 } 00392 } 00393 00394 // 00395 // If an exception occurs during the probe of the output event handle, 00396 // then always handle the exception and return the exception code as the 00397 // status value. 00398 // 00399 00400 } except(ExSystemExceptionFilter()) { 00401 return GetExceptionCode(); 00402 } 00403 00404 // 00405 // Return service status. 00406 // 00407 00408 return Status; 00409 } 00410 00411 NTSTATUS 00412 NtPulseEvent ( 00413 IN HANDLE EventHandle, 00414 OUT PLONG PreviousState OPTIONAL 00415 ) 00416 00417 /*++ 00418 00419 Routine Description: 00420 00421 This function sets an event object to a Signaled state, attempts to 00422 satisfy as many waits as possible, and then resets the state of the 00423 event object to Not-Signaled. 00424 00425 Arguments: 00426 00427 EventHandle - Supplies a handle to an event object. 00428 00429 PreviousState - Supplies an optional pointer to a variable that will 00430 receive the previous state of the event object. 00431 00432 Return Value: 00433 00434 TBS 00435 00436 --*/ 00437 00438 { 00439 00440 PVOID Event; 00441 KPROCESSOR_MODE PreviousMode; 00442 LONG State; 00443 NTSTATUS Status; 00444 00445 // 00446 // Establish an exception handler, probe the previous state address if 00447 // specified, reference the event object, and pulse the event object. If 00448 // the probe fails, then return the exception code as the service status. 00449 // Otherwise return the status value returned by the reference object by 00450 // handle routine. 00451 // 00452 00453 try { 00454 00455 // 00456 // Get previous processor mode and probe previous state address 00457 // if necessary. 00458 // 00459 00460 PreviousMode = KeGetPreviousMode(); 00461 if ((PreviousMode != KernelMode) && (ARGUMENT_PRESENT(PreviousState))) { 00462 ProbeForWriteLong(PreviousState); 00463 } 00464 00465 // 00466 // Reference event object by handle. 00467 // 00468 00469 Status = ObReferenceObjectByHandle(EventHandle, 00470 EVENT_MODIFY_STATE, 00471 ExEventObjectType, 00472 PreviousMode, 00473 &Event, 00474 NULL); 00475 00476 // 00477 // If the reference was successful, then pulse the event object, 00478 // dereference event object, and write the previous state value if 00479 // specified. If the write of the previous state fails, then do not 00480 // report an error. When the caller attempts to access the previous 00481 // state value, an access violation will occur. 00482 // 00483 00484 if (NT_SUCCESS(Status)) { 00485 State = KePulseEvent((PKEVENT)Event, ExpEventBoost, FALSE); 00486 ObDereferenceObject(Event); 00487 if (ARGUMENT_PRESENT(PreviousState)) { 00488 try { 00489 *PreviousState = State; 00490 00491 } except(ExSystemExceptionFilter()) { 00492 } 00493 } 00494 } 00495 00496 // 00497 // If an exception occurs during the probe of the previous state, then 00498 // always handle the exception and return the exception code as the status 00499 // value. 00500 // 00501 00502 } except(ExSystemExceptionFilter()) { 00503 return GetExceptionCode(); 00504 } 00505 00506 // 00507 // Return service status. 00508 // 00509 00510 return Status; 00511 } 00512 00513 NTSTATUS 00514 NtQueryEvent ( 00515 IN HANDLE EventHandle, 00516 IN EVENT_INFORMATION_CLASS EventInformationClass, 00517 OUT PVOID EventInformation, 00518 IN ULONG EventInformationLength, 00519 OUT PULONG ReturnLength OPTIONAL 00520 ) 00521 00522 /*++ 00523 00524 Routine Description: 00525 00526 This function queries the state of an event object and returns the 00527 requested information in the specified record structure. 00528 00529 Arguments: 00530 00531 EventHandle - Supplies a handle to an event object. 00532 00533 EventInformationClass - Supplies the class of information being requested. 00534 00535 EventInformation - Supplies a pointer to a record that is to receive the 00536 requested information. 00537 00538 EventInformationLength - Supplies the length of the record that is to 00539 receive the requested information. 00540 00541 ReturnLength - Supplies an optional pointer to a variable that is to 00542 receive the actual length of information that is returned. 00543 00544 Return Value: 00545 00546 TBS 00547 00548 --*/ 00549 00550 { 00551 00552 PKEVENT Event; 00553 KPROCESSOR_MODE PreviousMode; 00554 LONG State; 00555 NTSTATUS Status; 00556 EVENT_TYPE EventType; 00557 00558 // 00559 // Check argument validity. 00560 // 00561 00562 if (EventInformationClass != EventBasicInformation) { 00563 return STATUS_INVALID_INFO_CLASS; 00564 } 00565 00566 if (EventInformationLength != sizeof(EVENT_BASIC_INFORMATION)) { 00567 return STATUS_INFO_LENGTH_MISMATCH; 00568 } 00569 00570 // 00571 // Establish an exception handler, probe the output arguments, reference 00572 // the event object, and return the specified information. If the probe 00573 // fails, then return the exception code as the service status. Otherwise 00574 // return the status value returned by the reference object by handle 00575 // routine. 00576 // 00577 00578 try { 00579 00580 // 00581 // Get previous processor mode and probe output arguments if necessary. 00582 // 00583 00584 PreviousMode = KeGetPreviousMode(); 00585 if (PreviousMode != KernelMode) { 00586 ProbeForWrite(EventInformation, 00587 sizeof(EVENT_BASIC_INFORMATION), 00588 sizeof(ULONG)); 00589 00590 if (ARGUMENT_PRESENT(ReturnLength)) { 00591 ProbeForWriteUlong(ReturnLength); 00592 } 00593 } 00594 00595 // 00596 // Reference event object by handle. 00597 // 00598 00599 Status = ObReferenceObjectByHandle(EventHandle, 00600 EVENT_QUERY_STATE, 00601 ExEventObjectType, 00602 PreviousMode, 00603 (PVOID *)&Event, 00604 NULL); 00605 00606 // 00607 // If the reference was successful, then read the current state of 00608 // the event object, deference event object, fill in the information 00609 // structure, and return the length of the information structure if 00610 // specified. If the write of the event information or the return 00611 // length fails, then do not report an error. When the caller accesses 00612 // the information structure or length an access violation will occur. 00613 // 00614 00615 if (NT_SUCCESS(Status)) { 00616 State = KeReadStateEvent(Event); 00617 EventType = Event->Header.Type; 00618 ObDereferenceObject(Event); 00619 try { 00620 ((PEVENT_BASIC_INFORMATION)EventInformation)->EventType = EventType; 00621 ((PEVENT_BASIC_INFORMATION)EventInformation)->EventState = State; 00622 if (ARGUMENT_PRESENT(ReturnLength)) { 00623 *ReturnLength = sizeof(EVENT_BASIC_INFORMATION); 00624 } 00625 00626 } except(ExSystemExceptionFilter()) { 00627 } 00628 } 00629 00630 // 00631 // If an exception occurs during the probe of the output arguments, then 00632 // always handle the exception and return the exception code as the status 00633 // value. 00634 // 00635 00636 } except(ExSystemExceptionFilter()) { 00637 return GetExceptionCode(); 00638 } 00639 00640 // 00641 // Return service status. 00642 // 00643 00644 return Status; 00645 } 00646 00647 NTSTATUS 00648 NtResetEvent ( 00649 IN HANDLE EventHandle, 00650 OUT PLONG PreviousState OPTIONAL 00651 ) 00652 00653 /*++ 00654 00655 Routine Description: 00656 00657 This function sets an event object to a Not-Signaled state. 00658 00659 Arguments: 00660 00661 EventHandle - Supplies a handle to an event object. 00662 00663 PreviousState - Supplies an optional pointer to a variable that will 00664 receive the previous state of the event object. 00665 00666 Return Value: 00667 00668 TBS 00669 00670 --*/ 00671 00672 { 00673 00674 PVOID Event; 00675 KPROCESSOR_MODE PreviousMode; 00676 LONG State; 00677 NTSTATUS Status; 00678 00679 // 00680 // Establish an exception handler, probe the previous state address if 00681 // specified, reference the event object, and reset the event object. If 00682 // the probe fails, then return the exception code as the service status. 00683 // Otherwise return the status value returned by the reference object by 00684 // handle routine. 00685 // 00686 00687 try { 00688 00689 // 00690 // Get previous processor mode and probe previous state address 00691 // if necessary. 00692 // 00693 00694 PreviousMode = KeGetPreviousMode(); 00695 if ((PreviousMode != KernelMode) && (ARGUMENT_PRESENT(PreviousState))) { 00696 ProbeForWriteLong(PreviousState); 00697 } 00698 00699 // 00700 // Reference event object by handle. 00701 // 00702 00703 Status = ObReferenceObjectByHandle(EventHandle, 00704 EVENT_MODIFY_STATE, 00705 ExEventObjectType, 00706 PreviousMode, 00707 &Event, 00708 NULL); 00709 00710 // 00711 // If the reference was successful, then set the state of the event 00712 // object to Not-Signaled, dereference event object, and write the 00713 // previous state value if specified. If the write of the previous 00714 // state fails, then do not report an error. When the caller attempts 00715 // to access the previous state value, an access violation will occur. 00716 // 00717 00718 if (NT_SUCCESS(Status)) { 00719 State = KeResetEvent((PKEVENT)Event); 00720 ObDereferenceObject(Event); 00721 if (ARGUMENT_PRESENT(PreviousState)) { 00722 try { 00723 *PreviousState = State; 00724 00725 } except(ExSystemExceptionFilter()) { 00726 } 00727 } 00728 } 00729 00730 // 00731 // If an exception occurs during the probe of the previous state, then 00732 // always handle the exception and return the exception code as the status 00733 // value. 00734 // 00735 00736 } except(ExSystemExceptionFilter()) { 00737 return GetExceptionCode(); 00738 } 00739 00740 // 00741 // Return service status. 00742 // 00743 00744 return Status; 00745 } 00746 00747 NTSTATUS 00748 NtSetEvent ( 00749 IN HANDLE EventHandle, 00750 OUT PLONG PreviousState OPTIONAL 00751 ) 00752 00753 /*++ 00754 00755 Routine Description: 00756 00757 This function sets an event object to a Signaled state and attempts to 00758 satisfy as many waits as possible. 00759 00760 Arguments: 00761 00762 EventHandle - Supplies a handle to an event object. 00763 00764 PreviousState - Supplies an optional pointer to a variable that will 00765 receive the previous state of the event object. 00766 00767 Return Value: 00768 00769 TBS 00770 00771 --*/ 00772 00773 { 00774 00775 PVOID Event; 00776 KPROCESSOR_MODE PreviousMode; 00777 LONG State; 00778 NTSTATUS Status; 00779 #if DBG 00780 00781 // 00782 // Sneaky trick here to catch sleazy apps (csrss) that erroneously call 00783 // NtSetEvent on an event that happens to be somebody else's 00784 // critical section. Only allow setting a protected handle if the low 00785 // bit of PreviousState is set. 00786 // 00787 OBJECT_HANDLE_INFORMATION HandleInfo; 00788 00789 #endif 00790 00791 // 00792 // Establish an exception handler, probe the previous state address if 00793 // specified, reference the event object, and set the event object. If 00794 // the probe fails, then return the exception code as the service status. 00795 // Otherwise return the status value returned by the reference object by 00796 // handle routine. 00797 // 00798 00799 try { 00800 00801 // 00802 // Get previous processor mode and probe previous state address 00803 // if necessary. 00804 // 00805 00806 PreviousMode = KeGetPreviousMode(); 00807 #if DBG 00808 if ((PreviousMode != KernelMode) && 00809 (ARGUMENT_PRESENT(PreviousState)) && 00810 (PreviousState != (PLONG)1)) { 00811 ProbeForWriteLong(PreviousState); 00812 } 00813 #else 00814 if ((PreviousMode != KernelMode) && (ARGUMENT_PRESENT(PreviousState))) { 00815 ProbeForWriteLong(PreviousState); 00816 } 00817 #endif 00818 00819 // 00820 // Reference event object by handle. 00821 // 00822 00823 #if DBG 00824 Status = ObReferenceObjectByHandle(EventHandle, 00825 EVENT_MODIFY_STATE, 00826 ExEventObjectType, 00827 PreviousMode, 00828 &Event, 00829 &HandleInfo); 00830 if (NT_SUCCESS(Status)) { 00831 00832 if ((HandleInfo.HandleAttributes & 1) && 00833 (PreviousState != (PLONG)1)) { 00834 #if 0 00835 // 00836 // This is a protected handle. If the low bit of PreviousState is NOT set, 00837 // break into the debugger 00838 // 00839 00840 DbgPrint("NtSetEvent: Illegal call to NtSetEvent on a protected handle\n"); 00841 DbgBreakPoint(); 00842 PreviousState = NULL; 00843 #endif 00844 } 00845 } else { 00846 if ((KeGetPreviousMode() != KernelMode) && 00847 (EventHandle != NULL) && 00848 ((NtGlobalFlag & FLG_ENABLE_CLOSE_EXCEPTIONS) || 00849 (PsGetCurrentProcess()->DebugPort != NULL))) { 00850 00851 Status = KeRaiseUserException(STATUS_INVALID_HANDLE); 00852 00853 } 00854 } 00855 #else 00856 Status = ObReferenceObjectByHandle(EventHandle, 00857 EVENT_MODIFY_STATE, 00858 ExEventObjectType, 00859 PreviousMode, 00860 &Event, 00861 NULL); 00862 #endif 00863 00864 // 00865 // If the reference was successful, then set the event object to the 00866 // Signaled state, dereference event object, and write the previous 00867 // state value if specified. If the write of the previous state fails, 00868 // then do not report an error. When the caller attempts to access the 00869 // previous state value, an access violation will occur. 00870 // 00871 00872 if (NT_SUCCESS(Status)) { 00873 State = KeSetEvent((PKEVENT)Event, ExpEventBoost, FALSE); 00874 ObDereferenceObject(Event); 00875 if (ARGUMENT_PRESENT(PreviousState)) { 00876 try { 00877 *PreviousState = State; 00878 00879 } except(ExSystemExceptionFilter()) { 00880 } 00881 } 00882 } 00883 00884 // 00885 // If an exception occurs during the probe of the previous state, then 00886 // always handle the exception and return the exception code as the status 00887 // value. 00888 // 00889 00890 } except(ExSystemExceptionFilter()) { 00891 return GetExceptionCode(); 00892 } 00893 00894 // 00895 // Return service status. 00896 // 00897 00898 return Status; 00899 }

Generated on Sat May 15 19:39:56 2004 for test by doxygen 1.3.7