private static readonly int BUF_LEN = 8192 + 8; //8 bytes for the leading USN #endregion Fields #region Methods public static bool Build_Volume_Mapping(SafeFileHandle roothandle, Win32Api.USN_JOURNAL_DATA currentUsnState, Action<Win32Api.UsnEntry> func) { Debug.WriteLine("Starting Build_Volume_Mapping"); DateTime startTime = DateTime.Now; Win32Api.MFT_ENUM_DATA med; med.StartFileReferenceNumber = 0; med.LowUsn = 0; med.HighUsn = currentUsnState.NextUsn; using(var med_struct = new StructWrapper(med)) using(var rawdata = new Raw_Array_Wrapper(BUF_LEN)) { uint outBytesReturned = 0; while(Win32Api.DeviceIoControl( roothandle.DangerousGetHandle(), Win32Api.FSCTL_ENUM_USN_DATA, med_struct.Ptr, med_struct.Size, rawdata.Ptr, rawdata.Size, out outBytesReturned, IntPtr.Zero)) { outBytesReturned = outBytesReturned - sizeof(Int64); IntPtr pUsnRecord = System.IntPtr.Add(rawdata.Ptr, sizeof(Int64));//need to skip 8 bytes because the first 8 bytes are to a usn number, which isnt in the structure while(outBytesReturned > 60) { var usnEntry = new Win32Api.UsnEntry(pUsnRecord); pUsnRecord = System.IntPtr.Add(pUsnRecord, (int)usnEntry.RecordLength); func(usnEntry); if(usnEntry.RecordLength > outBytesReturned) outBytesReturned = 0;// prevent overflow else outBytesReturned -= usnEntry.RecordLength; } Marshal.WriteInt64(med_struct.Ptr, Marshal.ReadInt64(rawdata.Ptr, 0));//read the usn that we skipped and place it into the nextusn } var possiblerror = Marshal.GetLastWin32Error(); if(possiblerror < 0) throw new Win32Exception(possiblerror); } Debug.WriteLine("Time took: " + (DateTime.Now - startTime).TotalMilliseconds + "ms"); return true; }
public static int Read(SafeFileHandle handle, byte[] buffer, int offset, int count) { #if __MonoCS__ int r; fixed(byte *p = buffer) { do { r = (int) Syscall.read (handle.DangerousGetHandle().ToInt32(), p, (ulong) count); } while (UnixMarshal.ShouldRetrySyscall ((int) r)); if(r == -1) { int errno = Marshal.GetLastWin32Error(); if (errno == EAGAIN) { return 0; } throw new Win32Exception(); } return r; } #else return 0; #endif }
public static long GetDiskSize(SafeFileHandle Handle) { if (Handle.IsInvalid || Handle.IsClosed) throw new Exception("Native.GetDiskSize: Invalid handle specified. It is closed or invalid."); long size = 0; uint returnedBytes; if (DeviceIoControl(Handle.DangerousGetHandle(), (uint)IOCTL_CONTROL_CODE_CONSTANTS.IOCTL_DISK_GET_LENGTH_INFO, IntPtr.Zero, 0, ref size, 8, out returnedBytes, IntPtr.Zero)) return size; Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); return 0; }
private void SetCompletionPort(SafeFileHandle completionPortHandle) { int length = Marshal.SizeOf(typeof(NativeMethods.JobObjectAssociateCompletionPort)); IntPtr completionPortPtr = IntPtr.Zero; try { var completionPort = new NativeMethods.JobObjectAssociateCompletionPort { CompletionKey = IntPtr.Zero, CompletionPortHandle = completionPortHandle.DangerousGetHandle(), }; completionPortPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(completionPort, completionPortPtr, false); if (!NativeMethods.SetInformationJobObject(handle, NativeMethods.JobObjectInfoClass.AssociateCompletionPortInformation, completionPortPtr, length)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } finally { if (completionPortPtr != IntPtr.Zero) Marshal.FreeHGlobal(completionPortPtr); } }
/// <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) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); CONSOLE_SCREEN_BUFFER_INFO bufferInfo; bool result = NativeMethods.GetConsoleScreenBufferInfo(consoleHandle.DangerousGetHandle(), out bufferInfo); if (result == false) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "GetConsoleScreenBufferInfo", ErrorCategory.ResourceUnavailable, ConsoleControlStrings.GetConsoleScreenBufferInfoExceptionTemplate); throw e; } return bufferInfo; }
/// <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> /// /// 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 SetConsoleCursorInfo /// </summary> /// <param name="consoleHandle"> /// /// handle for the console where cursor info is set /// /// </param> /// <param name="cursorInfo"> /// /// cursor info to set the cursor /// /// </param> /// <exception cref="HostException"> /// If Win32's SetConsoleCursorInfo fails /// </exception> internal static void SetConsoleCursorInfo(ConsoleHandle consoleHandle, CONSOLE_CURSOR_INFO cursorInfo) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); bool result = NativeMethods.SetConsoleCursorInfo(consoleHandle.DangerousGetHandle(), ref cursorInfo); if (result == false) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "SetConsoleCursorInfo", ErrorCategory.ResourceUnavailable, ConsoleControlStrings.SetConsoleCursorInfoExceptionTemplate); throw e; } }
/// <summary> /// Wraps Win32 SetConsoleCursorPosition /// </summary> /// <param name="consoleHandle"> /// /// handle for the console where cursor position is set /// /// </param> /// <param name="cursorPosition"> /// /// location to which the cursor will be set /// /// </param> /// <exception cref="HostException"> /// If Win32's SetConsoleCursorPosition fails /// </exception> internal static void SetConsoleCursorPosition(ConsoleHandle consoleHandle, Coordinates cursorPosition) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); ConsoleControl.COORD c; c.X = (short)cursorPosition.X; c.Y = (short)cursorPosition.Y; bool result = NativeMethods.SetConsoleCursorPosition(consoleHandle.DangerousGetHandle(), c); if (result == false) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "SetConsoleCursorPosition", ErrorCategory.ResourceUnavailable, ConsoleControlStrings.SetConsoleCursorPositionExceptionTemplate); throw e; } }
/// <summary> /// set the output buffer's size /// </summary> /// <param name="consoleHandle"></param> /// <param name="newSize"></param> /// <exception cref="HostException"> /// If Win32's SetConsoleScreenBufferSize fails /// </exception> internal static void SetConsoleScreenBufferSize(ConsoleHandle consoleHandle, Size newSize) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); COORD s; s.X = (short)newSize.Width; s.Y = (short)newSize.Height; bool result = NativeMethods.SetConsoleScreenBufferSize(consoleHandle.DangerousGetHandle(), s); if (result == false) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "SetConsoleScreenBufferSize", ErrorCategory.ResourceUnavailable, ConsoleControlStrings.SetConsoleScreenBufferSizeExceptionTemplate); throw e; } }
private void OpenSqlFileStream ( string path, byte[] transactionContext, System.IO.FileAccess access, System.IO.FileOptions options, Int64 allocationSize ) { //----------------------------------------------------------------- // precondition validation // these should be checked by any caller of this method // ensure we have validated and normalized the path before Debug.Assert(path != null); Debug.Assert(transactionContext != null); if (access != FileAccess.Read && access != FileAccess.Write && access != FileAccess.ReadWrite) { throw ADP.ArgumentOutOfRange("access"); } // FileOptions is a set of flags, so AND the given value against the set of values we do not support if ((options & ~(FileOptions.WriteThrough | FileOptions.Asynchronous | FileOptions.RandomAccess | FileOptions.SequentialScan)) != 0) { throw ADP.ArgumentOutOfRange("options"); } //----------------------------------------------------------------- // normalize the provided path // * compress path to remove any occurences of '.' or '..' // * trim whitespace from the beginning and end of the path // * ensure that the path starts with '\\' // * ensure that the path does not start with '\\.\' // * ensure that the path is not longer than Int16.MaxValue path = GetFullPathInternal(path); // ensure the running code has permission to read/write the file DemandAccessPermission(path, access); FileFullEaInformation eaBuffer = null; SecurityQualityOfService qos = null; UnicodeString objectName = null; Microsoft.Win32.SafeHandles.SafeFileHandle hFile = null; int nDesiredAccess = UnsafeNativeMethods.FILE_READ_ATTRIBUTES | UnsafeNativeMethods.SYNCHRONIZE; UInt32 dwCreateOptions = 0; UInt32 dwCreateDisposition = 0; System.IO.FileShare shareAccess = System.IO.FileShare.None; switch (access) { case System.IO.FileAccess.Read: nDesiredAccess |= UnsafeNativeMethods.FILE_READ_DATA; shareAccess = System.IO.FileShare.Delete | System.IO.FileShare.ReadWrite; dwCreateDisposition = (uint)UnsafeNativeMethods.CreationDisposition.FILE_OPEN; break; case System.IO.FileAccess.Write: nDesiredAccess |= UnsafeNativeMethods.FILE_WRITE_DATA; shareAccess = System.IO.FileShare.Delete | System.IO.FileShare.Read; dwCreateDisposition = (uint)UnsafeNativeMethods.CreationDisposition.FILE_OVERWRITE; break; case System.IO.FileAccess.ReadWrite: default: // we validate the value of 'access' parameter in the beginning of this method Debug.Assert(access == System.IO.FileAccess.ReadWrite); nDesiredAccess |= UnsafeNativeMethods.FILE_READ_DATA | UnsafeNativeMethods.FILE_WRITE_DATA; shareAccess = System.IO.FileShare.Delete | System.IO.FileShare.Read; dwCreateDisposition = (uint)UnsafeNativeMethods.CreationDisposition.FILE_OVERWRITE; break; } if ((options & System.IO.FileOptions.WriteThrough) != 0) { dwCreateOptions |= (uint)UnsafeNativeMethods.CreateOption.FILE_WRITE_THROUGH; } if ((options & System.IO.FileOptions.Asynchronous) == 0) { dwCreateOptions |= (uint)UnsafeNativeMethods.CreateOption.FILE_SYNCHRONOUS_IO_NONALERT; } if ((options & System.IO.FileOptions.SequentialScan) != 0) { dwCreateOptions |= (uint)UnsafeNativeMethods.CreateOption.FILE_SEQUENTIAL_ONLY; } if ((options & System.IO.FileOptions.RandomAccess) != 0) { dwCreateOptions |= (uint)UnsafeNativeMethods.CreateOption.FILE_RANDOM_ACCESS; } try { eaBuffer = new FileFullEaInformation(transactionContext); qos = new SecurityQualityOfService(UnsafeNativeMethods.SecurityImpersonationLevel.SecurityAnonymous, false, false); // NOTE: the Name property is intended to reveal the publicly available moniker for the // FILESTREAM attributed column data. We will not surface the internal processing that // takes place to create the mappedPath. string mappedPath = InitializeNtPath(path); objectName = new UnicodeString(mappedPath); UnsafeNativeMethods.OBJECT_ATTRIBUTES oa; oa.length = Marshal.SizeOf(typeof(UnsafeNativeMethods.OBJECT_ATTRIBUTES)); oa.rootDirectory = IntPtr.Zero; oa.attributes = (int)UnsafeNativeMethods.Attributes.CaseInsensitive; oa.securityDescriptor = IntPtr.Zero; oa.securityQualityOfService = qos; oa.objectName = objectName; UnsafeNativeMethods.IO_STATUS_BLOCK ioStatusBlock; uint oldMode; uint retval = 0; UnsafeNativeMethods.SetErrorModeWrapper(UnsafeNativeMethods.SEM_FAILCRITICALERRORS, out oldMode); try { Bid.Trace("<sc.SqlFileStream.OpenSqlFileStream|ADV> %d#, desiredAccess=0x%08x, allocationSize=%I64d, fileAttributes=0x%08x, shareAccess=0x%08x, dwCreateDisposition=0x%08x, createOptions=0x%08x\n", ObjectID, (int)nDesiredAccess, allocationSize, 0, (int)shareAccess, dwCreateDisposition, dwCreateOptions); retval = UnsafeNativeMethods.NtCreateFile(out hFile, nDesiredAccess, ref oa, out ioStatusBlock, ref allocationSize, 0, shareAccess, dwCreateDisposition, dwCreateOptions, eaBuffer, (uint)eaBuffer.Length); } finally { UnsafeNativeMethods.SetErrorModeWrapper(oldMode, out oldMode); } switch (retval) { case 0: break; case UnsafeNativeMethods.STATUS_SHARING_VIOLATION: throw ADP.InvalidOperation(Res.GetString(Res.SqlFileStream_FileAlreadyInTransaction)); case UnsafeNativeMethods.STATUS_INVALID_PARAMETER: throw ADP.Argument(Res.GetString(Res.SqlFileStream_InvalidParameter)); case UnsafeNativeMethods.STATUS_OBJECT_NAME_NOT_FOUND: { System.IO.DirectoryNotFoundException e = new System.IO.DirectoryNotFoundException(); ADP.TraceExceptionAsReturnValue(e); throw e; } default: { uint error = UnsafeNativeMethods.RtlNtStatusToDosError(retval); if (error == UnsafeNativeMethods.ERROR_MR_MID_NOT_FOUND) { // status code could not be mapped to a Win32 error code error = retval; } System.ComponentModel.Win32Exception e = new System.ComponentModel.Win32Exception(unchecked ((int)error)); ADP.TraceExceptionAsReturnValue(e); throw e; } } if (hFile.IsInvalid) { System.ComponentModel.Win32Exception e = new System.ComponentModel.Win32Exception(UnsafeNativeMethods.ERROR_INVALID_HANDLE); ADP.TraceExceptionAsReturnValue(e); throw e; } UnsafeNativeMethods.FileType fileType = UnsafeNativeMethods.GetFileType(hFile); if (fileType != UnsafeNativeMethods.FileType.Disk) { hFile.Dispose(); throw ADP.Argument(Res.GetString(Res.SqlFileStream_PathNotValidDiskResource)); } // if the user is opening the SQL FileStream in read/write mode, we assume that they want to scan // through current data and then append new data to the end, so we need to tell SQL Server to preserve // the existing file contents. if (access == System.IO.FileAccess.ReadWrite) { uint ioControlCode = UnsafeNativeMethods.CTL_CODE(UnsafeNativeMethods.FILE_DEVICE_FILE_SYSTEM, IoControlCodeFunctionCode, (byte)UnsafeNativeMethods.Method.METHOD_BUFFERED, (byte)UnsafeNativeMethods.Access.FILE_ANY_ACCESS); uint cbBytesReturned = 0; if (!UnsafeNativeMethods.DeviceIoControl(hFile, ioControlCode, IntPtr.Zero, 0, IntPtr.Zero, 0, out cbBytesReturned, IntPtr.Zero)) { System.ComponentModel.Win32Exception e = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); ADP.TraceExceptionAsReturnValue(e); throw e; } } // now that we've successfully opened a handle on the path and verified that it is a file, // use the SafeFileHandle to initialize our internal System.IO.FileStream instance // NOTE: need to assert UnmanagedCode permissions for this constructor. This is relatively benign // in that we've done much the same validation as in the FileStream(string path, ...) ctor case // most notably, validating that the handle type corresponds to an on-disk file. bool bRevertAssert = false; try { SecurityPermission sp = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode); sp.Assert(); bRevertAssert = true; System.Diagnostics.Debug.Assert(m_fs == null); #if MOBILE m_fs = new System.IO.FileStream(hFile.DangerousGetHandle(), access, ((options & System.IO.FileOptions.Asynchronous) != 0), DefaultBufferSize); #else m_fs = new System.IO.FileStream(hFile, access, DefaultBufferSize, ((options & System.IO.FileOptions.Asynchronous) != 0)); #endif } finally { if (bRevertAssert) { SecurityPermission.RevertAssert(); } } } catch { if (hFile != null && !hFile.IsInvalid) { hFile.Dispose(); } throw; } finally { if (eaBuffer != null) { eaBuffer.Dispose(); eaBuffer = null; } if (qos != null) { qos.Dispose(); qos = null; } if (objectName != null) { objectName.Dispose(); objectName = null; } } }
public static void GetUsnJournalEntries(SafeFileHandle roothandle, Win32Api.USN_JOURNAL_DATA previousUsnState, UInt32 reasonMask, out List<Win32Api.UsnEntry> usnEntries, out Win32Api.USN_JOURNAL_DATA newUsnState) { usnEntries = new List<Win32Api.UsnEntry>(); newUsnState = new Win32Api.USN_JOURNAL_DATA(); QueryUsnJournal(roothandle, ref newUsnState); Win32Api.READ_USN_JOURNAL_DATA rujd = new Win32Api.READ_USN_JOURNAL_DATA(); rujd.StartUsn = previousUsnState.NextUsn; rujd.ReasonMask = reasonMask; rujd.ReturnOnlyOnClose = 0; rujd.Timeout = 0; rujd.bytesToWaitFor = 0; rujd.UsnJournalId = previousUsnState.UsnJournalID; using(var med_struct = new StructWrapper(rujd)) using(var rawdata = new Raw_Array_Wrapper(BUF_LEN)) { uint outBytesReturned = 0; var nextusn = previousUsnState.NextUsn; while(nextusn < newUsnState.NextUsn && Win32Api.DeviceIoControl( roothandle.DangerousGetHandle(), Win32Api.FSCTL_READ_USN_JOURNAL, med_struct.Ptr, med_struct.Size, rawdata.Ptr, rawdata.Size, out outBytesReturned, IntPtr.Zero)) { outBytesReturned = outBytesReturned - sizeof(Int64); IntPtr pUsnRecord = System.IntPtr.Add(rawdata.Ptr, sizeof(Int64));//point safe arithmetic!~!! while(outBytesReturned > 60) // while there are at least one entry in the usn journal { var usnEntry = new Win32Api.UsnEntry(pUsnRecord); if(usnEntry.USN > newUsnState.NextUsn) break; usnEntries.Add(usnEntry); pUsnRecord = System.IntPtr.Add(pUsnRecord, (int)usnEntry.RecordLength);//point safe arithmetic!~!! outBytesReturned -= usnEntry.RecordLength; } nextusn = Marshal.ReadInt64(rawdata.Ptr, 0); Marshal.WriteInt64(med_struct.Ptr, nextusn);//read the usn that we skipped and place it into the nextusn } } }
public static void QueryUsnJournal(SafeFileHandle roothandle, ref Win32Api.USN_JOURNAL_DATA usnJournalState) { int sizeUsnJournalState = Marshal.SizeOf(usnJournalState); UInt32 cb; if(!Win32Api.DeviceIoControl( roothandle.DangerousGetHandle(), Win32Api.FSCTL_QUERY_USN_JOURNAL, IntPtr.Zero, 0, out usnJournalState, sizeUsnJournalState, out cb, IntPtr.Zero)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } }
internal static int ReadConsoleInput(SafeFileHandle consoleHandle, ref ConsoleControl.INPUT_RECORD[] buffer) { int num = 0; bool flag = ConsoleControl.NativeMethods.ReadConsoleInput(consoleHandle.DangerousGetHandle(), buffer, buffer.Length, out num); if (flag) { return num; } else { int lastWin32Error = Marshal.GetLastWin32Error(); HostException hostException = ConsoleControl.CreateHostException(lastWin32Error, "ReadConsoleInput", ErrorCategory.ReadError, ConsoleControlStrings.ReadConsoleInputExceptionTemplate); throw hostException; } }
private static void WriteConsoleOutputCJK(ConsoleHandle consoleHandle, Coordinates origin, Rectangle contentsRegion, BufferCell[,] contents, BufferCellArrayRowType rowType) { Dbg.Assert(origin.X >= 0 && origin.Y >= 0, "origin must be within the output buffer"); int rows = contentsRegion.Bottom - contentsRegion.Top + 1; int cols = contentsRegion.Right - contentsRegion.Left + 1; CONSOLE_FONT_INFO_EX fontInfo = GetConsoleFontInfo(consoleHandle); int fontType = fontInfo.FontFamily & NativeMethods.FontTypeMask; bool trueTypeInUse = (fontType & NativeMethods.TrueTypeFont) == NativeMethods.TrueTypeFont; int bufferLimit = 2 * 1024; // Limit is 8K bytes as each CHAR_INFO takes 4 bytes COORD bufferCoord; bufferCoord.X = 0; bufferCoord.Y = 0; // keeps track of which screen area write SMALL_RECT writeRegion; writeRegion.Top = (short)origin.Y; int rowsRemaining = rows; while (rowsRemaining > 0) { // Iteration of columns is nested inside iteration of rows. // If the size of contents exceeds the buffer limit, writing is // done in blocks of size equal to the bufferlimit from left to right // then top to bottom. // For each iteration of rows, // - writeRegion.Left and bufferSize.X are reset // - rowsRemaining, writeRegion.Top, writeRegion.Bottom, and bufferSize.Y // are updated // For each iteration of columns, // - writeRegion.Left, writeRegion.Right and bufferSize.X are updated writeRegion.Left = (short)origin.X; COORD bufferSize; bufferSize.X = (short)Math.Min(cols, bufferLimit); bufferSize.Y = (short)Math.Min ( rowsRemaining, bufferLimit / bufferSize.X ); writeRegion.Bottom = (short)(writeRegion.Top + bufferSize.Y - 1); // atRow is at which row of contents a particular iteration is operating int atRow = rows - rowsRemaining + contentsRegion.Top; // number of columns yet to be written int colsRemaining = cols; while (colsRemaining > 0) { writeRegion.Right = (short)(writeRegion.Left + bufferSize.X - 1); // atCol is at which column of contents a particular iteration is operating int atCol = cols - colsRemaining + contentsRegion.Left; // if this is not the last column iteration && // the leftmost BufferCell is a leading cell, don't write that cell if (colsRemaining > bufferSize.X && contents[atRow, atCol + bufferSize.X - 1].BufferCellType == BufferCellType.Leading) { bufferSize.X--; writeRegion.Right--; } CHAR_INFO[] characterBuffer = new CHAR_INFO[bufferSize.Y * bufferSize.X]; // copy characterBuffer to contents; int characterBufferIndex = 0; bool lastCharIsLeading = false; BufferCell lastLeadingCell = new BufferCell(); for (int r = atRow; r < bufferSize.Y + atRow; r++) { for (int c = atCol; c < bufferSize.X + atCol; c++, characterBufferIndex++) { if (contents[r, c].BufferCellType == BufferCellType.Complete) { characterBuffer[characterBufferIndex].UnicodeChar = (ushort)contents[r, c].Character; characterBuffer[characterBufferIndex].Attributes = (ushort)(ColorToWORD(contents[r, c].ForegroundColor, contents[r, c].BackgroundColor)); lastCharIsLeading = false; } else if (contents[r, c].BufferCellType == BufferCellType.Leading) { characterBuffer[characterBufferIndex].UnicodeChar = (ushort)contents[r, c].Character; characterBuffer[characterBufferIndex].Attributes = (ushort)(ColorToWORD(contents[r, c].ForegroundColor, contents[r, c].BackgroundColor) | (ushort)NativeMethods.CHAR_INFO_Attributes.COMMON_LVB_LEADING_BYTE); lastCharIsLeading = true; lastLeadingCell = contents[r, c]; } else if (contents[r, c].BufferCellType == BufferCellType.Trailing) { // The FontFamily is a 8-bit integer. The low-order bit (bit 0) specifies the pitch of the font. // If it is 1, the font is variable pitch (or proportional). If it is 0, the font is fixed pitch // (or monospace). Bits 1 and 2 specify the font type. If both bits are 0, the font is a raster font; // if bit 1 is 1 and bit 2 is 0, the font is a vector font; if bit 1 is 0 and bit 2 is set, or if both // bits are 1, the font is true type. Bit 3 is 1 if the font is a device font; otherwise, it is 0. // We only care about the bit 1 and 2, which indicate the font type. // There are only two font type defined for the Console, at // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\. // Console\Nls --- national language supports // Console\RasterFonts --- raster type font // Console\TrueTypeFont --- true type font // For CJK characters, if it's TrueType, we need to output the trailing character marked with "Trailing_byte" // attribute. But if it's RasterFont, we ignore the trailing character, and the "Leading_byte"/"Trailing_byte" // attributes are not effective at all when reading the character from the console buffer. if (lastCharIsLeading && trueTypeInUse) { // For TrueType Font, we output the trailing byte with "Trailing_byte" attribute characterBuffer[characterBufferIndex].UnicodeChar = lastLeadingCell.Character; characterBuffer[characterBufferIndex].Attributes = (ushort)(ColorToWORD(contents[r, c].ForegroundColor, contents[r, c].BackgroundColor) | (ushort)NativeMethods.CHAR_INFO_Attributes.COMMON_LVB_TRAILING_BYTE); } else { // We don't output anything for this cell if Raster font is in use, or if the last cell is not a leading byte characterBufferIndex--; } lastCharIsLeading = false; } } } // Now writeRegion, bufferSize and characterBuffer are updated. // Call NativeMethods.WriteConsoleOutput bool result; if ((rowType & BufferCellArrayRowType.RightLeading) != 0 && colsRemaining == bufferSize.X) { COORD bSize = bufferSize; bSize.X++; SMALL_RECT wRegion = writeRegion; wRegion.Right++; // Suppress the PreFAST warning about not using Marshal.GetLastWin32Error() to // get the error code. #pragma warning disable 56523 result = NativeMethods.WriteConsoleOutput( consoleHandle.DangerousGetHandle(), characterBuffer, bSize, bufferCoord, ref wRegion); } else { // Suppress the PreFAST warning about not using Marshal.GetLastWin32Error() to // get the error code. #pragma warning disable 56523 result = NativeMethods.WriteConsoleOutput( consoleHandle.DangerousGetHandle(), characterBuffer, bufferSize, bufferCoord, ref writeRegion); } if (result == false) { // When WriteConsoleOutput fails, half bufferLimit if (bufferLimit < 2) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "WriteConsoleOutput", ErrorCategory.WriteError, ConsoleControlStrings.WriteConsoleOutputExceptionTemplate); throw e; } bufferLimit /= 2; if (cols == colsRemaining) { // if cols == colsRemaining, nothing is guaranteed written in this pass and // the unwritten area is still rectangular bufferSize.Y = 0; break; } else { // some areas have been written. This could only happen when the number of columns // to write is larger than bufferLimit. In that case, the algorithm writes one row // at a time => bufferSize.Y == 1. Then, we can safely leave bufferSize.Y unchanged // to retry with a smaller bufferSize.X. Dbg.Assert(bufferSize.Y == 1, string.Format(CultureInfo.InvariantCulture, "bufferSize.Y should be 1, but is {0}", bufferSize.Y)); bufferSize.X = (short)Math.Min(colsRemaining, bufferLimit); continue; } } colsRemaining -= bufferSize.X; writeRegion.Left += bufferSize.X; bufferSize.X = (short)Math.Min(colsRemaining, bufferLimit); } // column iteration rowsRemaining -= bufferSize.Y; writeRegion.Top += bufferSize.Y; } // row iteration }
/// <summary> /// /// Wrap Win32 WriteConsole /// /// </summary> /// <param name="consoleHandle"> /// /// handle for the console where the string is written /// /// </param> /// <param name="output"> /// /// string that is written /// /// </param> /// <exception cref="HostException"> /// /// if the Win32's WriteConsole fails /// /// </exception> internal static void WriteConsole(ConsoleHandle consoleHandle, string output) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); if (String.IsNullOrEmpty(output)) return; // Native WriteConsole doesn't support output buffer longer than 64K. // We need to chop the output string if it is too long. int cursor = 0; // This records the chopping position in output string const int maxBufferSize = 16383; // this is 64K/4 - 1 to account for possible width of each character. while (cursor < output.Length) { string outBuffer; if (cursor + maxBufferSize < output.Length) { outBuffer = output.Substring(cursor, maxBufferSize); cursor += maxBufferSize; } else { outBuffer = output.Substring(cursor); cursor = output.Length; } DWORD charsWritten; bool result = NativeMethods.WriteConsole( consoleHandle.DangerousGetHandle(), outBuffer, (DWORD)outBuffer.Length, out charsWritten, IntPtr.Zero); if (result == false) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "WriteConsole", ErrorCategory.WriteError, ConsoleControlStrings.WriteConsoleExceptionTemplate); throw e; } } }
private static void WriteConsoleOutputPlain(ConsoleHandle consoleHandle, Coordinates origin, BufferCell[,] contents) { int rows = contents.GetLength(0); int cols = contents.GetLength(1); if ((rows <= 0) || cols <= 0) { tracer.WriteLine("contents passed in has 0 rows and columns"); return; } int bufferLimit = 2 * 1024; // Limit is 8K bytes as each CHAR_INFO takes 4 bytes COORD bufferCoord; bufferCoord.X = 0; bufferCoord.Y = 0; // keeps track of which screen area write SMALL_RECT writeRegion; writeRegion.Top = (short)origin.Y; int rowsRemaining = rows; while (rowsRemaining > 0) { // Iteration of columns is nested inside iteration of rows. // If the size of contents exceeds the buffer limit, writing is // done in blocks of size equal to the bufferlimit from left to right // then top to bottom. // For each iteration of rows, // - writeRegion.Left and bufferSize.X are reset // - rowsRemaining, writeRegion.Top, writeRegion.Bottom, and bufferSize.Y // are updated // For each iteration of columns, // - writeRegion.Left, writeRegion.Right and bufferSize.X are updated writeRegion.Left = (short)origin.X; COORD bufferSize; bufferSize.X = (short)Math.Min(cols, bufferLimit); bufferSize.Y = (short)Math.Min ( rowsRemaining, bufferLimit / bufferSize.X ); writeRegion.Bottom = (short)(writeRegion.Top + bufferSize.Y - 1); // atRow is at which row of contents a particular iteration is operating int atRow = rows - rowsRemaining + contents.GetLowerBound(0); // number of columns yet to be written int colsRemaining = cols; while (colsRemaining > 0) { writeRegion.Right = (short)(writeRegion.Left + bufferSize.X - 1); // atCol is at which column of contents a particular iteration is operating int atCol = cols - colsRemaining + contents.GetLowerBound(1); CHAR_INFO[] characterBuffer = new CHAR_INFO[bufferSize.Y * bufferSize.X]; // copy characterBuffer to contents; for (int r = atRow, characterBufferIndex = 0; r < bufferSize.Y + atRow; r++) { for (int c = atCol; c < bufferSize.X + atCol; c++, characterBufferIndex++) { characterBuffer[characterBufferIndex].UnicodeChar = (ushort)contents[r, c].Character; characterBuffer[characterBufferIndex].Attributes = ColorToWORD(contents[r, c].ForegroundColor, contents[r, c].BackgroundColor); } } // Now writeRegion, bufferSize and characterBuffer are updated. // Call NativeMethods.WriteConsoleOutput bool result = NativeMethods.WriteConsoleOutput( consoleHandle.DangerousGetHandle(), characterBuffer, bufferSize, bufferCoord, ref writeRegion); if (result == false) { // When WriteConsoleOutput fails, half bufferLimit if (bufferLimit < 2) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "WriteConsoleOutput", ErrorCategory.WriteError, ConsoleControlStrings.WriteConsoleOutputExceptionTemplate); throw e; } bufferLimit /= 2; if (cols == colsRemaining) { // if cols == colsRemaining, nothing is guaranteed written in this pass and // the unwritten area is still rectangular bufferSize.Y = 0; break; } else { // some areas have been written. This could only happen when the number of columns // to write is larger than bufferLimit. In that case, the algorithm writes one row // at a time => bufferSize.Y == 1. Then, we can safely leave bufferSize.Y unchanged // to retry with a smaller bufferSize.X. Dbg.Assert(bufferSize.Y == 1, string.Format(CultureInfo.InvariantCulture, "bufferSize.Y should be 1, but is {0}", bufferSize.Y)); bufferSize.X = (short)Math.Min(colsRemaining, bufferLimit); continue; } } colsRemaining -= bufferSize.X; writeRegion.Left += bufferSize.X; bufferSize.X = (short)Math.Min(colsRemaining, bufferLimit); } // column iteration rowsRemaining -= bufferSize.Y; writeRegion.Top += bufferSize.Y; } // row iteration }
internal static CONSOLE_FONT_INFO_EX GetConsoleFontInfo(ConsoleHandle consoleHandle) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); CONSOLE_FONT_INFO_EX fontInfo = new CONSOLE_FONT_INFO_EX(); fontInfo.cbSize = Marshal.SizeOf(fontInfo); bool result = NativeMethods.GetCurrentConsoleFontEx(consoleHandle.DangerousGetHandle(), false, ref fontInfo); if (result == false) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "GetConsoleFontInfo", ErrorCategory.ResourceUnavailable, ConsoleControlStrings.GetConsoleFontInfoExceptionTemplate); throw e; } return fontInfo; }
private static bool ReadConsoleOutputCJKSmall ( ConsoleHandle consoleHandle, uint codePage, Coordinates origin, Rectangle contentsRegion, ref BufferCell[,] contents ) { COORD bufferSize; bufferSize.X = (short)(contentsRegion.Right - contentsRegion.Left + 1); bufferSize.Y = (short)(contentsRegion.Bottom - contentsRegion.Top + 1); COORD bufferCoord; bufferCoord.X = 0; bufferCoord.Y = 0; CHAR_INFO[] characterBuffer = new CHAR_INFO[bufferSize.X * bufferSize.Y]; SMALL_RECT readRegion; readRegion.Left = (short)origin.X; readRegion.Top = (short)origin.Y; readRegion.Right = (short)(origin.X + bufferSize.X - 1); readRegion.Bottom = (short)(origin.Y + bufferSize.Y - 1); // Suppress the PreFAST warning about not using Marshal.GetLastWin32Error() to // get the error code. #pragma warning disable 56523 bool result = NativeMethods.ReadConsoleOutput( consoleHandle.DangerousGetHandle(), characterBuffer, bufferSize, bufferCoord, ref readRegion); if (!result) { return false; } int characterBufferIndex = 0; for (int r = contentsRegion.Top; r <= contentsRegion.Bottom; r++) { for (int c = contentsRegion.Left; c <= contentsRegion.Right; c++, characterBufferIndex++) { ConsoleColor fgColor, bgColor; contents[r, c].Character = (char)characterBuffer[characterBufferIndex].UnicodeChar; WORDToColor(characterBuffer[characterBufferIndex].Attributes, out fgColor, out bgColor); contents[r, c].ForegroundColor = fgColor; contents[r, c].BackgroundColor = bgColor; // Set the attributes of the buffercells to be the same as that of the // incoming CHAR_INFO. In case where the CHAR_INFO character is a // trailing byte set the Character of BufferCell to 0. This is done // because at a lot of places this check is being done. Having a trailing // character to be 0 is by design. if ((characterBuffer[characterBufferIndex].Attributes & (ushort)NativeMethods.CHAR_INFO_Attributes.COMMON_LVB_LEADING_BYTE) == (ushort)NativeMethods.CHAR_INFO_Attributes.COMMON_LVB_LEADING_BYTE) { contents[r, c].BufferCellType = BufferCellType.Leading; } else if ((characterBuffer[characterBufferIndex].Attributes & (ushort)NativeMethods.CHAR_INFO_Attributes.COMMON_LVB_TRAILING_BYTE) == (ushort)NativeMethods.CHAR_INFO_Attributes.COMMON_LVB_TRAILING_BYTE) { contents[r, c].Character = (char)0; contents[r, c].BufferCellType = BufferCellType.Trailing; } else { int charLength = LengthInBufferCells(contents[r, c].Character); if (charLength == 2) { // When it's RasterFont, the "Leading_byte"/"Trailing_byte" are not effective, we // need to decide the leading byte by checking the char length. contents[r, c].BufferCellType = BufferCellType.Leading; c++; contents[r, c].Character = (char)0; contents[r, c].ForegroundColor = fgColor; contents[r, c].BackgroundColor = bgColor; contents[r, c].BufferCellType = BufferCellType.Trailing; } else { contents[r, c].BufferCellType = BufferCellType.Complete; } } } } return true; }
/// <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; } }
private static void ReadConsoleOutputPlain ( ConsoleHandle consoleHandle, Coordinates origin, Rectangle contentsRegion, ref BufferCell[,] contents ) { int rows = contentsRegion.Bottom - contentsRegion.Top + 1; int cols = contentsRegion.Right - contentsRegion.Left + 1; if ((rows <= 0) || cols <= 0) { tracer.WriteLine("invalid contents region"); return; } int bufferLimit = 2 * 1024; // Limit is 8K bytes as each CHAR_INFO takes 4 bytes COORD bufferCoord; bufferCoord.X = 0; bufferCoord.Y = 0; // keeps track of which screen area read SMALL_RECT readRegion; readRegion.Top = (short)origin.Y; int rowsRemaining = rows; while (rowsRemaining > 0) { // Iteration of columns is nested inside iteration of rows. // If the size of contents exceeds the buffer limit, reading is // done in blocks of size equal to the bufferlimit from left to right // then top to bottom. // For each iteration of rows, // - readRegion.Left and bufferSize.X are reset // - rowsRemaining, readRegion.Top, readRegion.Bottom, and bufferSize.Y // are updated // For each iteration of columns, // - readRegion.Left, readRegion.Right and bufferSize.X are updated readRegion.Left = (short)origin.X; COORD bufferSize; bufferSize.X = (short)Math.Min(cols, bufferLimit); bufferSize.Y = (short)Math.Min ( rowsRemaining, bufferLimit / bufferSize.X ); readRegion.Bottom = (short)(readRegion.Top + bufferSize.Y - 1); // atContentsRow is at which row of contents a particular iteration is operating int atContentsRow = rows - rowsRemaining + contentsRegion.Top; // number of columns yet to be read int colsRemaining = cols; while (colsRemaining > 0) { readRegion.Right = (short)(readRegion.Left + bufferSize.X - 1); // Now readRegion and bufferSize are updated. // Call NativeMethods.ReadConsoleOutput CHAR_INFO[] characterBuffer = new CHAR_INFO[bufferSize.Y * bufferSize.X]; bool result = NativeMethods.ReadConsoleOutput( consoleHandle.DangerousGetHandle(), characterBuffer, bufferSize, bufferCoord, ref readRegion); if (result == false) { // When WriteConsoleOutput fails, half bufferLimit if (bufferLimit < 2) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "ReadConsoleOutput", ErrorCategory.ReadError, ConsoleControlStrings.ReadConsoleOutputExceptionTemplate); throw e; } // if cols == colsRemaining, nothing is guaranteed read in this pass and // the unread area is still rectangular bufferLimit /= 2; if (cols == colsRemaining) { bufferSize.Y = 0; break; } else { // some areas have been read. This could only happen when the number of columns // to write is larger than bufferLimit. In that case, the algorithm reads one row // at a time => bufferSize.Y == 1. Then, we can safely leave bufferSize.Y unchanged // to retry with a smaller bufferSize.X. Dbg.Assert(bufferSize.Y == 1, string.Format(CultureInfo.InvariantCulture, "bufferSize.Y should be 1, but is {0}", bufferSize.Y)); bufferSize.X = (short)Math.Min(colsRemaining, bufferLimit); continue; } } // atContentsCol is at which column of contents a particular iteration is operating int atContentsCol = cols - colsRemaining + contentsRegion.Left; // copy characterBuffer to contents; int characterBufferIndex = 0; for (int r = atContentsRow; r < bufferSize.Y + atContentsRow; r++) { for (int c = atContentsCol; c < bufferSize.X + atContentsCol; c++, characterBufferIndex++) { contents[r, c].Character = (char) characterBuffer[characterBufferIndex].UnicodeChar; ConsoleColor fgColor, bgColor; WORDToColor(characterBuffer[characterBufferIndex].Attributes, out fgColor, out bgColor); contents[r, c].ForegroundColor = fgColor; contents[r, c].BackgroundColor = bgColor; } } colsRemaining -= bufferSize.X; readRegion.Left += bufferSize.X; bufferSize.X = (short)Math.Min(colsRemaining, bufferLimit); } // column iteration rowsRemaining -= bufferSize.Y; readRegion.Top += bufferSize.Y; } // row iteration // The following nested loop set the value of the empty cells in contents: // character to ' ' // foreground color to console's foreground color // background color to console's background color int rowIndex = contents.GetLowerBound(0); int rowEnd = contents.GetUpperBound(0); int colBegin = contents.GetLowerBound(1); int colEnd = contents.GetUpperBound(1); CONSOLE_SCREEN_BUFFER_INFO bufferInfo = GetConsoleScreenBufferInfo(consoleHandle); ConsoleColor foreground = 0; ConsoleColor background = 0; WORDToColor( bufferInfo.Attributes, out foreground, out background ); while (rowIndex <= rowEnd) { int colIndex = colBegin; while (true) { // if contents[rowIndex,colIndex] is in contentsRegion, hence a non-empty cell, // move colIndex to one past the right end of contentsRegion if (contentsRegion.Top <= rowIndex && rowIndex <= contentsRegion.Bottom && contentsRegion.Left <= colIndex && colIndex <= contentsRegion.Right) { colIndex = contentsRegion.Right + 1; } // colIndex past contents last column if (colIndex > colEnd) { break; } contents[rowIndex, colIndex].Character = ' '; contents[rowIndex, colIndex].ForegroundColor = foreground; contents[rowIndex, colIndex].BackgroundColor = background; colIndex++; } rowIndex++; } }
/// <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 FillConsoleOutputCharacter /// </summary> /// <param name="consoleHandle"> /// /// handle for the console where output is filled /// /// </param> /// <param name="character"> /// /// character to fill the console output /// /// </param> /// <param name="numberToWrite"> /// /// number of times to write character /// /// </param> /// <param name="origin"> /// /// location on screen buffer where writing starts /// /// </param> /// <exception cref="HostException"> /// If Win32's FillConsoleOutputCharacter fails /// </exception> internal static void FillConsoleOutputCharacter ( ConsoleHandle consoleHandle, char character, int numberToWrite, Coordinates origin ) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); COORD c; c.X = (short)origin.X; c.Y = (short)origin.Y; DWORD unused = 0; bool result = NativeMethods.FillConsoleOutputCharacter( consoleHandle.DangerousGetHandle(), character, (DWORD)numberToWrite, c, out unused); if (result == false) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "FillConsoleOutputCharacter", ErrorCategory.WriteError, ConsoleControlStrings.FillConsoleOutputCharacterExceptionTemplate); throw e; } // we don't assert that the number actually written matches the number we asked for, as the function may clip if // the number of cells to write extends past the end of the screen buffer. }
/// <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; } }
/// <summary> /// Wraps Win32 FillConsoleOutputAttribute /// </summary> /// <param name="consoleHandle"> /// /// handle for the console where output is filled /// /// </param> /// <param name="attribute"> /// /// attribute to fill the console output /// /// </param> /// <param name="numberToWrite"> /// /// number of times to write attribute /// /// </param> /// <param name="origin"> /// /// location on screen buffer where writing starts /// /// </param> /// <exception cref="HostException"> /// If Win32's FillConsoleOutputAttribute fails /// </exception> internal static void FillConsoleOutputAttribute ( ConsoleHandle consoleHandle, WORD attribute, int numberToWrite, Coordinates origin ) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); COORD c; c.X = (short)origin.X; c.Y = (short)origin.Y; DWORD unused = 0; bool result = NativeMethods.FillConsoleOutputAttribute( consoleHandle.DangerousGetHandle(), attribute, (DWORD)numberToWrite, c, out unused); if (result == false) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "FillConsoleOutputAttribute", ErrorCategory.WriteError, ConsoleControlStrings.FillConsoleOutputAttributeExceptionTemplate); throw e; } }
public static string GetFinalPathNameByHandle(SafeFileHandle safeHandle, DWORD dwFlags) { Contract.Requires(safeHandle != null); var rawHandle = safeHandle.DangerousGetHandle(); if (safeHandle.IsClosed || safeHandle.IsInvalid) throw new ArgumentException(); var pathLength = GetFinalPathNameByHandle(rawHandle, null, 0, dwFlags); NativeMethods.CheckWin32(pathLength > 0); var pathBuilder = new StringBuilder((int)pathLength); pathBuilder.Length = (int)pathLength; NativeMethods.CheckWin32(GetFinalPathNameByHandle(rawHandle, pathBuilder, pathLength, dwFlags) > 0); return pathBuilder.ToString(); }
/// <summary> /// Wrap Win32 ScrollConsoleScreenBuffer /// </summary> /// <param name="consoleHandle"> /// /// handle for the console where screen buffer is scrolled /// /// </param> /// <param name="scrollRectangle"> /// /// area to be scrolled /// /// </param> /// <param name="clipRectangle"> /// /// area to be updated after scrolling /// /// </param> /// <param name="destOrigin"> /// /// location to which the top left corner of scrollRectangle move /// /// </param> /// <param name="fill"> /// /// character and attribute to fill the area vacated by the scroll /// /// </param> /// <exception cref="HostException"> /// If Win32's ScrollConsoleScreenBuffer fails /// </exception> internal static void ScrollConsoleScreenBuffer ( ConsoleHandle consoleHandle, SMALL_RECT scrollRectangle, SMALL_RECT clipRectangle, COORD destOrigin, CHAR_INFO fill ) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); bool result = NativeMethods.ScrollConsoleScreenBuffer( consoleHandle.DangerousGetHandle(), ref scrollRectangle, ref clipRectangle, destOrigin, ref fill); if (result == false) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "ScrollConsoleScreenBuffer", ErrorCategory.WriteError, ConsoleControlStrings.ScrollConsoleScreenBufferExceptionTemplate); throw e; } }
internal static CONSOLE_FONT_INFO_EX GetConsoleFontInfo(SafeFileHandle consoleHandle) { CONSOLE_FONT_INFO_EX fontInfo = new CONSOLE_FONT_INFO_EX(); fontInfo.cbSize = Marshal.SizeOf(fontInfo); bool result = NativeMethods.GetCurrentConsoleFontEx(consoleHandle.DangerousGetHandle(), false, ref fontInfo); if (result == false) { int err = Marshal.GetLastWin32Error(); Win32Exception innerException = new Win32Exception(err); throw new Exception("Failed to get console font information.", innerException); } return fontInfo; }
/// <summary> /// Wraps Win32 GetLargestConsoleWindowSize /// </summary> /// <param name="consoleHandle"> /// /// handle for the console for which the largest window size is obtained /// /// </param> /// <returns> /// /// the largest window size /// /// </returns> /// <exception cref="HostException"> /// If Win32's GetLargestConsoleWindowSize fails /// </exception> internal static Size GetLargestConsoleWindowSize(ConsoleHandle consoleHandle) { Dbg.Assert(!consoleHandle.IsInvalid, "ConsoleHandle is not valid"); Dbg.Assert(!consoleHandle.IsClosed, "ConsoleHandle is closed"); COORD result = NativeMethods.GetLargestConsoleWindowSize(consoleHandle.DangerousGetHandle()); if ((result.X == 0) && (result.Y == 0)) { int err = Marshal.GetLastWin32Error(); HostException e = CreateHostException(err, "GetLargestConsoleWindowSize", ErrorCategory.ResourceUnavailable, ConsoleControlStrings.GetLargestConsoleWindowSizeExceptionTemplate); throw e; } return new Size(result.X, result.Y); }
public static DISK_GEOMETRY GetGeometry(SafeFileHandle Handle) { if (Handle.IsInvalid || Handle.IsClosed) throw new Exception("Native.GetGeometry: Invalid handle specified. It is closed or invalid."); var geom = new DISK_GEOMETRY(); uint returnedBytes; if (DeviceIoControl(Handle.DangerousGetHandle(), (uint)IOCTL_CONTROL_CODE_CONSTANTS.IOCTL_DISK_GET_DRIVE_GEOMETRY, IntPtr.Zero, 0, ref geom, (uint)Marshal.SizeOf(typeof(DISK_GEOMETRY)), out returnedBytes, IntPtr.Zero)) return geom; Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); return new DISK_GEOMETRY(); }
internal static string ReadConsole(SafeFileHandle consoleHandle, string initialContent, int charactersToRead, bool endOnTab, out int keyState) { keyState = 0; ConsoleControl.CONSOLE_READCONSOLE_CONTROL length = new ConsoleControl.CONSOLE_READCONSOLE_CONTROL(); length.nLength = Marshal.SizeOf(length); length.nInitialChars = initialContent.Length; length.dwControlKeyState = 0; if (endOnTab) { length.dwCtrlWakeupMask = 0x200; } int num = 0; StringBuilder stringBuilder = new StringBuilder(initialContent, charactersToRead); bool flag = ConsoleControl.NativeMethods.ReadConsole(consoleHandle.DangerousGetHandle(), stringBuilder, charactersToRead, out num, ref length); keyState = length.dwControlKeyState; if (flag) { if (num > stringBuilder.Length) { num = stringBuilder.Length; } return stringBuilder.ToString(0, num); } else { int lastWin32Error = Marshal.GetLastWin32Error(); HostException hostException = ConsoleControl.CreateHostException(lastWin32Error, "ReadConsole", ErrorCategory.ReadError, ConsoleControlStrings.ReadConsoleExceptionTemplate); throw hostException; } }