// -------------------------------------------------------------------- // This method was ported from SHS_StandardHandleState.C. Portions of // it were subsequently re-factored into GetStandardHandle, to vastly // simplify porting SHS_GetStdHandleFNCLI to GetRedirectedFileName. // -------------------------------------------------------------------- /// <summary> /// Get the redirection state of a specified standard console stream. /// </summary> /// <param name="penmStdHandleID"> /// Use a member of the StandardConsoleHandle enumeration to designate /// the desired standard console stream. /// </param> /// <returns> /// The return value is one of the following. /// /// StandardHandleState.Attached means that the specified stream is /// attached to its console. /// /// StandardHandleState.Redirected means that the specified stream is /// redirected. /// /// Call GetRedirectedFileName to get the fully qualified name of the /// file to which it is redirected. /// </returns> /// <remarks> /// In all versions of the framework, the following properties report /// inaccurately on the true state of the console stream. /// /// - System.Diagnostics.Process.StartInfo.RedirectStandardInput , /// - System.Diagnostics.Process.StartInfo.RedirectStandardOutput , /// - System.Diagnostics.Process.StartInfo.RedirectStandardError , /// /// The following properties, added in version 4.5, also report incorrectly. /// /// - Console.IsErrorRedirected /// - Console.IsInputRedirected /// - Console.IsOutputRedirected /// /// The above properties report inaccurately because their report is /// based entirely on changes made by calls to methods on the Console /// class. They exhibit no knowledge, whatsoever, of what the underlying /// operating system does in response to shell commands to redirect one /// or more of the standard console streams. /// /// On the other hand, since StandardHandleState gets its information /// from GetConsoleMode, a native Windows API routine, its report takes /// into account console stream redirections that are the result of /// shell commands. /// </remarks> public static StandardHandleState GetStandardHandleState(StandardConsoleHandle penmStdHandleID) { IntPtr hThis = INVALID_MODULE_HANDLE; // In the ANSI C implementation, the first use of this variable initializes it. As a concession to the C# compiler, this version employs a static initializer. UInt32 dwModde = ( uint )INVALID_MODULE_HANDLE; // The first use of this variable initializes it, AND it's a throwaway. As a concession to the C# compiler, this version employs a static initializer. if ((hThis = GetStandardHandle(penmStdHandleID)) != INVALID_HANDLE_VALUE) { // Handle acquired. Since GetStdHandle leaves the reference count unchanged, hThis needn't, and shouldn't, be closed. if (GetConsoleMode(hThis, out dwModde)) { // Handles that are attached to a console have a ConsoleMode. return(StandardHandleState.Attached); } // TRUE (Handle is attached to its console.) block, if ( GetConsoleMode ( hThis , &dwModde ) ) else { // When a console stream is redirected, its handle loses its ConsoleMode. s_intLastWin32Error = Marshal.GetLastWin32Error( ); if (s_intLastWin32Error == ERROR_INVALID_HANDLE) { // Since LastError is ERROR_INVALID_HANDLE, the cause of the failure is that the handle is redirected. return(StandardHandleState.Redirected); } // TRUE (anticipated outcome) block, if ( intLastWin32Error == ERROR_INVALID_HANDLE ) else { // Something besides redirection caused GetConsoleMode to fail. return(StandardHandleState.STATE_SYSTEM_ERROR); } // FALSE (unanticipated outcome) block, if ( intLastWin32Error == ERROR_INVALID_HANDLE ) } // FALSE (Handle is redirected from its console into a file or pipe.) block, if ( GetConsoleMode ( hThis , &dwModde ) ) } // TRUE (anticipated outcome) block, if ( ( hThis = GetStdHandle ( dwStdConsoleHandleIDs [ ( int ) penmStdHandleID ] ) ) != ( IntPtr ) INVALID_HANDLE_VALUE ) else { // Windows declined the request. Report that GetStdHandle failed. s_intLastWin32Error = Marshal.GetLastWin32Error( ); return(penmStdHandleID == StandardConsoleHandle.Undefined ? StandardHandleState.Undetermined : StandardHandleState.STATE_SYSTEM_ERROR); } // FALSE (unanticipated outcome) block, if ( ( hThis = GetStdHandle ( dwStdConsoleHandleIDs [ ( int ) penmStdHandleID ] ) ) != ( IntPtr ) INVALID_HANDLE_VALUE ) } // SHS_StandardHandleState
} // SHS_StandardHandleState // -------------------------------------------------------------------- // This method is a consolidated port of SHS_GetStdHandleFNCLI and // SHS_GetStdHandleFNW, which are rolled into one method. // -------------------------------------------------------------------- /// <summary> /// Get the name of the file to which a specified standard handle is /// redirected. /// </summary> /// <param name="penmStdHandleID"> /// Use a member of the StandardConsoleHandle enumeration to designate /// the desired standard console stream. /// </param> /// <returns> /// If the file is redirected, the returned string contains the fully /// qualified name of the file to which it is redirected. If the handle /// is attached to its console (that is, not redirected), the return /// value is the empty string. /// </returns> public static string GetRedirectedFileName(StandardConsoleHandle penmStdHandleID) { if (GetStandardHandleState(penmStdHandleID) != StandardHandleState.Redirected) { // A stream that is attached to its console has no file. return(SpecialStrings.EMPTY_STRING); } // if ( StandardHandleState ( penmStdHandleID ) != StandardHandleState.Redirected ) if (BasicSystemInfoDisplayMessages.WWKW_OSIsVistaOrNewer( )) { // This API requires Windows Vista or newer. using (WizardWrx.Core.UnmanagedLibrary lib = new WizardWrx.Core.UnmanagedLibrary("kernel32")) // becomes call to LoadLibrary { // Since it employs unmanaged resources, the UnmanagedLibrary instance implements IDisposable; hence, the using block. GetFinalPathNameByHandle fnGetFinalPathNameByHandle = lib.GetUnmanagedFunction <GetFinalPathNameByHandle> ("GetFinalPathNameByHandleW"); char [] achrManagedBuffer = new char [MagicNumbers.CAPACITY_32KB]; // Reserve 32K characters. GCHandle gchPinnedArray = GCHandle.Alloc( achrManagedBuffer, // Now that it is allocated, keep the garbage collector away from it. GCHandleType.Pinned); IntPtr lpManagedBuffer = gchPinnedArray.AddrOfPinnedObject( ); // Since IntPtr is a structure, this operation cannot be nested. // -------------------------------------------------------- // Since the return value, intFQFNLength, is the last // parameter of the string constructor, which must be first // onto the stack, this function call cannot be nested. // -------------------------------------------------------- Int32 intFQFNLength = fnGetFinalPathNameByHandle( GetStandardHandle(penmStdHandleID), // IntPtr hFile lpManagedBuffer, // IntPtr lpszFilePath MagicNumbers.CAPACITY_32KB, // UInt32 cchFilePath FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); // UInt32 dwFlags return(new string ( // Array of characters in, string out. achrManagedBuffer, // Array from which to copy characters ArrayInfo.ARRAY_FIRST_ELEMENT, // Start copying at this index into the array. intFQFNLength )); // Stop when this many characters have been copied. } // implicit call to lib.Dispose, which calls FreeLibrary. } // TRUE (anticipated outcome) block, if ( WWKW_OSIsVistaOrNewer ( ) ) else { // Windows versions before Vista are unsupported. throw new InvalidOperationException( string.Format( Properties.Resources.ERRMSG_UNSUPPORTED_WINDOWS_VERSION, // Format Control String new object [] // Make the parameter array explicit, { // and the ToString calls implicit. Environment.OSVersion.Version.Major, // Format Item 0 = installed version of Microsoft Windows, version {0} Environment.OSVersion.Version.Minor, // Format Item 1 = {1}. BasicSystemInfoDisplayMessages.WWKW_GETOSVERSIONINFO_VISTA, // Format Item 2 = minimum supported version is {2}. BasicSystemInfoDisplayMessages.WWKW_GETOSVERSIONINFO_BASE, // Format Item 3 = .{3}. Environment.NewLine // Format Item 4 = Newline embedded: .{4}The minimum supported })); } // FALSE (unanticipated outcome) block, if ( WWKW_OSIsVistaOrNewer ( ) ) } // GetRedirectedFileName
} // GetModuleHandle private static IntPtr GetStandardHandle(StandardConsoleHandle penmStdHandleID) { IntPtr hThis = INVALID_HANDLE_VALUE; // In the ANSI C implementation, the first use of this variable initializes it. As a concession to the C# compiler, this version employs a static initializer. switch (penmStdHandleID) { case StandardConsoleHandle.StandardInput: case StandardConsoleHandle.StandardOutput: case StandardConsoleHandle.StandardError: return(GetStdHandle( s_adwStdConsoleHandleIDs [( int )penmStdHandleID])); // An invalid argument elicits a return value of INVALID_HANDLE_VALUE, for which the caller must test. case StandardConsoleHandle.Undefined: // Argument penmStdHandleID is uninitialized. case StandardConsoleHandle.OutOfRange: // Argument penmStdHandleID is out of range. default: return(INVALID_HANDLE_VALUE); } // switch ( penmStdHandleID ) } // GetStandardHandle