test: ctrlc.c Source File

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

# ctrlc.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1985 - 1999, Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     ctrlc.c
    00008
    00009 Abstract:
    00010
    00011     This module implements ctrl-c handling
    00012
    00013 Author:
    00014
    00015     Therese Stowell (thereses) 1-Mar-1991
    00016
    00017 Revision History:
    00018
    00019 --*/
    00020
    00021 #include "precomp.h"
    00022 #pragma hdrstop
    00023
    00024 #if !defined(BUILD_WOW64)
    00025
    00026 #define LIST_INCREMENT 2    // amount to grow handler list
    00027 #define INITIAL_LIST_SIZE 1 // initial length of handler list
    00028
    00029 PHANDLER_ROUTINE SingleHandler[INITIAL_LIST_SIZE]; // initial handler list
    00030 ULONG HandlerListLength;            // used length of handler list
    00031 ULONG AllocatedHandlerListLength;   // allocated length of handler list
    00032 PHANDLER_ROUTINE *HandlerList;      // pointer to handler list
    00033
    00034 #define NUMBER_OF_CTRL_EVENTS 7     // number of ctrl events
    00035 #define SYSTEM_CLOSE_EVENT 4
    00036
    00037 #define IGNORE_CTRL_C   0x01
    00038
    00039 BOOL LastConsoleEventActive;
    00040
    00041
    00042 BOOL
    00043 DefaultHandler(
    00044     IN ULONG CtrlType
    00045     )
    00046
    00047 /*++
    00048
    00049     This is the default ctrl handler.
    00050
    00051 Parameters:
    00052
    00053     CtrlType - type of ctrl event (ctrl-c, ctrl-break).
    00054
    00055 Return Value:
    00056
    00057     none.
    00058
    00059 --*/
    00060
    00061 {
    00062     ExitProcess((DWORD)CONTROL_C_EXIT);
    00063     return TRUE;
    00064     UNREFERENCED_PARAMETER(CtrlType);
    00065 }
    00066
    00067 NTSTATUS
    00068 InitializeCtrlHandling( VOID )
    00069
    00070 /*++
    00071
    00072     This routine initializes ctrl handling.  It is called by AllocConsole
    00073     and the dll initialization code.
    00074
    00075 Parameters:
    00076
    00077     none.
    00078
    00079 Return Value:
    00080
    00081     none.
    00082
    00083 --*/
    00084
    00085 {
    00086     AllocatedHandlerListLength = HandlerListLength = INITIAL_LIST_SIZE;
    00087     HandlerList = SingleHandler;
    00088     SingleHandler[0] = DefaultHandler;
    00089     return STATUS_SUCCESS;
    00090 }
    00091
    00092 DWORD
    00093 CtrlRoutine(
    00094     IN LPVOID lpThreadParameter
    00095     )
    00096
    00097 /*++
    00098
    00099 Routine Description:
    00100
    00101     This thread is created when ctrl-c or ctrl-break is entered,
    00102     or when close is selected.  it calls the appropriate handlers.
    00103
    00104 Arguments:
    00105
    00106     lpThreadParameter - what type of event happened.
    00107
    00108 Return Value:
    00109
    00110     STATUS_SUCCESS
    00111
    00112 --*/
    00113
    00114 {
    00115     ULONG i;
    00116     ULONG EventNumber,OriginalEventNumber;
    00117     DWORD fNoExit;
    00118     DWORD dwExitCode;
    00119     EXCEPTION_RECORD ExceptionRecord;
    00120
    00121     SetThreadPriority(NtCurrentThread(), THREAD_PRIORITY_HIGHEST);
    00122     OriginalEventNumber = EventNumber = PtrToUlong(lpThreadParameter);
    00123
    00124     //
    00125     // If this bit is set, it means we don't want to cause this process
    00126     // to exit itself if it is a logoff or shutdown event.
    00127     //
    00128     fNoExit = 0x80000000 & EventNumber;
    00129     EventNumber &= ~0x80000000;
    00130
    00131     //
    00132     // the ctrl_close event is set when the user selects the window
    00133     // close option from the system menu, or EndTask, or Settings-Terminate.
    00134     // the system close event is used when another ctrl-thread times out.
    00135     //
    00136
    00137     switch (EventNumber) {
    00138     default:
    00139         ASSERT (EventNumber < NUMBER_OF_CTRL_EVENTS);
    00140         if (EventNumber >= NUMBER_OF_CTRL_EVENTS)
    00141             return (DWORD)STATUS_UNSUCCESSFUL;
    00142         break;
    00143
    00144     case CTRL_C_EVENT:
    00145     case CTRL_BREAK_EVENT:
    00146         //
    00147         // If the process is being debugged, give the debugger
    00148         // a shot. If the debugger handles the exception, then
    00149         // go back and wait.
    00150         //
    00151
    00152         if (!IsDebuggerPresent())
    00153             break;
    00154
    00155         if ( EventNumber == CTRL_C_EVENT ) {
    00156             ExceptionRecord.ExceptionCode = DBG_CONTROL_C;
    00157             }
    00158         else {
    00159             ExceptionRecord.ExceptionCode = DBG_CONTROL_BREAK;
    00160             }
    00161         ExceptionRecord.ExceptionFlags = 0;
    00162         ExceptionRecord.ExceptionRecord = NULL;
    00163         ExceptionRecord.ExceptionAddress = (PVOID)DefaultHandler;
    00164         ExceptionRecord.NumberParameters = 0;
    00165
    00166         try {
    00167             RtlRaiseException(&ExceptionRecord);
    00168         } except (EXCEPTION_EXECUTE_HANDLER) {
    00169             LockDll();
    00170             try {
    00171                 if (EventNumber != CTRL_C_EVENT ||
    00172                         NtCurrentPeb()->ProcessParameters->ConsoleFlags != IGNORE_CTRL_C) {
    00173                     for (i=HandlerListLength;i>0;i--) {
    00174                         if ((HandlerList[i-1])(EventNumber)) {
    00175                             break;
    00176                         }
    00177                     }
    00178                 }
    00179             } finally {
    00180                 UnlockDll();
    00181             }
    00182         }
    00183         ExitThread(0);
    00184         break;
    00185
    00186     case SYSTEM_CLOSE_EVENT:
    00187         ExitProcess((DWORD)CONTROL_C_EXIT);
    00188         break;
    00189
    00190     case SYSTEM_ROOT_CONSOLE_EVENT:
    00191         if (!LastConsoleEventActive)
    00192             ExitThread(0);
    00193         break;
    00194
    00195     case CTRL_CLOSE_EVENT:
    00196     case CTRL_LOGOFF_EVENT:
    00197     case CTRL_SHUTDOWN_EVENT:
    00198         //if (LastConsoleEventActive)
    00199             //EventNumber = SYSTEM_ROOT_CONSOLE_EVENT;
    00200         break;
    00201     }
    00202
    00203     LockDll();
    00204     dwExitCode = 0;
    00205     try {
    00206         if (EventNumber != CTRL_C_EVENT ||
    00207                 NtCurrentPeb()->ProcessParameters->ConsoleFlags != IGNORE_CTRL_C) {
    00208             for (i=HandlerListLength;i>0;i--) {
    00209
    00210                 //
    00211                 // Don't call the last handler (the default one which calls
    00212                 // ExitProcess() if this process isn't supposed to exit (system
    00213                 // process are not supposed to exit because of shutdown or
    00214                 // logoff event notification).
    00215                 //
    00216
    00217                 if ((i-1) == 0 && fNoExit) {
    00218                     if (EventNumber == CTRL_LOGOFF_EVENT ||
    00219                         EventNumber == CTRL_SHUTDOWN_EVENT) {
    00220                         break;
    00221                     }
    00222                 }
    00223
    00224                 if ((HandlerList[i-1])(EventNumber)) {
    00225                     switch (EventNumber) {
    00226                     case CTRL_CLOSE_EVENT:
    00227                     case CTRL_LOGOFF_EVENT:
    00228                     case CTRL_SHUTDOWN_EVENT:
    00229                     case SYSTEM_ROOT_CONSOLE_EVENT:
    00230                         dwExitCode = OriginalEventNumber;
    00231                         break;
    00232                     }
    00233                     break;
    00234                 }
    00235             }
    00236         }
    00237     } finally {
    00238         UnlockDll();
    00239     }
    00240     ExitThread(dwExitCode);
    00241     return STATUS_SUCCESS;
    00242 }
    00243
    00244 #endif
    00245
    00246 #if !defined(BUILD_WOW6432)
    00247
    00248 VOID
    00249 APIENTRY
    00250 SetLastConsoleEventActiveInternal( VOID )
    00251
    00252 /*++
    00253
    00254 Routine Description:
    00255
    00256     Sends a ConsolepNotifyLastClose command to the server.
    00257
    00258 Arguments:
    00259
    00260     none.
    00261
    00262 Return Value:
    00263
    00264     None.
    00265
    00266 --*/
    00267
    00268 {
    00269     CONSOLE_API_MSG m;
    00270     PCONSOLE_NOTIFYLASTCLOSE_MSG a = &m.u.SetLastConsoleEventActive;
    00271
    00272     a->ConsoleHandle = GET_CONSOLE_HANDLE;
    00273     CsrClientCallServer( (PCSR_API_MSG)&m,
    00274                          NULL,
    00275                          CSR_MAKE_API_NUMBER( CONSRV_SERVERDLL_INDEX,
    00276                                               ConsolepNotifyLastClose
    00277                                             ),
    00278                          sizeof( *a )
    00279                        );
    00280 }
    00281
    00282 #endif
    00283
    00284 #if !defined(BUILD_WOW64)
    00285
    00286 VOID
    00287 APIENTRY
    00288 SetLastConsoleEventActive( VOID )
    00289 // private api
    00290 {
    00291
    00292     LastConsoleEventActive = TRUE;
    00293     SetLastConsoleEventActiveInternal();
    00294 }
    00295
    00296 BOOL
    00297 SetCtrlHandler(
    00298     IN PHANDLER_ROUTINE HandlerRoutine
    00299     )
    00300
    00301 /*++
    00302
    00303 Routine Description:
    00304
    00305     This routine adds a ctrl handler to the process's list.
    00306
    00307 Arguments:
    00308
    00309     HandlerRoutine - pointer to ctrl handler.
    00310
    00311 Return Value:
    00312
    00313     TRUE - success.
    00314
    00315 --*/
    00316
    00317 {
    00318     PHANDLER_ROUTINE *NewHandlerList;
    00319
    00320     //
    00321     // NULL handler routine is not stored in table. It is
    00322     // used to temporarily inhibit ^C event handling
    00323     //
    00324
    00325     if ( !HandlerRoutine ) {
    00326         NtCurrentPeb()->ProcessParameters->ConsoleFlags = IGNORE_CTRL_C;
    00327         return TRUE;
    00328         }
    00329
    00330     if (HandlerListLength == AllocatedHandlerListLength) {
    00331
    00332         //
    00333         // grow list
    00334         //
    00335
    00336         NewHandlerList = (PHANDLER_ROUTINE *) RtlAllocateHeap( RtlProcessHeap(), 0,
    00337                                                  sizeof(PHANDLER_ROUTINE) * (HandlerListLength + LIST_INCREMENT));
    00338         if (!NewHandlerList) {
    00339             SET_LAST_ERROR(ERROR_NOT_ENOUGH_MEMORY);
    00340             return FALSE;
    00341         }
    00342
    00343         //
    00344         // copy list
    00345         //
    00346
    00347         RtlCopyMemory(NewHandlerList,HandlerList,sizeof(PHANDLER_ROUTINE) * HandlerListLength);
    00348
    00349         if (HandlerList != SingleHandler) {
    00350
    00351             //
    00352             // free old list
    00353             //
    00354
    00355             RtlFreeHeap(RtlProcessHeap(), 0, HandlerList);
    00356         }
    00357         HandlerList = NewHandlerList;
    00358         AllocatedHandlerListLength += LIST_INCREMENT;
    00359     }
    00360     ASSERT (HandlerListLength < AllocatedHandlerListLength);
    00361
    00362     HandlerList[HandlerListLength] = HandlerRoutine;
    00363     HandlerListLength++;
    00364     return TRUE;
    00365 }
    00366
    00367 BOOL
    00368 RemoveCtrlHandler(
    00369     IN PHANDLER_ROUTINE HandlerRoutine
    00370     )
    00371
    00372 /*++
    00373
    00374 Routine Description:
    00375
    00376     This routine removes a ctrl handler from the process's list.
    00377
    00378 Arguments:
    00379
    00380     HandlerRoutine - pointer to ctrl handler.
    00381
    00382 Return Value:
    00383
    00384     TRUE - success.
    00385
    00386 --*/
    00387
    00388 {
    00389     ULONG i;
    00390
    00391     //
    00392     // NULL handler routine is not stored in table. It is
    00393     // used to temporarily inhibit ^C event handling. Removing
    00394     // this handler allows normal processing to occur
    00395     //
    00396
    00397     if ( !HandlerRoutine ) {
    00398         NtCurrentPeb()->ProcessParameters->ConsoleFlags = 0;
    00399         return TRUE;
    00400         }
    00401
    00402     for (i=0;i<HandlerListLength;i++) {
    00403         if (*(HandlerList+i) == HandlerRoutine) {
    00404             if (i < (HandlerListLength-1)) {
    00405                 memmove(&HandlerList[i],&HandlerList[i+1],sizeof(PHANDLER_ROUTINE) * (HandlerListLength - i - 1));
    00406             }
    00407             HandlerListLength -= 1;
    00408             return TRUE;
    00409         }
    00410     }
    00411     SET_LAST_ERROR(ERROR_INVALID_PARAMETER);
    00412     return FALSE;
    00413 }
    00414
    00415 BOOL
    00416 APIENTRY
    00417 SetConsoleCtrlHandler(
    00418     IN PHANDLER_ROUTINE HandlerRoutine,
    00419     IN BOOL Add       // add or delete
    00420     )
    00421
    00422 /*++
    00423
    00424 Routine Description:
    00425
    00426     This routine adds or removes a ctrl handler from the process's list.
    00427
    00428 Arguments:
    00429
    00430     HandlerRoutine - pointer to ctrl handler.
    00431
    00432     Add - if TRUE, add handler.  else remove.
    00433
    00434 Return Value:
    00435
    00436     TRUE - success.
    00437
    00438 --*/
    00439
    00440 {
    00441     BOOL Success;
    00442
    00443     LockDll();
    00444     if (Add) {
    00445         Success = SetCtrlHandler(HandlerRoutine);
    00446     }
    00447     else {
    00448         Success = RemoveCtrlHandler(HandlerRoutine);
    00449     }
    00450     UnlockDll();
    00451     return Success;
    00452 }
    00453
    00454 #endif