Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenharderr.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ex/harderr.c 00005 * PURPOSE: Error Functions and Status/Exception Dispatching/Raising 00006 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 00007 */ 00008 00009 /* INCLUDES *****************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 #define TAG_ERR ' rrE' 00016 00017 /* GLOBALS ****************************************************************/ 00018 00019 BOOLEAN ExReadyForErrors = FALSE; 00020 PVOID ExpDefaultErrorPort = NULL; 00021 PEPROCESS ExpDefaultErrorPortProcess = NULL; 00022 00023 /* FUNCTIONS ****************************************************************/ 00024 00025 /*++ 00026 * @name ExpSystemErrorHandler 00027 * 00028 * For now it's a stub 00029 * 00030 * @param ErrorStatus 00031 * FILLME 00032 * 00033 * @param NumberOfParameters 00034 * FILLME 00035 * 00036 * @param UnicodeStringParameterMask 00037 * FILLME 00038 * 00039 * @param Parameters 00040 * FILLME 00041 * 00042 * @param ValidResponseOptions 00043 * FILLME 00044 * 00045 * @param Response 00046 * FILLME 00047 * 00048 * @return None 00049 * 00050 * @remarks None 00051 * 00052 *--*/ 00053 NTSTATUS 00054 NTAPI 00055 ExpSystemErrorHandler(IN NTSTATUS ErrorStatus, 00056 IN ULONG NumberOfParameters, 00057 IN ULONG UnicodeStringParameterMask, 00058 IN PULONG_PTR Parameters, 00059 IN BOOLEAN Shutdown) 00060 { 00061 ULONG_PTR BugCheckParameters[MAXIMUM_HARDERROR_PARAMETERS] = {0, 0, 0, 0}; 00062 ULONG i; 00063 00064 /* Sanity check */ 00065 ASSERT(NumberOfParameters <= MAXIMUM_HARDERROR_PARAMETERS); 00066 00067 /* 00068 * KeBugCheck expects MAXIMUM_HARDERROR_PARAMETERS parameters, 00069 * but we might get called with less, so use a local buffer here. 00070 */ 00071 for (i = 0; i < NumberOfParameters; i++) 00072 { 00073 /* Copy them over */ 00074 BugCheckParameters[i] = Parameters[i]; 00075 } 00076 00077 /* FIXME: STUB */ 00078 KeBugCheckEx(FATAL_UNHANDLED_HARD_ERROR, 00079 ErrorStatus, 00080 (ULONG_PTR)BugCheckParameters, 00081 0, 00082 0); 00083 return STATUS_SUCCESS; 00084 } 00085 00086 /*++ 00087 * @name ExpRaiseHardError 00088 * 00089 * For now it's a stub 00090 * 00091 * @param ErrorStatus 00092 * FILLME 00093 * 00094 * @param NumberOfParameters 00095 * FILLME 00096 * 00097 * @param UnicodeStringParameterMask 00098 * FILLME 00099 * 00100 * @param Parameters 00101 * FILLME 00102 * 00103 * @param ValidResponseOptions 00104 * FILLME 00105 * 00106 * @param Response 00107 * FILLME 00108 * 00109 * @return None 00110 * 00111 * @remarks None 00112 * 00113 *--*/ 00114 NTSTATUS 00115 NTAPI 00116 ExpRaiseHardError(IN NTSTATUS ErrorStatus, 00117 IN ULONG NumberOfParameters, 00118 IN ULONG UnicodeStringParameterMask, 00119 IN PULONG_PTR Parameters, 00120 IN ULONG ValidResponseOptions, 00121 OUT PULONG Response) 00122 { 00123 PEPROCESS Process = PsGetCurrentProcess(); 00124 PETHREAD Thread = PsGetCurrentThread(); 00125 UCHAR Buffer[PORT_MAXIMUM_MESSAGE_LENGTH]; 00126 PHARDERROR_MSG Message = (PHARDERROR_MSG)Buffer; 00127 NTSTATUS Status; 00128 HANDLE PortHandle; 00129 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 00130 PAGED_CODE(); 00131 00132 /* Check if this error will shutdown the system */ 00133 if (ValidResponseOptions == OptionShutdownSystem) 00134 { 00135 /* Check for privilege */ 00136 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode)) 00137 { 00138 /* No rights */ 00139 *Response = ResponseNotHandled; 00140 return STATUS_PRIVILEGE_NOT_HELD; 00141 } 00142 00143 /* Don't handle any new hard errors */ 00144 ExReadyForErrors = FALSE; 00145 } 00146 00147 /* Check if hard errors are not disabled */ 00148 if (!Thread->HardErrorsAreDisabled) 00149 { 00150 /* Check if we can't do errors anymore, and this is serious */ 00151 if ((!ExReadyForErrors) && (NT_ERROR(ErrorStatus))) 00152 { 00153 /* Use the system handler */ 00154 ExpSystemErrorHandler(ErrorStatus, 00155 NumberOfParameters, 00156 UnicodeStringParameterMask, 00157 Parameters, 00158 (PreviousMode != KernelMode) ? TRUE: FALSE); 00159 } 00160 } 00161 00162 /* Enable hard error processing if it is enabled for the process 00163 * or if the exception status forces it */ 00164 if ((Process->DefaultHardErrorProcessing & 1) || 00165 (ErrorStatus & 0x10000000)) 00166 { 00167 /* Check if we have an exception port */ 00168 if (Process->ExceptionPort) 00169 { 00170 /* Use the port */ 00171 PortHandle = Process->ExceptionPort; 00172 } 00173 else 00174 { 00175 /* Use our default system port */ 00176 PortHandle = ExpDefaultErrorPort; 00177 } 00178 } 00179 else 00180 { 00181 /* Don't process the error */ 00182 PortHandle = NULL; 00183 } 00184 00185 /* If hard errors are disabled, do nothing */ 00186 if (Thread->HardErrorsAreDisabled) PortHandle = NULL; 00187 00188 /* Now check if we have a port */ 00189 if (PortHandle) 00190 { 00191 /* Check if this is the default process */ 00192 if (Process == ExpDefaultErrorPortProcess) 00193 { 00194 /* We can't handle the error, check if this is critical */ 00195 if (NT_ERROR(ErrorStatus)) 00196 { 00197 /* It is, invoke the system handler */ 00198 ExpSystemErrorHandler(ErrorStatus, 00199 NumberOfParameters, 00200 UnicodeStringParameterMask, 00201 Parameters, 00202 (PreviousMode != KernelMode) ? TRUE: FALSE); 00203 00204 /* If we survived, return to caller */ 00205 *Response = ResponseReturnToCaller; 00206 return STATUS_SUCCESS; 00207 } 00208 } 00209 00210 /* Setup the LPC Message */ 00211 Message->h.u1.Length = (sizeof(HARDERROR_MSG) << 16) | 00212 (sizeof(HARDERROR_MSG) - sizeof(PORT_MESSAGE)); 00213 Message->h.u2.ZeroInit = 0; 00214 Message->h.u2.s2.Type = LPC_ERROR_EVENT; 00215 Message->Status = ErrorStatus &~ 0x10000000; 00216 Message->ValidResponseOptions = ValidResponseOptions; 00217 Message->UnicodeStringParameterMask = UnicodeStringParameterMask; 00218 Message->NumberOfParameters = NumberOfParameters; 00219 KeQuerySystemTime(&Message->ErrorTime); 00220 00221 /* Copy the parameters */ 00222 if (Parameters) RtlMoveMemory(&Message->Parameters, 00223 Parameters, 00224 sizeof(ULONG_PTR) * NumberOfParameters); 00225 00226 /* Send the LPC Message */ 00227 Status = LpcRequestWaitReplyPort(PortHandle, 00228 (PVOID)Message, 00229 (PVOID)Message); 00230 if (NT_SUCCESS(Status)) 00231 { 00232 /* Check what kind of response we got */ 00233 if ((Message->Response != ResponseReturnToCaller) && 00234 (Message->Response != ResponseNotHandled) && 00235 (Message->Response != ResponseAbort) && 00236 (Message->Response != ResponseCancel) && 00237 (Message->Response != ResponseIgnore) && 00238 (Message->Response != ResponseNo) && 00239 (Message->Response != ResponseOk) && 00240 (Message->Response != ResponseRetry) && 00241 (Message->Response != ResponseYes) && 00242 (Message->Response != ResponseTryAgain) && 00243 (Message->Response != ResponseContinue)) 00244 { 00245 /* Reset to a default one */ 00246 Message->Response = ResponseReturnToCaller; 00247 } 00248 00249 /* Set the response */ 00250 *Response = Message->Response; 00251 } 00252 else 00253 { 00254 /* Set the response */ 00255 *Response = ResponseReturnToCaller; 00256 } 00257 } 00258 else 00259 { 00260 /* Set defaults */ 00261 *Response = ResponseReturnToCaller; 00262 Status = STATUS_SUCCESS; 00263 } 00264 00265 /* Return status */ 00266 return Status; 00267 } 00268 00269 /*++ 00270 * @name ExRaiseAccessViolation 00271 * @implemented 00272 * 00273 * The ExRaiseAccessViolation routine can be used with structured exception 00274 * handling to throw a driver-determined exception for a memory access 00275 * violation that occurs when a driver processes I/O requests. 00276 * See: http://msdn.microsoft.com/library/en-us/Kernel_r/hh/Kernel_r/k102_71b4c053-599c-4a6d-8a59-08aae6bdc534.xml.asp?frame=true 00277 * http://www.osronline.com/ddkx/kmarch/k102_814i.htm 00278 * 00279 * @return None 00280 * 00281 * @remarks None 00282 * 00283 *--*/ 00284 VOID 00285 NTAPI 00286 ExRaiseAccessViolation(VOID) 00287 { 00288 /* Raise the Right Status */ 00289 RtlRaiseStatus(STATUS_ACCESS_VIOLATION); 00290 } 00291 00292 /*++ 00293 * @name ExRaiseDatatypeMisalignment 00294 * @implemented 00295 * 00296 * ExRaiseDatatypeMisalignment raises an exception with the exception 00297 * code set to STATUS_DATATYPE_MISALIGNMENT 00298 * See: MSDN / DDK 00299 * http://www.osronline.com/ddkx/kmarch/k102_814i.htm 00300 * 00301 * @return None 00302 * 00303 * @remarks None 00304 * 00305 *--*/ 00306 VOID 00307 NTAPI 00308 ExRaiseDatatypeMisalignment(VOID) 00309 { 00310 /* Raise the Right Status */ 00311 RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT); 00312 } 00313 00314 /*++ 00315 * @name ExSystemExceptionFilter 00316 * @implemented 00317 * 00318 * TODO: Add description 00319 * 00320 * @return FILLME 00321 * 00322 * @remarks None 00323 * 00324 *--*/ 00325 LONG 00326 NTAPI 00327 ExSystemExceptionFilter(VOID) 00328 { 00329 return KeGetPreviousMode() != KernelMode ? 00330 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; 00331 } 00332 00333 /*++ 00334 * @name ExRaiseHardError 00335 * @implemented 00336 * 00337 * See NtRaiseHardError 00338 * 00339 * @param ErrorStatus 00340 * Error Code 00341 * 00342 * @param NumberOfParameters 00343 * Number of optional parameters in Parameters array 00344 * 00345 * @param UnicodeStringParameterMask 00346 * Optional string parameter (can be only one per error code) 00347 * 00348 * @param Parameters 00349 * Array of ULONG parameters for use in error message string 00350 * 00351 * @param ValidResponseOptions 00352 * See HARDERROR_RESPONSE_OPTION for possible values description 00353 * 00354 * @param Response 00355 * Pointer to HARDERROR_RESPONSE enumeration 00356 * 00357 * @return None 00358 * 00359 * @remarks None 00360 * 00361 *--*/ 00362 NTSTATUS 00363 NTAPI 00364 ExRaiseHardError(IN NTSTATUS ErrorStatus, 00365 IN ULONG NumberOfParameters, 00366 IN ULONG UnicodeStringParameterMask, 00367 IN PULONG_PTR Parameters, 00368 IN ULONG ValidResponseOptions, 00369 OUT PULONG Response) 00370 { 00371 SIZE_T Size; 00372 UNICODE_STRING CapturedParams[MAXIMUM_HARDERROR_PARAMETERS]; 00373 ULONG i; 00374 PVOID UserData = NULL; 00375 PHARDERROR_USER_PARAMETERS UserParams; 00376 PWSTR BufferBase; 00377 ULONG SafeResponse; 00378 NTSTATUS Status; 00379 PAGED_CODE(); 00380 00381 /* Check if we have parameters */ 00382 if (Parameters) 00383 { 00384 /* Check if we have strings */ 00385 if (UnicodeStringParameterMask) 00386 { 00387 /* Calculate the required size */ 00388 Size = FIELD_OFFSET(HARDERROR_USER_PARAMETERS, Buffer[0]); 00389 00390 /* Loop each parameter */ 00391 for (i = 0; i < NumberOfParameters; i++) 00392 { 00393 /* Check if it's part of the mask */ 00394 if (UnicodeStringParameterMask & (1 << i)) 00395 { 00396 /* Copy it */ 00397 RtlMoveMemory(&CapturedParams[i], 00398 (PVOID)Parameters[i], 00399 sizeof(UNICODE_STRING)); 00400 00401 /* Increase the size */ 00402 Size += CapturedParams[i].MaximumLength; 00403 } 00404 } 00405 00406 /* Allocate the user data region */ 00407 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 00408 &UserData, 00409 0, 00410 &Size, 00411 MEM_COMMIT, 00412 PAGE_READWRITE); 00413 if (!NT_SUCCESS(Status)) return Status; 00414 00415 /* Set the pointers to our data */ 00416 UserParams = UserData; 00417 BufferBase = UserParams->Buffer; 00418 00419 /* Loop parameters again */ 00420 for (i = 0; i < NumberOfParameters; i++) 00421 { 00422 /* Check if we're in the mask */ 00423 if (UnicodeStringParameterMask & (1 << i)) 00424 { 00425 /* Update the base */ 00426 UserParams->Parameters[i] = (ULONG_PTR)&UserParams->Strings[i]; 00427 00428 /* Copy the string buffer */ 00429 RtlMoveMemory(BufferBase, 00430 CapturedParams[i].Buffer, 00431 CapturedParams[i].MaximumLength); 00432 00433 /* Set buffer */ 00434 CapturedParams[i].Buffer = BufferBase; 00435 00436 /* Copy the string structure */ 00437 UserParams->Strings[i] = CapturedParams[i]; 00438 00439 /* Update the pointer */ 00440 BufferBase += CapturedParams[i].MaximumLength; 00441 } 00442 else 00443 { 00444 /* No need to copy any strings */ 00445 UserParams->Parameters[i] = Parameters[i]; 00446 } 00447 } 00448 } 00449 else 00450 { 00451 /* Just keep the data as is */ 00452 UserData = Parameters; 00453 } 00454 } 00455 00456 /* Now call the worker function */ 00457 Status = ExpRaiseHardError(ErrorStatus, 00458 NumberOfParameters, 00459 UnicodeStringParameterMask, 00460 UserData, 00461 ValidResponseOptions, 00462 &SafeResponse); 00463 00464 /* Check if we had done user-mode allocation */ 00465 if ((UserData) && (UserData != Parameters)) 00466 { 00467 /* We did! Delete it */ 00468 Size = 0; 00469 ZwFreeVirtualMemory(NtCurrentProcess(), 00470 &UserData, 00471 &Size, 00472 MEM_RELEASE); 00473 } 00474 00475 /* Return status and the response */ 00476 *Response = SafeResponse; 00477 return Status; 00478 } 00479 00480 /*++ 00481 * @name NtRaiseHardError 00482 * @implemented 00483 * 00484 * This function sends HARDERROR_MSG LPC message to listener 00485 * (typically CSRSS.EXE). See NtSetDefaultHardErrorPort for more information 00486 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtRaiseHardError.html 00487 * 00488 * @param ErrorStatus 00489 * Error Code 00490 * 00491 * @param NumberOfParameters 00492 * Number of optional parameters in Parameters array 00493 * 00494 * @param UnicodeStringParameterMask 00495 * Optional string parameter (can be only one per error code) 00496 * 00497 * @param Parameters 00498 * Array of ULONG_PTR parameters for use in error message string 00499 * 00500 * @param ValidResponseOptions 00501 * See HARDERROR_RESPONSE_OPTION for possible values description 00502 * 00503 * @param Response 00504 * Pointer to HARDERROR_RESPONSE enumeration 00505 * 00506 * @return Status 00507 * 00508 * @remarks NtRaiseHardError is easy way to display message in GUI 00509 * without loading Win32 API libraries 00510 * 00511 *--*/ 00512 NTSTATUS 00513 NTAPI 00514 NtRaiseHardError(IN NTSTATUS ErrorStatus, 00515 IN ULONG NumberOfParameters, 00516 IN ULONG UnicodeStringParameterMask, 00517 IN PULONG_PTR Parameters, 00518 IN ULONG ValidResponseOptions, 00519 OUT PULONG Response) 00520 { 00521 NTSTATUS Status = STATUS_SUCCESS; 00522 PULONG_PTR SafeParams = NULL; 00523 ULONG SafeResponse; 00524 UNICODE_STRING SafeString; 00525 ULONG i; 00526 ULONG ParamSize; 00527 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00528 00529 /* Validate parameter count */ 00530 if (NumberOfParameters > MAXIMUM_HARDERROR_PARAMETERS) 00531 { 00532 /* Fail */ 00533 return STATUS_INVALID_PARAMETER_2; 00534 } 00535 00536 /* Make sure we have some at least */ 00537 if ((Parameters) && !(NumberOfParameters)) 00538 { 00539 /* Fail */ 00540 return STATUS_INVALID_PARAMETER_2; 00541 } 00542 00543 /* Check if we were called from user-mode */ 00544 if (PreviousMode != KernelMode) 00545 { 00546 /* First validate the responses */ 00547 switch (ValidResponseOptions) 00548 { 00549 /* Check all valid cases */ 00550 case OptionAbortRetryIgnore: 00551 case OptionOk: 00552 case OptionOkCancel: 00553 case OptionRetryCancel: 00554 case OptionYesNo: 00555 case OptionYesNoCancel: 00556 case OptionShutdownSystem: 00557 break; 00558 00559 /* Anything else is invalid */ 00560 default: 00561 return STATUS_INVALID_PARAMETER_4; 00562 } 00563 00564 /* Enter SEH Block */ 00565 _SEH2_TRY 00566 { 00567 /* Validate the response pointer */ 00568 ProbeForWriteUlong(Response); 00569 00570 /* Check if we have parameters */ 00571 if (Parameters) 00572 { 00573 /* Validate the parameter pointers */ 00574 ParamSize = sizeof(ULONG_PTR) * NumberOfParameters; 00575 ProbeForRead(Parameters, ParamSize, sizeof(ULONG_PTR)); 00576 00577 /* Allocate a safe buffer */ 00578 SafeParams = ExAllocatePoolWithTag(PagedPool, 00579 ParamSize, 00580 TAG_ERR); 00581 00582 /* Copy them */ 00583 RtlCopyMemory(SafeParams, Parameters, ParamSize); 00584 00585 /* Now check if there's strings in it */ 00586 if (UnicodeStringParameterMask) 00587 { 00588 /* Loop every string */ 00589 for (i = 0; i < NumberOfParameters; i++) 00590 { 00591 /* Check if this parameter is a string */ 00592 if (UnicodeStringParameterMask & (1 << i)) 00593 { 00594 /* Probe the structure */ 00595 ProbeForRead((PVOID)SafeParams[i], 00596 sizeof(UNICODE_STRING), 00597 sizeof(ULONG_PTR)); 00598 00599 /* Capture it */ 00600 RtlCopyMemory(&SafeString, 00601 (PVOID)SafeParams[i], 00602 sizeof(UNICODE_STRING)); 00603 00604 /* Probe the buffer */ 00605 ProbeForRead(SafeString.Buffer, 00606 SafeString.MaximumLength, 00607 sizeof(UCHAR)); 00608 } 00609 } 00610 } 00611 } 00612 } 00613 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00614 { 00615 /* Free captured buffer */ 00616 if (SafeParams) ExFreePoolWithTag(SafeParams, TAG_ERR); 00617 00618 /* Return the exception code */ 00619 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00620 } 00621 _SEH2_END; 00622 00623 /* Call the system function directly, because we probed */ 00624 ExpRaiseHardError(ErrorStatus, 00625 NumberOfParameters, 00626 UnicodeStringParameterMask, 00627 SafeParams, 00628 ValidResponseOptions, 00629 &SafeResponse); 00630 } 00631 else 00632 { 00633 /* Reuse variable */ 00634 SafeParams = Parameters; 00635 00636 /* 00637 * Call the Executive Function. It will probe and copy pointers to 00638 * user-mode 00639 */ 00640 ExRaiseHardError(ErrorStatus, 00641 NumberOfParameters, 00642 UnicodeStringParameterMask, 00643 SafeParams, 00644 ValidResponseOptions, 00645 &SafeResponse); 00646 } 00647 00648 /* Check if we were called in user-mode */ 00649 if (PreviousMode != KernelMode) 00650 { 00651 /* That means we have a buffer to free */ 00652 if (SafeParams) ExFreePoolWithTag(SafeParams, TAG_ERR); 00653 00654 /* Enter SEH Block for return */ 00655 _SEH2_TRY 00656 { 00657 /* Return the response */ 00658 *Response = SafeResponse; 00659 } 00660 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00661 { 00662 /* Get the exception code */ 00663 Status = _SEH2_GetExceptionCode(); 00664 } 00665 _SEH2_END; 00666 } 00667 else 00668 { 00669 /* Return the response */ 00670 *Response = SafeResponse; 00671 } 00672 00673 /* Return status */ 00674 return Status; 00675 } 00676 00677 /*++ 00678 * @name NtSetDefaultHardErrorPort 00679 * @implemented 00680 * 00681 * NtSetDefaultHardErrorPort is typically called only once. After call, 00682 * kernel set BOOLEAN flag named _ExReadyForErrors to TRUE, and all other 00683 * tries to change default port are broken with STATUS_UNSUCCESSFUL error code 00684 * See: http://www.windowsitlibrary.com/Content/356/08/2.html 00685 * http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtSetDefaultHardErrorPort.html 00686 * 00687 * @param PortHandle 00688 * Handle to named port object 00689 * 00690 * @return Status 00691 * 00692 * @remarks Privileges: SE_TCB_PRIVILEGE 00693 * 00694 *--*/ 00695 NTSTATUS 00696 NTAPI 00697 NtSetDefaultHardErrorPort(IN HANDLE PortHandle) 00698 { 00699 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00700 NTSTATUS Status = STATUS_UNSUCCESSFUL; 00701 00702 /* Check if we have the Privilege */ 00703 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 00704 { 00705 DPRINT1("NtSetDefaultHardErrorPort: Caller requires " 00706 "the SeTcbPrivilege privilege!\n"); 00707 return STATUS_PRIVILEGE_NOT_HELD; 00708 } 00709 00710 /* Only called once during bootup, make sure we weren't called yet */ 00711 if (!ExReadyForErrors) 00712 { 00713 /* Reference the port */ 00714 Status = ObReferenceObjectByHandle(PortHandle, 00715 0, 00716 LpcPortObjectType, 00717 PreviousMode, 00718 (PVOID*)&ExpDefaultErrorPort, 00719 NULL); 00720 if (NT_SUCCESS(Status)) 00721 { 00722 /* Save the data */ 00723 ExpDefaultErrorPortProcess = PsGetCurrentProcess(); 00724 ExReadyForErrors = TRUE; 00725 } 00726 } 00727 00728 /* Return status to caller */ 00729 return Status; 00730 } 00731 00732 VOID 00733 __cdecl 00734 _purecall(VOID) 00735 { 00736 /* Not supported in Kernel Mode */ 00737 RtlRaiseStatus(STATUS_NOT_IMPLEMENTED); 00738 } 00739 00740 /* EOF */ Generated on Mon May 28 2012 04:36:59 for ReactOS by
1.7.6.1
|