Merge pull request #1464 from akoeplinger/fix-portable-target
[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                                 StreamWriter w = new CStreamWriter (OpenStandardOutput (0), outputEncoding);
145                                 w.AutoFlush = true;
146                                 stdout = TextWriter.Synchronized (w, true);
147
148                                 w = new CStreamWriter (OpenStandardOutput (0), outputEncoding);
149                                 w.AutoFlush = true;
150                                 stderr = TextWriter.Synchronized (w, true);
151                                 
152                                 stdin = new CStreamReader (OpenStandardInput (0), inputEncoding);
153                         } else {
154 #endif
155 // FULL_AOT_RUNTIME is used (instead of MONOTOUCH) since we only want this code when running on 
156 // iOS (simulator or devices) and *not* when running tools (e.g. btouch #12179) that needs to use 
157 // the mscorlib.dll shipped with Xamarin.iOS
158 #if MONOTOUCH && FULL_AOT_RUNTIME
159                                 stdout = new NSLogWriter ();
160 #else
161                                 stdout = new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding);
162                                 ((StreamWriter)stdout).AutoFlush = true;
163 #endif
164                                 stdout = TextWriter.Synchronized (stdout, true);
165
166 #if MONOTOUCH && FULL_AOT_RUNTIME
167                                 stderr = new NSLogWriter ();
168 #else
169                                 stderr = new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding); 
170                                 ((StreamWriter)stderr).AutoFlush = true;
171 #endif
172                                 stderr = TextWriter.Synchronized (stderr, true);
173
174                                 stdin = new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding);
175                                 stdin = TextReader.Synchronized (stdin);
176 #if !NET_2_1
177                         }
178 #endif
179
180 #if MONODROID
181                         if (LogcatTextWriter.IsRunningOnAndroid ()) {
182                                 stdout = TextWriter.Synchronized (new LogcatTextWriter ("mono-stdout", stdout));
183                                 stderr = TextWriter.Synchronized (new LogcatTextWriter ("mono-stderr", stderr));
184                         }
185 #endif  // MONODROID
186
187                         GC.SuppressFinalize (stdout);
188                         GC.SuppressFinalize (stderr);
189                         GC.SuppressFinalize (stdin);
190                 }
191
192                 public static TextWriter Error {
193                         get {
194                                 return stderr;
195                         }
196                 }
197
198                 public static TextWriter Out {
199                         get {
200                                 return stdout;
201                         }
202                 }
203
204                 public static TextReader In {
205                         get {
206                                 return stdin;
207                         }
208                 }
209
210                 private static Stream Open (IntPtr handle, FileAccess access, int bufferSize)
211                 {
212                         try {
213                                 return new FileStream (handle, access, false, bufferSize, false, bufferSize == 0);
214                         } catch (IOException) {
215                                 return new NullStream ();
216                         }
217                 }
218
219                 public static Stream OpenStandardError ()
220                 {
221                         return OpenStandardError (0);
222                 }
223
224                 // calling any FileStream constructor with a handle normally
225                 // requires permissions UnmanagedCode permissions. In this 
226                 // case we assert this permission so the console can be used
227                 // in partial trust (i.e. without having UnmanagedCode).
228                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
229                 public static Stream OpenStandardError (int bufferSize)
230                 {
231                         return Open (MonoIO.ConsoleError, FileAccess.Write, bufferSize);
232                 }
233
234                 public static Stream OpenStandardInput ()
235                 {
236                         return OpenStandardInput (0);
237                 }
238
239                 // calling any FileStream constructor with a handle normally
240                 // requires permissions UnmanagedCode permissions. In this 
241                 // case we assert this permission so the console can be used
242                 // in partial trust (i.e. without having UnmanagedCode).
243                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
244                 public static Stream OpenStandardInput (int bufferSize)
245                 {
246                         return Open (MonoIO.ConsoleInput, FileAccess.Read, bufferSize);
247                 }
248
249                 public static Stream OpenStandardOutput ()
250                 {
251                         return OpenStandardOutput (0);
252                 }
253
254                 // calling any FileStream constructor with a handle normally
255                 // requires permissions UnmanagedCode permissions. In this 
256                 // case we assert this permission so the console can be used
257                 // in partial trust (i.e. without having UnmanagedCode).
258                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
259                 public static Stream OpenStandardOutput (int bufferSize)
260                 {
261                         return Open (MonoIO.ConsoleOutput, FileAccess.Write, bufferSize);
262                 }
263
264                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
265                 public static void SetError (TextWriter newError)
266                 {
267                         if (newError == null)
268                                 throw new ArgumentNullException ("newError");
269
270                         stderr = newError;
271                 }
272
273                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
274                 public static void SetIn (TextReader newIn)
275                 {
276                         if (newIn == null)
277                                 throw new ArgumentNullException ("newIn");
278
279                         stdin = newIn;
280                 }
281
282                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
283                 public static void SetOut (TextWriter newOut)
284                 {
285                         if (newOut == null)
286                                 throw new ArgumentNullException ("newOut");
287
288                         stdout = newOut;
289                 }
290
291                 public static void Write (bool value)
292                 {
293                         stdout.Write (value);
294                 }
295
296                 public static void Write (char value)
297                 {
298                         stdout.Write (value);
299                 }
300
301                 public static void Write (char[] buffer)
302                 {
303                         stdout.Write (buffer);
304                 }
305
306                 public static void Write (decimal value)
307                 {
308                         stdout.Write (value);
309                 }
310                 
311                 public static void Write (double value)
312                 {
313                         stdout.Write (value);
314                 }
315
316                 public static void Write (int value)
317                 {
318                         stdout.Write (value);
319                 }
320
321                 public static void Write (long value)
322                 {
323                         stdout.Write (value);
324                 }
325
326                 public static void Write (object value)
327                 {
328                         stdout.Write (value);
329                 }
330
331                 public static void Write (float value)
332                 {
333                         stdout.Write (value);
334                 }
335
336                 public static void Write (string value)
337                 {
338                         stdout.Write (value);
339                 }
340
341                 [CLSCompliant (false)]
342                 public static void Write (uint value)
343                 {
344                         stdout.Write (value);
345                 }
346
347                 [CLSCompliant (false)]
348                 public static void Write (ulong value)
349                 {
350                         stdout.Write (value);
351                 }
352
353                 public static void Write (string format, object arg0)
354                 {
355                         stdout.Write (format, arg0);
356                 }
357
358                 public static void Write (string format, params object[] arg)
359                 {
360                         if (arg == null)
361                                 stdout.Write (format);
362                         else
363                                 stdout.Write (format, arg);
364                 }
365
366                 public static void Write (char[] buffer, int index, int count)
367                 {
368                         stdout.Write (buffer, index, count);
369                 }
370
371                 public static void Write (string format, object arg0, object arg1)
372                 {
373                         stdout.Write (format, arg0, arg1);
374                 }
375
376                 public static void Write (string format, object arg0, object arg1, object arg2 )
377                 {
378                         stdout.Write (format, arg0, arg1, arg2);
379                 }
380
381                 [CLSCompliant (false)]
382                 public static void Write (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
383                 {
384                         ArgIterator iter = new ArgIterator (__arglist);
385                         int argCount = iter.GetRemainingCount();
386
387                         object[] args = new object [argCount + 4];
388                         args [0] = arg0;
389                         args [1] = arg1;
390                         args [2] = arg2;
391                         args [3] = arg3;
392                         for (int i = 0; i < argCount; i++) {
393                                 TypedReference typedRef = iter.GetNextArg ();
394                                 args [i + 4] = TypedReference.ToObject (typedRef);
395                         }
396
397                         stdout.Write (String.Format (format, args));
398                 }
399
400                 public static void WriteLine ()
401                 {
402                         stdout.WriteLine ();
403                 }
404
405                 public static void WriteLine (bool value)
406                 {
407                         stdout.WriteLine (value);
408                 }
409
410                 public static void WriteLine (char value)
411                 {
412                         stdout.WriteLine (value);
413                 }
414
415                 public static void WriteLine (char[] buffer)
416                 {
417                         stdout.WriteLine (buffer);
418                 }
419
420                 public static void WriteLine (decimal value)
421                 {
422                         stdout.WriteLine (value);
423                 }
424
425                 public static void WriteLine (double value)
426                 {
427                         stdout.WriteLine (value);
428                 }
429
430                 public static void WriteLine (int value)
431                 {
432                         stdout.WriteLine (value);
433                 }
434
435                 public static void WriteLine (long value)
436                 {
437                         stdout.WriteLine (value);
438                 }
439
440                 public static void WriteLine (object value)
441                 {
442                         stdout.WriteLine (value);
443                 }
444
445                 public static void WriteLine (float value)
446                 {
447                         stdout.WriteLine (value);
448                 }
449
450                 public static void WriteLine (string value)
451                 {
452                         stdout.WriteLine (value);
453                 }
454
455                 [CLSCompliant (false)]
456                 public static void WriteLine (uint value)
457                 {
458                         stdout.WriteLine (value);
459                 }
460
461                 [CLSCompliant (false)]
462                 public static void WriteLine (ulong value)
463                 {
464                         stdout.WriteLine (value);
465                 }
466
467                 public static void WriteLine (string format, object arg0)
468                 {
469                         stdout.WriteLine (format, arg0);
470                 }
471
472                 public static void WriteLine (string format, params object[] arg)
473                 {
474                         if (arg == null)
475                                 stdout.WriteLine (format);
476                         else
477                                 stdout.WriteLine (format, arg);
478                 }
479
480                 public static void WriteLine (char[] buffer, int index, int count)
481                 {
482                         stdout.WriteLine (buffer, index, count);
483                 }
484
485                 public static void WriteLine (string format, object arg0, object arg1)
486                 {
487                         stdout.WriteLine (format, arg0, arg1);
488                 }
489
490                 public static void WriteLine (string format, object arg0, object arg1, object arg2)
491                 {
492                         stdout.WriteLine (format, arg0, arg1, arg2);
493                 }
494
495                 [CLSCompliant (false)]
496                 public static void WriteLine (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
497                 {
498                         ArgIterator iter = new ArgIterator (__arglist);
499                         int argCount = iter.GetRemainingCount();
500
501                         object[] args = new object [argCount + 4];
502                         args [0] = arg0;
503                         args [1] = arg1;
504                         args [2] = arg2;
505                         args [3] = arg3;
506                         for (int i = 0; i < argCount; i++) {
507                                 TypedReference typedRef = iter.GetNextArg ();
508                                 args [i + 4] = TypedReference.ToObject (typedRef);
509                         }
510
511                         stdout.WriteLine (String.Format (format, args));
512                 }
513
514 #if !NET_2_1
515                 public static int Read ()
516                 {
517                         if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
518                                 return ConsoleDriver.Read ();
519                         } else {
520                                 return stdin.Read ();
521                         }
522                 }
523
524                 public static string ReadLine ()
525                 {
526                         if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
527                                 return ConsoleDriver.ReadLine ();
528                         } else {
529                                 return stdin.ReadLine ();
530                         }
531                 }
532 #else
533                 public static int Read ()
534                 {
535                         return stdin.Read ();
536                 }
537
538                 public static string ReadLine ()
539                 {
540                         return stdin.ReadLine ();
541                 }
542
543 #endif
544
545 #if !NET_2_1
546                 // FIXME: Console should use these encodings when changed
547                 static Encoding inputEncoding;
548                 static Encoding outputEncoding;
549
550                 public static Encoding InputEncoding {
551                         get { return inputEncoding; }
552                         set {
553                                 inputEncoding = value;
554                                 SetupStreams (inputEncoding, outputEncoding);
555                         }
556                 }
557
558                 public static Encoding OutputEncoding {
559                         get { return outputEncoding; }
560                         set {
561                                 outputEncoding = value;
562                                 SetupStreams (inputEncoding, outputEncoding);
563                         }
564                 }
565
566                 public static ConsoleColor BackgroundColor {
567                         get { return ConsoleDriver.BackgroundColor; }
568                         set { ConsoleDriver.BackgroundColor = value; }
569                 }
570
571                 public static int BufferHeight {
572                         get { return ConsoleDriver.BufferHeight; }
573                         [MonoLimitation ("Implemented only on Windows")]
574                         set { ConsoleDriver.BufferHeight = value; }
575                 }
576
577                 public static int BufferWidth {
578                         get { return ConsoleDriver.BufferWidth; }
579                         [MonoLimitation ("Implemented only on Windows")]
580                         set { ConsoleDriver.BufferWidth = value; }
581                 }
582
583                 [MonoLimitation ("Implemented only on Windows")]
584                 public static bool CapsLock {
585                         get { return ConsoleDriver.CapsLock; }
586                 }
587
588                 public static int CursorLeft {
589                         get { return ConsoleDriver.CursorLeft; }
590                         set { ConsoleDriver.CursorLeft = value; }
591                 }
592
593                 public static int CursorTop {
594                         get { return ConsoleDriver.CursorTop; }
595                         set { ConsoleDriver.CursorTop = value; }
596                 }
597
598                 public static int CursorSize {
599                         get { return ConsoleDriver.CursorSize; }
600                         set { ConsoleDriver.CursorSize = value; }
601                 }
602
603                 public static bool CursorVisible {
604                         get { return ConsoleDriver.CursorVisible; }
605                         set { ConsoleDriver.CursorVisible = value; }
606                 }
607
608                 public static ConsoleColor ForegroundColor {
609                         get { return ConsoleDriver.ForegroundColor; }
610                         set { ConsoleDriver.ForegroundColor = value; }
611                 }
612
613                 public static bool KeyAvailable {
614                         get { return ConsoleDriver.KeyAvailable; }
615                 }
616
617                 public static int LargestWindowHeight {
618                         get { return ConsoleDriver.LargestWindowHeight; }
619                 }
620
621                 public static int LargestWindowWidth {
622                         get { return ConsoleDriver.LargestWindowWidth; }
623                 }
624
625                 [MonoLimitation ("Only works on windows")]
626                 public static bool NumberLock {
627                         get { return ConsoleDriver.NumberLock; }
628                 }
629
630                 public static string Title {
631                         get { return ConsoleDriver.Title; }
632                         set { ConsoleDriver.Title = value; }
633                 }
634
635                 public static bool TreatControlCAsInput {
636                         get { return ConsoleDriver.TreatControlCAsInput; }
637                         set { ConsoleDriver.TreatControlCAsInput = value; }
638                 }
639
640                 [MonoLimitation ("Only works on windows")]
641                 public static int WindowHeight {
642                         get { return ConsoleDriver.WindowHeight; }
643                         set { ConsoleDriver.WindowHeight = value; }
644                 }
645
646                 [MonoLimitation ("Only works on windows")]
647                 public static int WindowLeft {
648                         get { return ConsoleDriver.WindowLeft; }
649                         set { ConsoleDriver.WindowLeft = value; }
650                 }
651
652                 [MonoLimitation ("Only works on windows")]
653                 public static int WindowTop {
654                         get { return ConsoleDriver.WindowTop; }
655                         set { ConsoleDriver.WindowTop = value; }
656                 }
657
658                 [MonoLimitation ("Only works on windows")]
659                 public static int WindowWidth {
660                         get { return ConsoleDriver.WindowWidth; }
661                         set { ConsoleDriver.WindowWidth = value; }
662                 }
663
664                 public static bool IsErrorRedirected {
665                         get {
666                                 return ConsoleDriver.IsErrorRedirected;
667                         }
668                 }
669
670                 public static bool IsOutputRedirected {
671                         get {
672                                 return ConsoleDriver.IsOutputRedirected;
673                         }
674                 }
675
676                 public static bool IsInputRedirected {
677                         get {
678                                 return ConsoleDriver.IsInputRedirected;
679                         }
680                 }
681
682                 public static void Beep ()
683                 {
684                         Beep (1000, 500);
685                 }
686
687                 public static void Beep (int frequency, int duration)
688                 {
689                         if (frequency < 37 || frequency > 32767)
690                                 throw new ArgumentOutOfRangeException ("frequency");
691
692                         if (duration <= 0)
693                                 throw new ArgumentOutOfRangeException ("duration");
694
695                         ConsoleDriver.Beep (frequency, duration);
696                 }
697
698                 public static void Clear ()
699                 {
700                         ConsoleDriver.Clear ();
701                 }
702
703                 [MonoLimitation ("Implemented only on Windows")]
704                 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
705                                                 int targetLeft, int targetTop)
706                 {
707                         ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop);
708                 }
709
710                 [MonoLimitation ("Implemented only on Windows")]
711                 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
712                                                 int targetLeft, int targetTop, Char sourceChar,
713                                                 ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
714                 {
715                         ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop,
716                                                         sourceChar, sourceForeColor, sourceBackColor);
717                 }
718
719                 public static ConsoleKeyInfo ReadKey ()
720                 {
721                         return ReadKey (false);
722                 }
723
724                 public static ConsoleKeyInfo ReadKey (bool intercept)
725                 {
726                         return ConsoleDriver.ReadKey (intercept);
727                 }
728
729                 public static void ResetColor ()
730                 {
731                         ConsoleDriver.ResetColor ();
732                 }
733
734                 [MonoLimitation ("Only works on windows")]
735                 public static void SetBufferSize (int width, int height)
736                 {
737                         ConsoleDriver.SetBufferSize (width, height);
738                 }
739
740                 public static void SetCursorPosition (int left, int top)
741                 {
742                         ConsoleDriver.SetCursorPosition (left, top);
743                 }
744
745                 public static void SetWindowPosition (int left, int top)
746                 {
747                         ConsoleDriver.SetWindowPosition (left, top);
748                 }
749
750                 public static void SetWindowSize (int width, int height)
751                 {
752                         ConsoleDriver.SetWindowSize (width, height);
753                 }
754
755                 static ConsoleCancelEventHandler cancel_event;
756                 public static event ConsoleCancelEventHandler CancelKeyPress {
757                         add {
758                                 if (ConsoleDriver.Initialized == false)
759                                         ConsoleDriver.Init ();
760
761                                 cancel_event += value;
762
763                                 if (Environment.IsRunningOnWindows && !WindowsConsole.ctrlHandlerAdded)
764                                         WindowsConsole.AddCtrlHandler();
765                         }
766                         remove {
767                                 if (ConsoleDriver.Initialized == false)
768                                         ConsoleDriver.Init ();
769
770                                 cancel_event -= value;
771
772                                 if (cancel_event == null && Environment.IsRunningOnWindows)
773                                 {
774                                         // Need to remove our hook if there's nothing left in the event
775                                         if (WindowsConsole.ctrlHandlerAdded)
776                                                 WindowsConsole.RemoveCtrlHandler();
777                                 }
778                         }
779                 }
780
781                 delegate void InternalCancelHandler ();
782                 
783 #pragma warning disable 414
784                 //
785                 // Used by console-io.c
786                 //
787                 static readonly InternalCancelHandler cancel_handler = new InternalCancelHandler (DoConsoleCancelEvent);
788 #pragma warning restore 414             
789
790                 internal static void DoConsoleCancelEvent ()
791                 {
792                         bool exit = true;
793                         if (cancel_event != null) {
794                                 ConsoleCancelEventArgs args = new ConsoleCancelEventArgs (ConsoleSpecialKey.ControlC);
795                                 Delegate [] delegates = cancel_event.GetInvocationList ();
796                                 foreach (ConsoleCancelEventHandler d in delegates){
797                                         try {
798                                                 // Sender is always null here.
799                                                 d (null, args);
800                                         } catch {} // Ignore any exception.
801                                 }
802                                 exit = !args.Cancel;
803                         }
804
805                         if (exit)
806                                 Environment.Exit (58);
807                 }
808 #endif
809         }
810 }
811