[corlib] Add Console.[Input|Output]Encoding to the mobile profiles.
[mono.git] / mcs / class / corlib / System / Console.cs
1 //
2 // System.Console.cs
3 //
4 // Author:
5 //      Dietmar Maurer (dietmar@ximian.com)
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
8 // (C) Ximian, Inc.  http://www.ximian.com
9 // (C) 2004,2005 Novell, Inc. (http://www.novell.com)
10 // Copyright 2013 Xamarin Inc. (http://www.xamarin.com)
11
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Diagnostics;
33 using System.IO;
34 using System.Runtime.CompilerServices;
35 using System.Runtime.InteropServices;
36 using System.Security;
37 using System.Security.Permissions;
38 using System.Text;
39
40 namespace System
41 {
42         public static partial class Console
43         {
44 #if !NET_2_1
45                 private class WindowsConsole
46                 {
47                         public static bool ctrlHandlerAdded = false;
48                         private delegate bool WindowsCancelHandler (int keyCode);
49                         private static WindowsCancelHandler cancelHandler = new WindowsCancelHandler (DoWindowsConsoleCancelEvent);
50
51                         [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
52                         private static extern int GetConsoleCP ();
53                         [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
54                         private static extern int GetConsoleOutputCP ();
55
56                         [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
57                         private static extern bool SetConsoleCtrlHandler (WindowsCancelHandler handler, bool addHandler);
58
59                         // Only call the event handler if Control-C was pressed (code == 0), nothing else
60                         private static bool DoWindowsConsoleCancelEvent (int keyCode)
61                         {
62                                 if (keyCode == 0)
63                                         DoConsoleCancelEvent ();
64                                 return keyCode == 0;
65                         }
66
67                         [MethodImpl (MethodImplOptions.NoInlining)]
68                         public static int GetInputCodePage ()
69                         {
70                                 return GetConsoleCP ();
71                         }
72
73                         [MethodImpl (MethodImplOptions.NoInlining)]
74                         public static int GetOutputCodePage ()
75                         {
76                                 return GetConsoleOutputCP ();
77                         }
78
79                         public static void AddCtrlHandler ()
80                         {
81                                 SetConsoleCtrlHandler (cancelHandler, true);
82                                 ctrlHandlerAdded = true;
83                         }
84                         
85                         public static void RemoveCtrlHandler ()
86                         {
87                                 SetConsoleCtrlHandler (cancelHandler, false);
88                                 ctrlHandlerAdded = false;
89                         }
90                 }
91 #endif
92
93                 internal static TextWriter stdout;
94                 private static TextWriter stderr;
95                 private static TextReader stdin;
96
97                 static Console ()
98                 {
99 #if NET_2_1
100                         Encoding inputEncoding;
101                         Encoding outputEncoding;
102 #endif
103
104                         if (Environment.IsRunningOnWindows) {
105                                 //
106                                 // On Windows, follow the Windows tradition
107                                 //
108 #if NET_2_1
109                                 // should never happen since Moonlight does not run on windows
110                                 inputEncoding = outputEncoding = Encoding.Default;
111 #else                   
112                                 try {
113                                         inputEncoding = Encoding.GetEncoding (WindowsConsole.GetInputCodePage ());
114                                         outputEncoding = Encoding.GetEncoding (WindowsConsole.GetOutputCodePage ());
115                                         // ArgumentException and NotSupportedException can be thrown as well
116                                 } catch {
117                                         // FIXME: I18N assemblies are not available when compiling mcs
118                                         // Use Latin 1 as it is fast and UTF-8 is never used as console code page
119                                         inputEncoding = outputEncoding = Encoding.Default;
120                                 }
121 #endif
122                         } else {
123                                 //
124                                 // On Unix systems (128), do not output the
125                                 // UTF-8 ZWNBSP (zero-width non-breaking space).
126                                 //
127                                 int code_page = 0;
128                                 EncodingHelper.InternalCodePage (ref code_page);
129
130                                 if (code_page != -1 && ((code_page & 0x0fffffff) == 3 // UTF8Encoding.UTF8_CODE_PAGE
131                                         || ((code_page & 0x10000000) != 0)))
132                                         inputEncoding = outputEncoding = EncodingHelper.UTF8Unmarked;
133                                 else
134                                         inputEncoding = outputEncoding = Encoding.Default;
135                         }
136
137                         SetupStreams (inputEncoding, outputEncoding);
138                 }
139
140                 static void SetupStreams (Encoding inputEncoding, Encoding outputEncoding)
141                 {
142 #if !NET_2_1
143                         if (!Environment.IsRunningOnWindows && ConsoleDriver.IsConsole) {
144                                 stdin = new CStreamReader (OpenStandardInput (0), inputEncoding);
145                                 stdout = TextWriter.Synchronized (new CStreamWriter (OpenStandardOutput (0), outputEncoding, true) { AutoFlush = true });
146                                 stderr = TextWriter.Synchronized (new CStreamWriter (OpenStandardError (0), outputEncoding, true) { AutoFlush = true });
147                         } else
148 #endif
149                         {
150                                 stdin = TextReader.Synchronized (new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding));
151
152 #if MONOTOUCH
153                                 stdout = new NSLogWriter ();
154                                 stderr = new NSLogWriter ();
155 #else
156                                 stdout = TextWriter.Synchronized (new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding) { AutoFlush = true });
157                                 stderr = TextWriter.Synchronized (new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding) { AutoFlush = true });
158
159 #if MONODROID
160                                 if (LogcatTextWriter.IsRunningOnAndroid ()) {
161                                         stdout = TextWriter.Synchronized (new LogcatTextWriter ("mono-stdout", stdout));
162                                         stderr = TextWriter.Synchronized (new LogcatTextWriter ("mono-stderr", stderr));
163                                 }
164 #endif // MONODROID
165 #endif // MONOTOUCH
166                         }
167
168                         GC.SuppressFinalize (stdout);
169                         GC.SuppressFinalize (stderr);
170                         GC.SuppressFinalize (stdin);
171                 }
172
173                 public static TextWriter Error {
174                         get {
175                                 return stderr;
176                         }
177                 }
178
179                 public static TextWriter Out {
180                         get {
181                                 return stdout;
182                         }
183                 }
184
185                 public static TextReader In {
186                         get {
187                                 return stdin;
188                         }
189                 }
190
191                 private static Stream Open (IntPtr handle, FileAccess access, int bufferSize)
192                 {
193                         try {
194                                 // TODO: Should use __ConsoleStream from reference sources
195                                 return new FileStream (handle, access, false, bufferSize, false, true);
196                         } catch (IOException) {
197                                 return Stream.Null;
198                         }
199                 }
200
201                 public static Stream OpenStandardError ()
202                 {
203                         return OpenStandardError (0);
204                 }
205
206                 // calling any FileStream constructor with a handle normally
207                 // requires permissions UnmanagedCode permissions. In this 
208                 // case we assert this permission so the console can be used
209                 // in partial trust (i.e. without having UnmanagedCode).
210                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
211                 public static Stream OpenStandardError (int bufferSize)
212                 {
213                         return Open (MonoIO.ConsoleError, FileAccess.Write, bufferSize);
214                 }
215
216                 public static Stream OpenStandardInput ()
217                 {
218                         return OpenStandardInput (0);
219                 }
220
221                 // calling any FileStream constructor with a handle normally
222                 // requires permissions UnmanagedCode permissions. In this 
223                 // case we assert this permission so the console can be used
224                 // in partial trust (i.e. without having UnmanagedCode).
225                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
226                 public static Stream OpenStandardInput (int bufferSize)
227                 {
228                         return Open (MonoIO.ConsoleInput, FileAccess.Read, bufferSize);
229                 }
230
231                 public static Stream OpenStandardOutput ()
232                 {
233                         return OpenStandardOutput (0);
234                 }
235
236                 // calling any FileStream constructor with a handle normally
237                 // requires permissions UnmanagedCode permissions. In this 
238                 // case we assert this permission so the console can be used
239                 // in partial trust (i.e. without having UnmanagedCode).
240                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
241                 public static Stream OpenStandardOutput (int bufferSize)
242                 {
243                         return Open (MonoIO.ConsoleOutput, FileAccess.Write, bufferSize);
244                 }
245
246                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
247                 public static void SetError (TextWriter newError)
248                 {
249                         if (newError == null)
250                                 throw new ArgumentNullException ("newError");
251
252                         stderr = newError;
253                 }
254
255                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
256                 public static void SetIn (TextReader newIn)
257                 {
258                         if (newIn == null)
259                                 throw new ArgumentNullException ("newIn");
260
261                         stdin = newIn;
262                 }
263
264                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
265                 public static void SetOut (TextWriter newOut)
266                 {
267                         if (newOut == null)
268                                 throw new ArgumentNullException ("newOut");
269
270                         stdout = newOut;
271                 }
272
273                 public static void Write (bool value)
274                 {
275                         stdout.Write (value);
276                 }
277
278                 public static void Write (char value)
279                 {
280                         stdout.Write (value);
281                 }
282
283                 public static void Write (char[] buffer)
284                 {
285                         stdout.Write (buffer);
286                 }
287
288                 public static void Write (decimal value)
289                 {
290                         stdout.Write (value);
291                 }
292                 
293                 public static void Write (double value)
294                 {
295                         stdout.Write (value);
296                 }
297
298                 public static void Write (int value)
299                 {
300                         stdout.Write (value);
301                 }
302
303                 public static void Write (long value)
304                 {
305                         stdout.Write (value);
306                 }
307
308                 public static void Write (object value)
309                 {
310                         stdout.Write (value);
311                 }
312
313                 public static void Write (float value)
314                 {
315                         stdout.Write (value);
316                 }
317
318                 public static void Write (string value)
319                 {
320                         stdout.Write (value);
321                 }
322
323                 [CLSCompliant (false)]
324                 public static void Write (uint value)
325                 {
326                         stdout.Write (value);
327                 }
328
329                 [CLSCompliant (false)]
330                 public static void Write (ulong value)
331                 {
332                         stdout.Write (value);
333                 }
334
335                 public static void Write (string format, object arg0)
336                 {
337                         stdout.Write (format, arg0);
338                 }
339
340                 public static void Write (string format, params object[] arg)
341                 {
342                         if (arg == null)
343                                 stdout.Write (format);
344                         else
345                                 stdout.Write (format, arg);
346                 }
347
348                 public static void Write (char[] buffer, int index, int count)
349                 {
350                         stdout.Write (buffer, index, count);
351                 }
352
353                 public static void Write (string format, object arg0, object arg1)
354                 {
355                         stdout.Write (format, arg0, arg1);
356                 }
357
358                 public static void Write (string format, object arg0, object arg1, object arg2 )
359                 {
360                         stdout.Write (format, arg0, arg1, arg2);
361                 }
362
363                 [CLSCompliant (false)]
364                 public static void Write (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
365                 {
366                         ArgIterator iter = new ArgIterator (__arglist);
367                         int argCount = iter.GetRemainingCount();
368
369                         object[] args = new object [argCount + 4];
370                         args [0] = arg0;
371                         args [1] = arg1;
372                         args [2] = arg2;
373                         args [3] = arg3;
374                         for (int i = 0; i < argCount; i++) {
375                                 TypedReference typedRef = iter.GetNextArg ();
376                                 args [i + 4] = TypedReference.ToObject (typedRef);
377                         }
378
379                         stdout.Write (String.Format (format, args));
380                 }
381
382                 public static void WriteLine ()
383                 {
384                         stdout.WriteLine ();
385                 }
386
387                 public static void WriteLine (bool value)
388                 {
389                         stdout.WriteLine (value);
390                 }
391
392                 public static void WriteLine (char value)
393                 {
394                         stdout.WriteLine (value);
395                 }
396
397                 public static void WriteLine (char[] buffer)
398                 {
399                         stdout.WriteLine (buffer);
400                 }
401
402                 public static void WriteLine (decimal value)
403                 {
404                         stdout.WriteLine (value);
405                 }
406
407                 public static void WriteLine (double value)
408                 {
409                         stdout.WriteLine (value);
410                 }
411
412                 public static void WriteLine (int value)
413                 {
414                         stdout.WriteLine (value);
415                 }
416
417                 public static void WriteLine (long value)
418                 {
419                         stdout.WriteLine (value);
420                 }
421
422                 public static void WriteLine (object value)
423                 {
424                         stdout.WriteLine (value);
425                 }
426
427                 public static void WriteLine (float value)
428                 {
429                         stdout.WriteLine (value);
430                 }
431
432                 public static void WriteLine (string value)
433                 {
434                         stdout.WriteLine (value);
435                 }
436
437                 [CLSCompliant (false)]
438                 public static void WriteLine (uint value)
439                 {
440                         stdout.WriteLine (value);
441                 }
442
443                 [CLSCompliant (false)]
444                 public static void WriteLine (ulong value)
445                 {
446                         stdout.WriteLine (value);
447                 }
448
449                 public static void WriteLine (string format, object arg0)
450                 {
451                         stdout.WriteLine (format, arg0);
452                 }
453
454                 public static void WriteLine (string format, params object[] arg)
455                 {
456                         if (arg == null)
457                                 stdout.WriteLine (format);
458                         else
459                                 stdout.WriteLine (format, arg);
460                 }
461
462                 public static void WriteLine (char[] buffer, int index, int count)
463                 {
464                         stdout.WriteLine (buffer, index, count);
465                 }
466
467                 public static void WriteLine (string format, object arg0, object arg1)
468                 {
469                         stdout.WriteLine (format, arg0, arg1);
470                 }
471
472                 public static void WriteLine (string format, object arg0, object arg1, object arg2)
473                 {
474                         stdout.WriteLine (format, arg0, arg1, arg2);
475                 }
476
477                 [CLSCompliant (false)]
478                 public static void WriteLine (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
479                 {
480                         ArgIterator iter = new ArgIterator (__arglist);
481                         int argCount = iter.GetRemainingCount();
482
483                         object[] args = new object [argCount + 4];
484                         args [0] = arg0;
485                         args [1] = arg1;
486                         args [2] = arg2;
487                         args [3] = arg3;
488                         for (int i = 0; i < argCount; i++) {
489                                 TypedReference typedRef = iter.GetNextArg ();
490                                 args [i + 4] = TypedReference.ToObject (typedRef);
491                         }
492
493                         stdout.WriteLine (String.Format (format, args));
494                 }
495
496 #if !NET_2_1
497                 public static int Read ()
498                 {
499                         if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
500                                 return ConsoleDriver.Read ();
501                         } else {
502                                 return stdin.Read ();
503                         }
504                 }
505
506                 public static string ReadLine ()
507                 {
508                         if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
509                                 return ConsoleDriver.ReadLine ();
510                         } else {
511                                 return stdin.ReadLine ();
512                         }
513                 }
514 #else
515                 public static int Read ()
516                 {
517                         return stdin.Read ();
518                 }
519
520                 public static string ReadLine ()
521                 {
522                         return stdin.ReadLine ();
523                 }
524
525 #endif
526
527                 // FIXME: Console should use these encodings when changed
528                 static Encoding inputEncoding;
529                 static Encoding outputEncoding;
530
531                 public static Encoding InputEncoding {
532                         get { return inputEncoding; }
533                         set {
534                                 inputEncoding = value;
535                                 SetupStreams (inputEncoding, outputEncoding);
536                         }
537                 }
538
539                 public static Encoding OutputEncoding {
540                         get { return outputEncoding; }
541                         set {
542                                 outputEncoding = value;
543                                 SetupStreams (inputEncoding, outputEncoding);
544                         }
545                 }
546
547 #if !NET_2_1
548                 public static ConsoleColor BackgroundColor {
549                         get { return ConsoleDriver.BackgroundColor; }
550                         set { ConsoleDriver.BackgroundColor = value; }
551                 }
552
553                 public static int BufferHeight {
554                         get { return ConsoleDriver.BufferHeight; }
555                         [MonoLimitation ("Implemented only on Windows")]
556                         set { ConsoleDriver.BufferHeight = value; }
557                 }
558
559                 public static int BufferWidth {
560                         get { return ConsoleDriver.BufferWidth; }
561                         [MonoLimitation ("Implemented only on Windows")]
562                         set { ConsoleDriver.BufferWidth = value; }
563                 }
564
565                 [MonoLimitation ("Implemented only on Windows")]
566                 public static bool CapsLock {
567                         get { return ConsoleDriver.CapsLock; }
568                 }
569
570                 public static int CursorLeft {
571                         get { return ConsoleDriver.CursorLeft; }
572                         set { ConsoleDriver.CursorLeft = value; }
573                 }
574
575                 public static int CursorTop {
576                         get { return ConsoleDriver.CursorTop; }
577                         set { ConsoleDriver.CursorTop = value; }
578                 }
579
580                 public static int CursorSize {
581                         get { return ConsoleDriver.CursorSize; }
582                         set { ConsoleDriver.CursorSize = value; }
583                 }
584
585                 public static bool CursorVisible {
586                         get { return ConsoleDriver.CursorVisible; }
587                         set { ConsoleDriver.CursorVisible = value; }
588                 }
589
590                 public static ConsoleColor ForegroundColor {
591                         get { return ConsoleDriver.ForegroundColor; }
592                         set { ConsoleDriver.ForegroundColor = value; }
593                 }
594
595                 public static bool KeyAvailable {
596                         get { return ConsoleDriver.KeyAvailable; }
597                 }
598
599                 public static int LargestWindowHeight {
600                         get { return ConsoleDriver.LargestWindowHeight; }
601                 }
602
603                 public static int LargestWindowWidth {
604                         get { return ConsoleDriver.LargestWindowWidth; }
605                 }
606
607                 [MonoLimitation ("Only works on windows")]
608                 public static bool NumberLock {
609                         get { return ConsoleDriver.NumberLock; }
610                 }
611
612                 public static string Title {
613                         get { return ConsoleDriver.Title; }
614                         set { ConsoleDriver.Title = value; }
615                 }
616
617                 public static bool TreatControlCAsInput {
618                         get { return ConsoleDriver.TreatControlCAsInput; }
619                         set { ConsoleDriver.TreatControlCAsInput = value; }
620                 }
621
622                 [MonoLimitation ("Only works on windows")]
623                 public static int WindowHeight {
624                         get { return ConsoleDriver.WindowHeight; }
625                         set { ConsoleDriver.WindowHeight = value; }
626                 }
627
628                 [MonoLimitation ("Only works on windows")]
629                 public static int WindowLeft {
630                         get { return ConsoleDriver.WindowLeft; }
631                         set { ConsoleDriver.WindowLeft = value; }
632                 }
633
634                 [MonoLimitation ("Only works on windows")]
635                 public static int WindowTop {
636                         get { return ConsoleDriver.WindowTop; }
637                         set { ConsoleDriver.WindowTop = value; }
638                 }
639
640                 [MonoLimitation ("Only works on windows")]
641                 public static int WindowWidth {
642                         get { return ConsoleDriver.WindowWidth; }
643                         set { ConsoleDriver.WindowWidth = value; }
644                 }
645
646                 public static bool IsErrorRedirected {
647                         get {
648                                 return ConsoleDriver.IsErrorRedirected;
649                         }
650                 }
651
652                 public static bool IsOutputRedirected {
653                         get {
654                                 return ConsoleDriver.IsOutputRedirected;
655                         }
656                 }
657
658                 public static bool IsInputRedirected {
659                         get {
660                                 return ConsoleDriver.IsInputRedirected;
661                         }
662                 }
663
664                 public static void Beep ()
665                 {
666                         Beep (1000, 500);
667                 }
668
669                 public static void Beep (int frequency, int duration)
670                 {
671                         if (frequency < 37 || frequency > 32767)
672                                 throw new ArgumentOutOfRangeException ("frequency");
673
674                         if (duration <= 0)
675                                 throw new ArgumentOutOfRangeException ("duration");
676
677                         ConsoleDriver.Beep (frequency, duration);
678                 }
679
680                 public static void Clear ()
681                 {
682                         ConsoleDriver.Clear ();
683                 }
684
685                 [MonoLimitation ("Implemented only on Windows")]
686                 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
687                                                 int targetLeft, int targetTop)
688                 {
689                         ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop);
690                 }
691
692                 [MonoLimitation ("Implemented only on Windows")]
693                 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
694                                                 int targetLeft, int targetTop, Char sourceChar,
695                                                 ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
696                 {
697                         ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop,
698                                                         sourceChar, sourceForeColor, sourceBackColor);
699                 }
700
701                 public static ConsoleKeyInfo ReadKey ()
702                 {
703                         return ReadKey (false);
704                 }
705
706                 public static ConsoleKeyInfo ReadKey (bool intercept)
707                 {
708                         return ConsoleDriver.ReadKey (intercept);
709                 }
710
711                 public static void ResetColor ()
712                 {
713                         ConsoleDriver.ResetColor ();
714                 }
715
716                 [MonoLimitation ("Only works on windows")]
717                 public static void SetBufferSize (int width, int height)
718                 {
719                         ConsoleDriver.SetBufferSize (width, height);
720                 }
721
722                 public static void SetCursorPosition (int left, int top)
723                 {
724                         ConsoleDriver.SetCursorPosition (left, top);
725                 }
726
727                 public static void SetWindowPosition (int left, int top)
728                 {
729                         ConsoleDriver.SetWindowPosition (left, top);
730                 }
731
732                 public static void SetWindowSize (int width, int height)
733                 {
734                         ConsoleDriver.SetWindowSize (width, height);
735                 }
736
737                 static ConsoleCancelEventHandler cancel_event;
738                 public static event ConsoleCancelEventHandler CancelKeyPress {
739                         add {
740                                 if (ConsoleDriver.Initialized == false)
741                                         ConsoleDriver.Init ();
742
743                                 cancel_event += value;
744
745                                 if (Environment.IsRunningOnWindows && !WindowsConsole.ctrlHandlerAdded)
746                                         WindowsConsole.AddCtrlHandler();
747                         }
748                         remove {
749                                 if (ConsoleDriver.Initialized == false)
750                                         ConsoleDriver.Init ();
751
752                                 cancel_event -= value;
753
754                                 if (cancel_event == null && Environment.IsRunningOnWindows)
755                                 {
756                                         // Need to remove our hook if there's nothing left in the event
757                                         if (WindowsConsole.ctrlHandlerAdded)
758                                                 WindowsConsole.RemoveCtrlHandler();
759                                 }
760                         }
761                 }
762
763                 delegate void InternalCancelHandler ();
764                 
765 #pragma warning disable 414
766                 //
767                 // Used by console-io.c
768                 //
769                 static readonly InternalCancelHandler cancel_handler = new InternalCancelHandler (DoConsoleCancelEvent);
770 #pragma warning restore 414             
771
772                 internal static void DoConsoleCancelEvent ()
773                 {
774                         bool exit = true;
775                         if (cancel_event != null) {
776                                 ConsoleCancelEventArgs args = new ConsoleCancelEventArgs (ConsoleSpecialKey.ControlC);
777                                 Delegate [] delegates = cancel_event.GetInvocationList ();
778                                 foreach (ConsoleCancelEventHandler d in delegates){
779                                         try {
780                                                 // Sender is always null here.
781                                                 d (null, args);
782                                         } catch {} // Ignore any exception.
783                                 }
784                                 exit = !args.Cancel;
785                         }
786
787                         if (exit)
788                                 Environment.Exit (58);
789                 }
790 #endif
791         }
792 }
793