//	--------------------------------------------------------------------
        //	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