Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

452 lines
10 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. ctrlc.c
  5. Abstract:
  6. This module implements ctrl-c handling
  7. Author:
  8. Therese Stowell (thereses) 1-Mar-1991
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #if !defined(BUILD_WOW64)
  14. #define LIST_INCREMENT 2 // amount to grow handler list
  15. #define INITIAL_LIST_SIZE 1 // initial length of handler list
  16. PHANDLER_ROUTINE SingleHandler[INITIAL_LIST_SIZE]; // initial handler list
  17. ULONG HandlerListLength; // used length of handler list
  18. ULONG AllocatedHandlerListLength; // allocated length of handler list
  19. PHANDLER_ROUTINE *HandlerList; // pointer to handler list
  20. #define NUMBER_OF_CTRL_EVENTS 7 // number of ctrl events
  21. #define SYSTEM_CLOSE_EVENT 4
  22. BOOL LastConsoleEventActive;
  23. BOOL
  24. DefaultHandler(
  25. IN ULONG CtrlType
  26. )
  27. /*++
  28. This is the default ctrl handler.
  29. Parameters:
  30. CtrlType - type of ctrl event (ctrl-c, ctrl-break).
  31. Return Value:
  32. none.
  33. --*/
  34. {
  35. ExitProcess((DWORD)CONTROL_C_EXIT);
  36. return TRUE;
  37. UNREFERENCED_PARAMETER(CtrlType);
  38. }
  39. NTSTATUS
  40. InitializeCtrlHandling( VOID )
  41. /*++
  42. This routine initializes ctrl handling. It is called by AllocConsole
  43. and the dll initialization code.
  44. Parameters:
  45. none.
  46. Return Value:
  47. none.
  48. --*/
  49. {
  50. AllocatedHandlerListLength = HandlerListLength = INITIAL_LIST_SIZE;
  51. HandlerList = SingleHandler;
  52. SingleHandler[0] = DefaultHandler;
  53. return STATUS_SUCCESS;
  54. }
  55. DWORD
  56. CtrlRoutine(
  57. IN LPVOID lpThreadParameter
  58. )
  59. /*++
  60. Routine Description:
  61. This thread is created when ctrl-c or ctrl-break is entered,
  62. or when close is selected. it calls the appropriate handlers.
  63. Arguments:
  64. lpThreadParameter - what type of event happened.
  65. Return Value:
  66. STATUS_SUCCESS
  67. --*/
  68. {
  69. ULONG i;
  70. ULONG EventNumber,OriginalEventNumber;
  71. DWORD fNoExit;
  72. DWORD dwExitCode;
  73. EXCEPTION_RECORD ExceptionRecord;
  74. SetThreadPriority(NtCurrentThread(), THREAD_PRIORITY_HIGHEST);
  75. OriginalEventNumber = EventNumber = PtrToUlong(lpThreadParameter);
  76. //
  77. // If this bit is set, it means we don't want to cause this process
  78. // to exit itself if it is a logoff or shutdown event.
  79. //
  80. fNoExit = 0x80000000 & EventNumber;
  81. EventNumber &= ~0x80000000;
  82. //
  83. // the ctrl_close event is set when the user selects the window
  84. // close option from the system menu, or EndTask, or Settings-Terminate.
  85. // the system close event is used when another ctrl-thread times out.
  86. //
  87. switch (EventNumber) {
  88. default:
  89. ASSERT (EventNumber < NUMBER_OF_CTRL_EVENTS);
  90. if (EventNumber >= NUMBER_OF_CTRL_EVENTS)
  91. return (DWORD)STATUS_UNSUCCESSFUL;
  92. break;
  93. case CTRL_C_EVENT:
  94. case CTRL_BREAK_EVENT:
  95. //
  96. // If the process is being debugged, give the debugger
  97. // a shot. If the debugger handles the exception, then
  98. // go back and wait.
  99. //
  100. if (!IsDebuggerPresent())
  101. break;
  102. if ( EventNumber == CTRL_C_EVENT ) {
  103. ExceptionRecord.ExceptionCode = DBG_CONTROL_C;
  104. }
  105. else {
  106. ExceptionRecord.ExceptionCode = DBG_CONTROL_BREAK;
  107. }
  108. ExceptionRecord.ExceptionFlags = 0;
  109. ExceptionRecord.ExceptionRecord = NULL;
  110. ExceptionRecord.ExceptionAddress = (PVOID)DefaultHandler;
  111. ExceptionRecord.NumberParameters = 0;
  112. try {
  113. RtlRaiseException(&ExceptionRecord);
  114. } except (EXCEPTION_EXECUTE_HANDLER) {
  115. LockDll();
  116. try {
  117. if (EventNumber != CTRL_C_EVENT ||
  118. (NtCurrentPeb()->ProcessParameters->ConsoleFlags & CONSOLE_IGNORE_CTRL_C) == 0) {
  119. for (i=HandlerListLength;i>0;i--) {
  120. if ((HandlerList[i-1])(EventNumber)) {
  121. break;
  122. }
  123. }
  124. }
  125. } finally {
  126. UnlockDll();
  127. }
  128. }
  129. ExitThread(0);
  130. break;
  131. case SYSTEM_CLOSE_EVENT:
  132. ExitProcess((DWORD)CONTROL_C_EXIT);
  133. break;
  134. case SYSTEM_ROOT_CONSOLE_EVENT:
  135. if (!LastConsoleEventActive)
  136. ExitThread(0);
  137. break;
  138. case CTRL_CLOSE_EVENT:
  139. case CTRL_LOGOFF_EVENT:
  140. case CTRL_SHUTDOWN_EVENT:
  141. //if (LastConsoleEventActive)
  142. //EventNumber = SYSTEM_ROOT_CONSOLE_EVENT;
  143. break;
  144. }
  145. LockDll();
  146. dwExitCode = 0;
  147. try {
  148. if (EventNumber != CTRL_C_EVENT ||
  149. (NtCurrentPeb()->ProcessParameters->ConsoleFlags & CONSOLE_IGNORE_CTRL_C) == 0) {
  150. for (i=HandlerListLength;i>0;i--) {
  151. //
  152. // Don't call the last handler (the default one which calls
  153. // ExitProcess() if this process isn't supposed to exit (system
  154. // process are not supposed to exit because of shutdown or
  155. // logoff event notification).
  156. //
  157. if ((i-1) == 0 && fNoExit) {
  158. if (EventNumber == CTRL_LOGOFF_EVENT ||
  159. EventNumber == CTRL_SHUTDOWN_EVENT) {
  160. break;
  161. }
  162. }
  163. if ((HandlerList[i-1])(EventNumber)) {
  164. switch (EventNumber) {
  165. case CTRL_CLOSE_EVENT:
  166. case CTRL_LOGOFF_EVENT:
  167. case CTRL_SHUTDOWN_EVENT:
  168. case SYSTEM_ROOT_CONSOLE_EVENT:
  169. dwExitCode = OriginalEventNumber;
  170. break;
  171. }
  172. break;
  173. }
  174. }
  175. }
  176. } finally {
  177. UnlockDll();
  178. }
  179. ExitThread(dwExitCode);
  180. return STATUS_SUCCESS;
  181. }
  182. #endif //!defined(BUILD_WOW64)
  183. #if !defined(BUILD_WOW6432)
  184. VOID
  185. APIENTRY
  186. SetLastConsoleEventActiveInternal( VOID )
  187. /*++
  188. Routine Description:
  189. Sends a ConsolepNotifyLastClose command to the server.
  190. Arguments:
  191. none.
  192. Return Value:
  193. None.
  194. --*/
  195. {
  196. CONSOLE_API_MSG m;
  197. PCONSOLE_NOTIFYLASTCLOSE_MSG a = &m.u.SetLastConsoleEventActive;
  198. a->ConsoleHandle = GET_CONSOLE_HANDLE;
  199. CsrClientCallServer( (PCSR_API_MSG)&m,
  200. NULL,
  201. CSR_MAKE_API_NUMBER( CONSRV_SERVERDLL_INDEX,
  202. ConsolepNotifyLastClose
  203. ),
  204. sizeof( *a )
  205. );
  206. }
  207. #endif //!defined(BUILD_WOW6432)
  208. #if !defined(BUILD_WOW64)
  209. VOID
  210. APIENTRY
  211. SetLastConsoleEventActive( VOID )
  212. // private api
  213. {
  214. LastConsoleEventActive = TRUE;
  215. SetLastConsoleEventActiveInternal();
  216. }
  217. BOOL
  218. SetCtrlHandler(
  219. IN PHANDLER_ROUTINE HandlerRoutine
  220. )
  221. /*++
  222. Routine Description:
  223. This routine adds a ctrl handler to the process's list.
  224. Arguments:
  225. HandlerRoutine - pointer to ctrl handler.
  226. Return Value:
  227. TRUE - success.
  228. --*/
  229. {
  230. PHANDLER_ROUTINE *NewHandlerList;
  231. //
  232. // NULL handler routine is not stored in table. It is
  233. // used to temporarily inhibit ^C event handling
  234. //
  235. if (!HandlerRoutine) {
  236. NtCurrentPeb()->ProcessParameters->ConsoleFlags |= CONSOLE_IGNORE_CTRL_C;
  237. return TRUE;
  238. }
  239. if (HandlerListLength == AllocatedHandlerListLength) {
  240. //
  241. // grow list
  242. //
  243. NewHandlerList = (PHANDLER_ROUTINE *) RtlAllocateHeap( RtlProcessHeap(), 0,
  244. sizeof(PHANDLER_ROUTINE) * (HandlerListLength + LIST_INCREMENT));
  245. if (!NewHandlerList) {
  246. SET_LAST_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  247. return FALSE;
  248. }
  249. //
  250. // copy list
  251. //
  252. RtlCopyMemory(NewHandlerList,HandlerList,sizeof(PHANDLER_ROUTINE) * HandlerListLength);
  253. if (HandlerList != SingleHandler) {
  254. //
  255. // free old list
  256. //
  257. RtlFreeHeap(RtlProcessHeap(), 0, HandlerList);
  258. }
  259. HandlerList = NewHandlerList;
  260. AllocatedHandlerListLength += LIST_INCREMENT;
  261. }
  262. ASSERT (HandlerListLength < AllocatedHandlerListLength);
  263. HandlerList[HandlerListLength] = HandlerRoutine;
  264. HandlerListLength++;
  265. return TRUE;
  266. }
  267. BOOL
  268. RemoveCtrlHandler(
  269. IN PHANDLER_ROUTINE HandlerRoutine
  270. )
  271. /*++
  272. Routine Description:
  273. This routine removes a ctrl handler from the process's list.
  274. Arguments:
  275. HandlerRoutine - pointer to ctrl handler.
  276. Return Value:
  277. TRUE - success.
  278. --*/
  279. {
  280. ULONG i;
  281. //
  282. // NULL handler routine is not stored in table. It is
  283. // used to temporarily inhibit ^C event handling. Removing
  284. // this handler allows normal processing to occur
  285. //
  286. if ( !HandlerRoutine ) {
  287. NtCurrentPeb()->ProcessParameters->ConsoleFlags = 0;
  288. return TRUE;
  289. }
  290. for (i=0;i<HandlerListLength;i++) {
  291. if (*(HandlerList+i) == HandlerRoutine) {
  292. if (i < (HandlerListLength-1)) {
  293. memmove(&HandlerList[i],&HandlerList[i+1],sizeof(PHANDLER_ROUTINE) * (HandlerListLength - i - 1));
  294. }
  295. HandlerListLength -= 1;
  296. return TRUE;
  297. }
  298. }
  299. SET_LAST_ERROR(ERROR_INVALID_PARAMETER);
  300. return FALSE;
  301. }
  302. BOOL
  303. APIENTRY
  304. SetConsoleCtrlHandler(
  305. IN PHANDLER_ROUTINE HandlerRoutine,
  306. IN BOOL Add // add or delete
  307. )
  308. /*++
  309. Routine Description:
  310. This routine adds or removes a ctrl handler from the process's list.
  311. Arguments:
  312. HandlerRoutine - pointer to ctrl handler.
  313. Add - if TRUE, add handler. else remove.
  314. Return Value:
  315. TRUE - success.
  316. --*/
  317. {
  318. BOOL Success;
  319. LockDll();
  320. if (Add) {
  321. Success = SetCtrlHandler(HandlerRoutine);
  322. }
  323. else {
  324. Success = RemoveCtrlHandler(HandlerRoutine);
  325. }
  326. UnlockDll();
  327. return Success;
  328. }
  329. #endif //!defined(BUILD_WOW64)