forked from PowerShell/PowerShell
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConsoleControl.cs
More file actions
3627 lines (3159 loc) · 145 KB
/
Copy pathConsoleControl.cs
File metadata and controls
3627 lines (3159 loc) · 145 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#if !UNIX
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
// Implementation notes: In the functions that take ConsoleHandle parameters, we only assert that the handle is valid and not
// closed, as opposed to doing a check and throwing an exception. This is because the win32 APIs that those functions wrap will
// fail on invalid/closed handles, and the check for API failure will throw the exception.
//
// On the use of DangerousGetHandle: If the handle has been invalidated, then the API we pass it to will return an error. These
// handles should not be exposed to recycling attacks (because they are not exposed at all), but if they were, the worse they
// could do is diddle with the console buffer.
#pragma warning disable 1634, 1691
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Internal;
using System.ComponentModel;
using System.Collections.Generic;
using System.Globalization;
using System.Diagnostics;
using Microsoft.Win32.SafeHandles;
using ConsoleHandle = Microsoft.Win32.SafeHandles.SafeFileHandle;
using WORD = System.UInt16;
using ULONG = System.UInt32;
using DWORD = System.UInt32;
using NakedWin32Handle = System.IntPtr;
using HWND = System.IntPtr;
using HDC = System.IntPtr;
#endif
using System.Diagnostics.CodeAnalysis;
using Dbg = System.Management.Automation.Diagnostics;
namespace Microsoft.PowerShell
{
/// <summary>
///
/// Class ConsoleControl is used to wrap the various win32 console APIs 1:1 (i.e. at a low level, without attempting to be a
/// "true" object-oriented library.
///
/// </summary>
internal static class ConsoleControl
{
#if !UNIX
#region structs
internal enum InputRecordEventTypes : ushort
{
// from wincon.h. These look like bit flags, but of course they could not really be used that way, since it would
// not make sense to have more than one of the INPUT_RECORD union members "in effect" at any one time.
KEY_EVENT = 0x0001,
MOUSE_EVENT = 0x0002,
WINDOW_BUFFER_SIZE_EVENT = 0x0004,
MENU_EVENT = 0x0008,
FOCUS_EVENT = 0x0010
}
[StructLayout(LayoutKind.Sequential)]
internal struct INPUT_RECORD
{
internal WORD EventType;
internal KEY_EVENT_RECORD KeyEvent;
}
[Flags]
internal enum ControlKeyStates : uint
{
// From wincon.h.
RIGHT_ALT_PRESSED = 0x0001, // the right alt key is pressed.
LEFT_ALT_PRESSED = 0x0002, // the left alt key is pressed.
RIGHT_CTRL_PRESSED = 0x0004, // the right ctrl key is pressed.
LEFT_CTRL_PRESSED = 0x0008, // the left ctrl key is pressed.
SHIFT_PRESSED = 0x0010, // the shift key is pressed.
NUMLOCK_ON = 0x0020, // the numlock light is on.
SCROLLLOCK_ON = 0x0040, // the scrolllock light is on.
CAPSLOCK_ON = 0x0080, // the capslock light is on.
ENHANCED_KEY = 0x0100 // the key is enhanced.
}
// LayoutKind must be Explicit
[StructLayout(LayoutKind.Sequential)]
internal struct KEY_EVENT_RECORD
{
internal bool KeyDown;
internal WORD RepeatCount;
internal WORD VirtualKeyCode;
internal WORD VirtualScanCode;
internal char UnicodeChar;
internal DWORD ControlKeyState;
}
[StructLayout(LayoutKind.Sequential)]
internal struct COORD
{
internal short X;
internal short Y;
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "{0},{1}", X, Y);
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct CONSOLE_READCONSOLE_CONTROL
{
// from public/internal/windows/inc/winconp.h
internal ULONG nLength;
internal ULONG nInitialChars;
internal ULONG dwCtrlWakeupMask;
internal /* out */ ULONG dwControlKeyState;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct CONSOLE_FONT_INFO_EX
{
internal int cbSize;
internal int nFont;
internal short FontWidth;
internal short FontHeight;
internal int FontFamily;
internal int FontWeight;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
internal string FontFace;
}
[StructLayout(LayoutKind.Sequential)]
internal struct CHAR_INFO
{
internal ushort UnicodeChar;
internal WORD Attributes;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SMALL_RECT
{
internal short Left;
internal short Top;
internal short Right;
internal short Bottom;
public override string ToString()
{
return String.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", Left, Top, Right, Bottom);
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct CONSOLE_SCREEN_BUFFER_INFO
{
internal COORD BufferSize;
internal COORD CursorPosition;
internal WORD Attributes;
internal SMALL_RECT WindowRect;
internal COORD MaxWindowSize;
// NTRAID#Windows Out Of Band Releases-938428-2006/07/17-jwh
// Bring the total size of the struct to 24 bytes.
internal DWORD Padding;
}
[StructLayout(LayoutKind.Sequential)]
internal struct CONSOLE_CURSOR_INFO
{
internal DWORD Size;
internal bool Visible;
public override string ToString()
{
return String.Format(CultureInfo.InvariantCulture, "Size: {0}, Visible: {1}", Size, Visible);
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct FONTSIGNATURE
{
//From public\sdk\inc\wingdi.h
// fsUsb*: A 128-bit Unicode subset bitfield (USB) identifying up to 126 Unicode subranges
internal DWORD fsUsb0;
internal DWORD fsUsb1;
internal DWORD fsUsb2;
internal DWORD fsUsb3;
// fsCsb*: A 64-bit, code-page bitfield (CPB) that identifies a specific character set or code page.
internal DWORD fsCsb0;
internal DWORD fsCsb1;
}
[StructLayout(LayoutKind.Sequential)]
internal struct CHARSETINFO
{
//From public\sdk\inc\wingdi.h
internal uint ciCharset; // Character set value.
internal uint ciACP; // ANSI code-page identifier.
internal FONTSIGNATURE fs;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct TEXTMETRIC
{
//From public\sdk\inc\wingdi.h
public int tmHeight;
public int tmAscent;
public int tmDescent;
public int tmInternalLeading;
public int tmExternalLeading;
public int tmAveCharWidth;
public int tmMaxCharWidth;
public int tmWeight;
public int tmOverhang;
public int tmDigitizedAspectX;
public int tmDigitizedAspectY;
public char tmFirstChar;
public char tmLastChar;
public char tmDefaultChar;
public char tmBreakChar;
public byte tmItalic;
public byte tmUnderlined;
public byte tmStruckOut;
public byte tmPitchAndFamily;
public byte tmCharSet;
}
#region SentInput Data Structures
[StructLayout(LayoutKind.Sequential)]
internal struct INPUT
{
internal DWORD Type;
internal MouseKeyboardHardwareInput Data;
}
[StructLayout(LayoutKind.Explicit)]
internal struct MouseKeyboardHardwareInput
{
[FieldOffset(0)]
internal MouseInput Mouse;
[FieldOffset(0)]
internal KeyboardInput Keyboard;
[FieldOffset(0)]
internal HardwareInput Hardware;
}
[StructLayout(LayoutKind.Sequential)]
internal struct MouseInput
{
/// <summary>
/// The absolute position of the mouse, or the amount of motion since the last mouse event was generated, depending on the value of the dwFlags member.
/// Absolute data is specified as the x coordinate of the mouse; relative data is specified as the number of pixels moved.
/// </summary>
internal Int32 X;
/// <summary>
/// The absolute position of the mouse, or the amount of motion since the last mouse event was generated, depending on the value of the dwFlags member.
/// Absolute data is specified as the y coordinate of the mouse; relative data is specified as the number of pixels moved.
/// </summary>
internal Int32 Y;
/// <summary>
/// If dwFlags contains MOUSEEVENTF_WHEEL, then mouseData specifies the amount of wheel movement. A positive value indicates that the wheel was rotated forward, away from the user;
/// a negative value indicates that the wheel was rotated backward, toward the user. One wheel click is defined as WHEEL_DELTA, which is 120.
/// </summary>
internal DWORD MouseData;
/// <summary>
/// A set of bit flags that specify various aspects of mouse motion and button clicks.
/// See (http://msdn.microsoft.com/en-us/library/ms646273(VS.85).aspx)
/// </summary>
internal DWORD Flags;
/// <summary>
/// The time stamp for the event, in milliseconds. If this parameter is 0, the system will provide its own time stamp.
/// </summary>
internal DWORD Time;
/// <summary>
/// An additional value associated with the mouse event. An application calls GetMessageExtraInfo to obtain this extra information
/// </summary>
internal IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
internal struct KeyboardInput
{
/// <summary>
/// A virtual-key code. The code must be a value in the range 1 to 254.
/// If the dwFlags member specifies KEYEVENTF_UNICODE, wVk must be 0.
/// </summary>
internal WORD Vk;
/// <summary>
/// A hardware scan code for the key. If dwFlags specifies KEYEVENTF_UNICODE,
/// wScan specifies a Unicode character which is to be sent to the foreground application.
/// </summary>
internal WORD Scan;
/// <summary>
/// Specifies various aspects of a keystroke.
/// This member can be certain combinations of the following values.
/// </summary>
internal DWORD Flags;
/// <summary>
/// The time stamp for the event, in milliseconds.
/// If this parameter is zero, the system will provide its own time stamp.
/// </summary>
internal DWORD Time;
/// <summary>
/// An additional value associated with the keystroke.
/// Use the GetMessageExtraInfo function to obtain this information.
/// </summary>
internal IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
internal struct HardwareInput
{
/// <summary>
/// The message generated by the input hardware.
/// </summary>
internal DWORD Msg;
/// <summary>
/// The low-order word of the lParam parameter for uMsg.
/// </summary>
internal WORD ParamL;
/// <summary>
/// The high-order word of the lParam parameter for uMsg.
/// </summary>
internal WORD ParamH;
}
internal enum VirtualKeyCode : ushort
{
/// <summary>
/// LEFT ARROW key
/// </summary>
Left = 0x25,
/// <summary>
/// ENTER key
/// </summary>
Return = 0x0D,
}
/// <summary>
/// Specify the type of the input
/// </summary>
internal enum InputType : uint
{
/// <summary>
/// INPUT_MOUSE = 0x00
/// </summary>
Mouse = 0,
/// <summary>
/// INPUT_KEYBOARD = 0x01
/// </summary>
Keyboard = 1,
/// <summary>
/// INPUT_HARDWARE = 0x02
/// </summary>
Hardware = 2,
}
internal enum KeyboardFlag : uint
{
/// <summary>
/// If specified, the scan code was preceded by a prefix byte that has the value 0xE0 (224).
/// </summary>
ExtendedKey = 0x0001,
/// <summary>
/// If specified, the key is being released. If not specified, the key is being pressed.
/// </summary>
KeyUp = 0x0002,
/// <summary>
/// If specified, wScan identifies the key and wVk is ignored.
/// </summary>
Unicode = 0x0004,
/// <summary>
/// If specified, the system synthesizes a VK_PACKET keystroke. The wVk parameter must be zero.
/// This flag can only be combined with the KEYEVENTF_KEYUP flag.
/// </summary>
ScanCode = 0x0008
}
#endregion SentInput Data Structures
#endregion structs
#region Window Visibility
[DllImport(PinvokeDllNames.GetConsoleWindowDllName)]
internal static extern IntPtr GetConsoleWindow();
internal const int SW_HIDE = 0;
internal const int SW_SHOWNORMAL = 1;
internal const int SW_NORMAL = 1;
internal const int SW_SHOWMINIMIZED = 2;
internal const int SW_SHOWMAXIMIZED = 3;
internal const int SW_MAXIMIZE = 3;
internal const int SW_SHOWNOACTIVATE = 4;
internal const int SW_SHOW = 5;
internal const int SW_MINIMIZE = 6;
internal const int SW_SHOWMINNOACTIVE = 7;
internal const int SW_SHOWNA = 8;
internal const int SW_RESTORE = 9;
internal const int SW_SHOWDEFAULT = 10;
internal const int SW_FORCEMINIMIZE = 11;
internal const int SW_MAX = 11;
#if !CORECLR // ProcessWindowStyle does Not exist on CoreCLR
/// <summary>
/// Code to control the display properties of the a window...
/// </summary>
/// <param name="hWnd">The window to show...</param>
/// <param name="nCmdShow">The command to do</param>
/// <returns>true it it was successful</returns>
[DllImport("user32.dll")]
internal static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
internal static void SetConsoleMode(ProcessWindowStyle style)
{
IntPtr hwnd = GetConsoleWindow();
Dbg.Assert(hwnd != IntPtr.Zero, "Console handle should never be zero");
switch (style)
{
case ProcessWindowStyle.Hidden:
ShowWindow(hwnd, SW_HIDE);
break;
case ProcessWindowStyle.Maximized:
ShowWindow(hwnd, SW_MAXIMIZE);
break;
case ProcessWindowStyle.Minimized:
ShowWindow(hwnd, SW_MINIMIZE);
break;
case ProcessWindowStyle.Normal:
ShowWindow(hwnd, SW_NORMAL);
break;
}
}
#endif
#endregion
#region Input break handler (Ctrl-C, Ctrl-Break)
/// <summary>
///
/// Types of control ConsoleBreakSignals received by break Win32Handler delegates
///
/// </summary>
internal enum ConsoleBreakSignal : uint
{
// These correspond to the CRTL_XXX_EVENT #defines in public/sdk/inc/wincon.h
CtrlC = 0,
CtrlBreak = 1,
Close = 2,
Logoff = 5,
// This only gets received by services
Shutdown = 6,
// None is not really a signal -- it's used to indicate that no signal exists.
None = 0xFF
}
// NOTE: this delegate will be executed in its own thread
internal delegate bool BreakHandler(ConsoleBreakSignal ConsoleBreakSignal);
/// <summary>
/// Set the console's break handler
/// </summary>
/// <param name="handlerDelegate"></param>
/// <exception cref="HostException">
/// If Win32's SetConsoleCtrlHandler fails
/// </exception>
internal static void AddBreakHandler(BreakHandler handlerDelegate)
{
bool result = NativeMethods.SetConsoleCtrlHandler(handlerDelegate, true);
if (result == false)
{
int err = Marshal.GetLastWin32Error();
HostException e = CreateHostException(err, "AddBreakHandler",
ErrorCategory.ResourceUnavailable, ConsoleControlStrings.AddBreakHandlerExceptionMessage);
throw e;
}
}
/// <summary>
/// Set the console's break handler to null
/// </summary>
/// <exception cref="HostException">
/// If Win32's SetConsoleCtrlHandler fails
/// </exception>
internal static void RemoveBreakHandler()
{
bool result = NativeMethods.SetConsoleCtrlHandler(null, false);
if (result == false)
{
int err = Marshal.GetLastWin32Error();
HostException e = CreateHostException(err, "RemoveBreakHandler",
ErrorCategory.ResourceUnavailable, ConsoleControlStrings.RemoveBreakHandlerExceptionTemplate);
throw e;
}
}
#endregion
#region Win32Handles
private static readonly Lazy<ConsoleHandle> _keyboardInputHandle = new Lazy<SafeFileHandle>(() =>
{
var handle = NativeMethods.CreateFile(
"CONIN$",
(UInt32)
(NativeMethods.AccessQualifiers.GenericRead | NativeMethods.AccessQualifiers.GenericWrite),
(UInt32)NativeMethods.ShareModes.ShareRead,
(IntPtr)0,
(UInt32)NativeMethods.CreationDisposition.OpenExisting,
0,
(IntPtr)0);
if (handle == NativeMethods.INVALID_HANDLE_VALUE)
{
int err = Marshal.GetLastWin32Error();
HostException e = CreateHostException(err, "RetreiveInputConsoleHandle",
ErrorCategory.ResourceUnavailable,
ConsoleControlStrings.GetInputModeExceptionTemplate);
throw e;
}
return new ConsoleHandle(handle, true);
}
);
/// <summary>
/// Returns a ConsoleHandle to the console (keyboard device)
/// </summary>
internal static ConsoleHandle GetConioDeviceHandle()
{
return _keyboardInputHandle.Value;
}
private static readonly Lazy<ConsoleHandle> _outputHandle = new Lazy<SafeFileHandle>(() =>
{
// We use CreateFile here instead of GetStdWin32Handle, as GetStdWin32Handle will return redirected handles
var handle = NativeMethods.CreateFile(
"CONOUT$",
(UInt32)(NativeMethods.AccessQualifiers.GenericRead | NativeMethods.AccessQualifiers.GenericWrite),
(UInt32)NativeMethods.ShareModes.ShareWrite,
(IntPtr)0,
(UInt32)NativeMethods.CreationDisposition.OpenExisting,
0,
(IntPtr)0);
if (handle == NativeMethods.INVALID_HANDLE_VALUE)
{
int err = Marshal.GetLastWin32Error();
HostException e = CreateHostException(err, "RetreiveActiveScreenBufferConsoleHandle",
ErrorCategory.ResourceUnavailable, ConsoleControlStrings.GetActiveScreenBufferHandleExceptionTemplate);
throw e;
}
return new ConsoleHandle(handle, true);
}
);
/// <summary>
/// Returns a ConsoleHandle to the active screen buffer, even if that output has been redirected.
/// </summary>
/// <returns></returns>
/// <exception cref="HostException">
/// If Win32's CreateFile fails
/// </exception>
internal static ConsoleHandle GetActiveScreenBufferHandle()
{
return _outputHandle.Value;
}
#endregion
#region Mode
/// <summary>
///
/// flags used by ConsoleControl.GetMode and ConsoleControl.SetMode
///
/// </summary>
[Flags]
internal enum ConsoleModes : uint
{
// These values from wincon.h
// input modes
ProcessedInput = 0x001,
LineInput = 0x002,
EchoInput = 0x004,
WindowInput = 0x008,
MouseInput = 0x010,
Insert = 0x020,
QuickEdit = 0x040,
Extended = 0x080,
AutoPosition = 0x100,
// output modes
ProcessedOutput = 0x001, // yes, I know they are the same values as some flags defined above.
WrapEndOfLine = 0x002,
VirtualTerminal = 0x004,
// Error getting console mode
Unknown = 0xffffffff,
}
/// <summary>
///
/// Returns a mask of ConsoleModes flags describing the current modality of the console
///
/// </summary>
/// <exception cref="HostException">
/// If Win32's GetConsoleMode fails
/// </exception>
internal static ConsoleModes GetMode(ConsoleHandle consoleHandle)
{
Dbg.Assert(!consoleHandle.IsInvalid, "consoleHandle is not valid");
Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed");
UInt32 m = 0;
bool result = NativeMethods.GetConsoleMode(consoleHandle.DangerousGetHandle(), out m);
if (result == false)
{
int err = Marshal.GetLastWin32Error();
HostException e = CreateHostException(err, "GetConsoleMode",
ErrorCategory.ResourceUnavailable, ConsoleControlStrings.GetModeExceptionTemplate);
throw e;
}
return (ConsoleModes)m;
}
/// <summary>
///
/// Sets the current mode of the console device
///
/// </summary>
/// <param name="consoleHandle">
///
/// Handle to the console device returned by GetInputHandle
///
/// </param>
/// <param name="mode">
///
/// Mask of mode flags
///
/// </param>
/// <exception cref="HostException">
///
/// If Win32's SetConsoleMode fails
///
/// </exception>
internal static void SetMode(ConsoleHandle consoleHandle, ConsoleModes mode)
{
Dbg.Assert(!consoleHandle.IsInvalid, "consoleHandle is not valid");
Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed");
bool result = NativeMethods.SetConsoleMode(consoleHandle.DangerousGetHandle(), (DWORD)mode);
if (result == false)
{
int err = Marshal.GetLastWin32Error();
HostException e = CreateHostException(err, "SetConsoleMode",
ErrorCategory.ResourceUnavailable, ConsoleControlStrings.SetModeExceptionTemplate);
throw e;
}
}
#endregion
#region Input
/// <summary>
///
/// Reads input from the console device according to the mode in effect (see GetMode, SetMode)
///
/// </summary>
/// <param name="consoleHandle"></param>
///
/// Handle to the console device returned by GetInputHandle
///
/// <param name="initialContent">
///
/// Initial contents of the edit buffer, if any. charactersToRead should be at least as large as the length of this string.
///
/// </param>
/// <param name="charactersToRead">
///
/// Number of characters to read from the device.
///
/// </param>
/// <param name="endOnTab">
///
/// true to allow the user to terminate input by hitting the tab or shift-tab key, in addition to the enter key
///
/// </param>
/// <param name="keyState">
///
/// bit mask indicating the state of the control/shift keys at the point input was terminated.
///
/// </param>
/// <returns></returns>
/// <exception cref="HostException">
///
/// If Win32's ReadConsole fails
///
/// </exception>
internal static string ReadConsole(ConsoleHandle consoleHandle, string initialContent,
int charactersToRead, bool endOnTab, out uint keyState)
{
Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid");
Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed");
Dbg.Assert(initialContent != null, "if no initial content is desired, pass String.Empty");
keyState = 0;
CONSOLE_READCONSOLE_CONTROL control = new CONSOLE_READCONSOLE_CONTROL();
control.nLength = (ULONG)Marshal.SizeOf(control);
control.nInitialChars = (ULONG)initialContent.Length;
control.dwControlKeyState = 0;
if (endOnTab)
{
const int TAB = 0x9;
control.dwCtrlWakeupMask = (1 << TAB);
}
DWORD charsReadUnused = 0;
StringBuilder buffer = new StringBuilder(initialContent, charactersToRead);
bool result =
NativeMethods.ReadConsole(
consoleHandle.DangerousGetHandle(),
buffer,
(DWORD)charactersToRead,
out charsReadUnused,
ref control);
keyState = control.dwControlKeyState;
if (result == false)
{
int err = Marshal.GetLastWin32Error();
HostException e = CreateHostException(err, "ReadConsole",
ErrorCategory.ReadError, ConsoleControlStrings.ReadConsoleExceptionTemplate);
throw e;
}
if (charsReadUnused > (uint)buffer.Length)
charsReadUnused = (uint)buffer.Length;
return buffer.ToString(0, (int)charsReadUnused);
}
/// <summary>
/// Wraps Win32 ReadConsoleInput.
/// Returns the number of records read in buffer.
/// </summary>
/// <param name="consoleHandle">
///
/// handle for the console where input is read
///
/// </param>
/// <param name="buffer">
///
/// array where data read are stored
///
/// </param>
/// <returns>
///
/// actual number of input records read
///
/// </returns>
/// <exception cref="HostException">
/// If Win32's ReadConsoleInput fails
/// </exception>
internal static int ReadConsoleInput(ConsoleHandle consoleHandle, ref INPUT_RECORD[] buffer)
{
Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid");
Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed");
DWORD recordsRead = 0;
bool result =
NativeMethods.ReadConsoleInput(
consoleHandle.DangerousGetHandle(),
buffer,
(DWORD)buffer.Length,
out recordsRead);
if (result == false)
{
int err = Marshal.GetLastWin32Error();
HostException e = CreateHostException(err, "ReadConsoleInput",
ErrorCategory.ReadError, ConsoleControlStrings.ReadConsoleInputExceptionTemplate);
throw e;
}
return (int)recordsRead;
}
/// <summary>
/// Wraps Win32 PeekConsoleInput
/// </summary>
/// <param name="consoleHandle">
///
/// handle for the console where input is peeked
///
/// </param>
/// <param name="buffer">
///
/// array where data read are stored
///
/// </param>
/// <returns>
///
/// actual number of input records peeked
///
/// </returns>
/// <exception cref="HostException">
/// If Win32's PeekConsoleInput fails
/// </exception>
internal static int PeekConsoleInput
(
ConsoleHandle consoleHandle,
ref INPUT_RECORD[] buffer
)
{
Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid");
Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed");
DWORD recordsRead;
bool result =
NativeMethods.PeekConsoleInput(
consoleHandle.DangerousGetHandle(),
buffer,
(DWORD)buffer.Length,
out recordsRead);
if (result == false)
{
int err = Marshal.GetLastWin32Error();
HostException e = CreateHostException(err, "PeekConsoleInput",
ErrorCategory.ReadError, ConsoleControlStrings.PeekConsoleInputExceptionTemplate);
throw e;
}
return (int)recordsRead;
}
/// <summary>
/// Wraps Win32 GetNumberOfConsoleInputEvents
/// </summary>
/// <param name="consoleHandle">
///
/// handle for the console where the number of console input events is obtained
///
/// </param>
/// <returns>
///
/// number of console input events
///
/// </returns>
/// <exception cref="HostException">
/// If Win32's GetNumberOfConsoleInputEvents fails
/// </exception>
internal static int GetNumberOfConsoleInputEvents(ConsoleHandle consoleHandle)
{
Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid");
Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed");
DWORD numEvents;
bool result = NativeMethods.GetNumberOfConsoleInputEvents(consoleHandle.DangerousGetHandle(), out numEvents);
if (result == false)
{
int err = Marshal.GetLastWin32Error();
HostException e = CreateHostException(err, "GetNumberOfConsoleInputEvents",
ErrorCategory.ReadError, ConsoleControlStrings.GetNumberOfConsoleInputEventsExceptionTemplate);
throw e;
}
return (int)numEvents;
}
/// <summary>
/// Wraps Win32 FlushConsoleInputBuffer
/// </summary>
/// <param name="consoleHandle">
///
/// handle for the console where the input buffer is flushed
///
/// </param>
/// <exception cref="HostException">
/// If Win32's FlushConsoleInputBuffer fails
/// </exception>
internal static void FlushConsoleInputBuffer(ConsoleHandle consoleHandle)
{
Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid");
Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed");
bool result = false;
NakedWin32Handle h = consoleHandle.DangerousGetHandle();
result = NativeMethods.FlushConsoleInputBuffer(h);
if (result == false)
{
int err = Marshal.GetLastWin32Error();
HostException e = CreateHostException(err, "FlushConsoleInputBuffer",
ErrorCategory.ReadError, ConsoleControlStrings.FlushConsoleInputBufferExceptionTemplate);
throw e;
}
}
#endregion Input
#region Buffer
/// <summary>
/// Wraps Win32 GetConsoleScreenBufferInfo
/// Returns Console Screen Buffer Info
/// </summary>
/// <param name="consoleHandle">
///
/// Handle for the console where the screen buffer info is obtained
///
/// </param>
/// <returns>
///
/// info about the screen buffer. See the definition of CONSOLE_SCREEN_BUFFER_INFO
///
/// </returns>
/// <exception cref="HostException">
/// If Win32's GetConsoleScreenBufferInfo fails
/// </exception>
internal static CONSOLE_SCREEN_BUFFER_INFO GetConsoleScreenBufferInfo(ConsoleHandle consoleHandle)
{