No Console Output When Using Allocconsole and Target Architecture X86

No console output when using AllocConsole and target architecture x86

When "Enable native code debugging" is enabled, output from consoles crated with AllocConsole is redirected to the debug output window instead.

The reason this only happens in x86 and not AnyCPU is because you can only debug native code in an x86 application.

Note that this behavior only occurs with consoles created with AllocConsole. A console application's output is not redirected.

EDIT: The other reason for the console not outputting text is when you've written to the console before calling AllocConsole.

Regardless of the reason, this code will restore output if it was redirected, and reopen the console in case it's invalid. It uses the magic number 7 which is what the handle of stdout usually equals to.

using System;
using System.IO;
using System.Runtime.InteropServices;

public static class ConsoleHelper
{
public static void CreateConsole()
{
AllocConsole();

// stdout's handle seems to always be equal to 7
IntPtr defaultStdout = new IntPtr(7);
IntPtr currentStdout = GetStdHandle(StdOutputHandle);

if (currentStdout != defaultStdout)
// reset stdout
SetStdHandle(StdOutputHandle, defaultStdout);

// reopen stdout
TextWriter writer = new StreamWriter(Console.OpenStandardOutput())
{ AutoFlush = true };
Console.SetOut(writer);
}

// P/Invoke required:
private const UInt32 StdOutputHandle = 0xFFFFFFF5;
[DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(UInt32 nStdHandle);
[DllImport("kernel32.dll")]
private static extern void SetStdHandle(UInt32 nStdHandle, IntPtr handle);
[DllImport("kernel32")]
static extern bool AllocConsole();
}

See How to detect if Console.In (stdin) has been redirected? for another way to detect if the console handles have been redirected.

Can not attach console

I was able to reproduce your issue and get it working on my machine. Some of your code looks like it comes from the accepted answer at No console output when using AllocConsole and target architecture x86. If you read the comment thread under that answer, you will see that new IntPtr(7) does not work as of Windows 7/ Server 2012. The "new magic number" for Windows 7 also did not work for me. To solve this, I started down the path of porting the given c++ call from the comments into c#, which required some signature changes for the PInvokes (which were all copied and pasted from PInvoke.net, so they should be fine). The changes that I made are almost exclusively in the PInvoke code. Here is a full working code set:

Program.cs (unchanged):

static void Main()
{
ServiceLauncher.RunService(() => new Service1());
}

ServiceLauncher.cs (unchanged):

public static void RunService(Func<ServiceBase> factory)
{
if (Debugger.IsAttached)
{
Utils.AttachConsole();
Console.Write($"Starting service ");
var instance = factory();
Console.WriteLine(instance.GetType().Name);
//Invoke start Method
Console.WriteLine("Press [ENTER] to exit");
Console.ReadLine();
//Stop service
}
else
{
ServiceBase.Run(factory());
}
}

Utils.cs (1 change as documemented in comments):

public static void AttachConsole()
{
var ret = NativeMethods.AllocConsole();
IntPtr currentStdout = NativeMethods.GetStdHandle(NativeMethods.STD_OUTPUT_HANDLE);

// IntPtr(7) was a dangerous assumption that doesn't work on current versions of Windows...
//NativeMethods.SetStdHandle(NativeMethods.STD_OUTPUT_HANDLE, new IntPtr(7));

// Instead, get the defaultStdOut using PInvoke
SafeFileHandle defaultStdOut = NativeMethods.CreateFile("CONOUT$", EFileAccess.GenericRead | EFileAccess.GenericWrite, EFileShare.Write, IntPtr.Zero, ECreationDisposition.OpenExisting, 0, IntPtr.Zero);
NativeMethods.SetStdHandle(NativeMethods.STD_OUTPUT_HANDLE, defaultStdOut.DangerousGetHandle()); // also seems dangerous... there may be an alternate signature for SetStdHandle that takes SafeFileHandle.

TextWriter writer = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true };
Console.SetOut(writer);
}

NativeMethods.cs (almost completely different - links and explanations given in comments). Enums included in this file (outside of the class scope) but can be moved to different files at your discretion:

internal static class NativeMethods
{
// 0xFFFFFFF5 is not consistent with what I found...
//internal const uint STD_OUTPUT_HANDLE = 0xFFFFFFF5;

// https://www.pinvoke.net/default.aspx/kernel32.getstdhandle
internal const int STD_OUTPUT_HANDLE = -11;

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool AllocConsole();

// method signature changed per https://www.pinvoke.net/default.aspx/kernel32.getstdhandle
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetStdHandle(int nStdHandle);

// method signature changed per https://www.pinvoke.net/default.aspx/kernel32.setstdhandle
[DllImport("kernel32.dll")]
internal static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern SafeFileHandle CreateFile(
string lpFileName,
EFileAccess dwDesiredAccess,
EFileShare dwShareMode,
IntPtr lpSecurityAttributes,
ECreationDisposition dwCreationDisposition,
EFileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);
}

// ENUMS FROM http://www.pinvoke.net/default.aspx/kernel32/CreateFile.html
[Flags]
public enum EFileAccess : uint
{
//
// Standart Section
//

AccessSystemSecurity = 0x1000000, // AccessSystemAcl access type
MaximumAllowed = 0x2000000, // MaximumAllowed access type

Delete = 0x10000,
ReadControl = 0x20000,
WriteDAC = 0x40000,
WriteOwner = 0x80000,
Synchronize = 0x100000,

StandardRightsRequired = 0xF0000,
StandardRightsRead = ReadControl,
StandardRightsWrite = ReadControl,
StandardRightsExecute = ReadControl,
StandardRightsAll = 0x1F0000,
SpecificRightsAll = 0xFFFF,

FILE_READ_DATA = 0x0001, // file & pipe
FILE_LIST_DIRECTORY = 0x0001, // directory
FILE_WRITE_DATA = 0x0002, // file & pipe
FILE_ADD_FILE = 0x0002, // directory
FILE_APPEND_DATA = 0x0004, // file
FILE_ADD_SUBDIRECTORY = 0x0004, // directory
FILE_CREATE_PIPE_INSTANCE = 0x0004, // named pipe
FILE_READ_EA = 0x0008, // file & directory
FILE_WRITE_EA = 0x0010, // file & directory
FILE_EXECUTE = 0x0020, // file
FILE_TRAVERSE = 0x0020, // directory
FILE_DELETE_CHILD = 0x0040, // directory
FILE_READ_ATTRIBUTES = 0x0080, // all
FILE_WRITE_ATTRIBUTES = 0x0100, // all

//
// Generic Section
//

GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000,

SPECIFIC_RIGHTS_ALL = 0x00FFFF,
FILE_ALL_ACCESS =
StandardRightsRequired |
Synchronize |
0x1FF,

FILE_GENERIC_READ =
StandardRightsRead |
FILE_READ_DATA |
FILE_READ_ATTRIBUTES |
FILE_READ_EA |
Synchronize,

FILE_GENERIC_WRITE =
StandardRightsWrite |
FILE_WRITE_DATA |
FILE_WRITE_ATTRIBUTES |
FILE_WRITE_EA |
FILE_APPEND_DATA |
Synchronize,

FILE_GENERIC_EXECUTE =
StandardRightsExecute |
FILE_READ_ATTRIBUTES |
FILE_EXECUTE |
Synchronize
}

[Flags]
public enum EFileShare : uint
{
/// <summary>
///
/// </summary>
None = 0x00000000,
/// <summary>
/// Enables subsequent open operations on an object to request read access.
/// Otherwise, other processes cannot open the object if they request read access.
/// If this flag is not specified, but the object has been opened for read access, the function fails.
/// </summary>
Read = 0x00000001,
/// <summary>
/// Enables subsequent open operations on an object to request write access.
/// Otherwise, other processes cannot open the object if they request write access.
/// If this flag is not specified, but the object has been opened for write access, the function fails.
/// </summary>
Write = 0x00000002,
/// <summary>
/// Enables subsequent open operations on an object to request delete access.
/// Otherwise, other processes cannot open the object if they request delete access.
/// If this flag is not specified, but the object has been opened for delete access, the function fails.
/// </summary>
Delete = 0x00000004
}

public enum ECreationDisposition : uint
{
/// <summary>
/// Creates a new file. The function fails if a specified file exists.
/// </summary>
New = 1,
/// <summary>
/// Creates a new file, always.
/// If a file exists, the function overwrites the file, clears the existing attributes, combines the specified file attributes,
/// and flags with FILE_ATTRIBUTE_ARCHIVE, but does not set the security descriptor that the SECURITY_ATTRIBUTES structure specifies.
/// </summary>
CreateAlways = 2,
/// <summary>
/// Opens a file. The function fails if the file does not exist.
/// </summary>
OpenExisting = 3,
/// <summary>
/// Opens a file, always.
/// If a file does not exist, the function creates a file as if dwCreationDisposition is CREATE_NEW.
/// </summary>
OpenAlways = 4,
/// <summary>
/// Opens a file and truncates it so that its size is 0 (zero) bytes. The function fails if the file does not exist.
/// The calling process must open the file with the GENERIC_WRITE access right.
/// </summary>
TruncateExisting = 5
}

[Flags]
public enum EFileAttributes : uint
{
Readonly = 0x00000001,
Hidden = 0x00000002,
System = 0x00000004,
Directory = 0x00000010,
Archive = 0x00000020,
Device = 0x00000040,
Normal = 0x00000080,
Temporary = 0x00000100,
SparseFile = 0x00000200,
ReparsePoint = 0x00000400,
Compressed = 0x00000800,
Offline = 0x00001000,
NotContentIndexed = 0x00002000,
Encrypted = 0x00004000,
Write_Through = 0x80000000,
Overlapped = 0x40000000,
NoBuffering = 0x20000000,
RandomAccess = 0x10000000,
SequentialScan = 0x08000000,
DeleteOnClose = 0x04000000,
BackupSemantics = 0x02000000,
PosixSemantics = 0x01000000,
OpenReparsePoint = 0x00200000,
OpenNoRecall = 0x00100000,
FirstPipeInstance = 0x00080000
}

Attaching Console to C# Windows Application with STDOUT Print Statements

AttachConsole doesn't quite behave the way you expect, what you need to do often is to AllocConsole and change your stdio handles to use that console.

The accepted answer for this question I can verify works in this scenario because I've used it: No console output when using AllocConsole and target architecture x86

Debugging a service via IDE

After some digging around I came up with a new class to suit my needs. Thanks for the post by Pavlo I was able to actually get text to read and write to the new console window I needed to create when one was not present.

My altered RunInteractive function from my original question:

private static void RunInteractive(ServiceBase[] servicesToRun)
{
//Account for running this application without a console window (debugging in IDE)
if (!ConsoleWindow.Exists() && !ConsoleWindow.Create())
return;

Console.WriteLine("Services running in interactive mode.");
Console.WriteLine();

MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ServiceBase service in servicesToRun)
{
Console.Write("Starting {0}...", service.ServiceName);
onStartMethod.Invoke(service, new object[] { new string[] { } });
Console.Write("Started");
}

Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Press any key to stop the services and end the process...");
Console.ReadKey();
Console.WriteLine();

MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ServiceBase service in servicesToRun)
{
Console.Write("Stopping {0}...", service.ServiceName);
onStopMethod.Invoke(service, null);
Console.WriteLine("Stopped");
}

//Keep the console alive for a second to allow the user to see the message.
Console.WriteLine("All services stopped.");
Thread.Sleep(1000);
}

Note: The only thing that was added here was this little bit at the top of the function.

//Account for running this application without a console window (debugging in IDE)
if (!ConsoleWindow.Exists() && !ConsoleWindow.Create())
return;

My new ConsoleWindow class:

using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

namespace crs.Includes
{
public class ConsoleWindow
{
#region Constants
private const UInt32 GENERIC_WRITE = 0x40000000;
private const UInt32 GENERIC_READ = 0x80000000;
private const UInt32 FILE_SHARE_READ = 0x00000001;
private const UInt32 FILE_SHARE_WRITE = 0x00000002;
private const UInt32 OPEN_EXISTING = 0x00000003;
private const UInt32 FILE_ATTRIBUTE_NORMAL = 0x80;
#endregion

#region WinAPI external functions
[DllImport("kernel32.dll")]
private static extern IntPtr GetConsoleWindow();

[DllImport(
"kernel32.dll",
SetLastError = true
)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FreeConsole();

[DllImport(
"kernel32.dll",
SetLastError = true
)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AllocConsole();

[DllImport(
"kernel32.dll",
EntryPoint = "CreateFileW",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall
)]
private static extern IntPtr CreateFileW(
string lpFileName,
UInt32 dwDesiredAccess,
UInt32 dwShareMode,
IntPtr lpSecurityAttributes,
UInt32 dwCreationDisposition,
UInt32 dwFlagsAndAttributes,
IntPtr hTemplateFil
);
#endregion

#region Public class methods
public static bool Exists()
{
if (GetConsoleWindow() == IntPtr.Zero)
return false;
else
return true;
}

public static bool Create()
{
try
{
if (!AllocConsole())
throw new Exception("Error! Could not get a lock on a console window and could not create one.");

InitializeOutStream();
InitializeInStream();

return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

return false;
}
#endregion

#region Functions
private static void InitializeOutStream()
{
FileStream fs = CreateFileStream("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, FileAccess.Write);
if (fs != null)
{
StreamWriter writer = new StreamWriter(fs) { AutoFlush = true };
Console.SetOut(writer);
Console.SetError(writer);
}
}

private static void InitializeInStream()
{
FileStream fs = CreateFileStream("CONIN$", GENERIC_READ, FILE_SHARE_READ, FileAccess.Read);
if (fs != null)
Console.SetIn(new StreamReader(fs));
}

private static FileStream CreateFileStream(string name, uint win32DesiredAccess, uint win32ShareMode, FileAccess dotNetFileAccess)
{
SafeFileHandle file = new SafeFileHandle(CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true);
if (!file.IsInvalid)
{
FileStream fs = new FileStream(file, dotNetFileAccess);
return fs;
}
return null;
}
#endregion
}
}

No output to console from a WPF application?

You'll have to create a Console window manually before you actually call any Console.Write methods. That will init the Console to work properly without changing the project type (which for WPF application won't work).

Here's a complete source code example, of how a ConsoleManager class might look like, and how it can be used to enable/disable the Console, independently of the project type.

With the following class, you just need to write ConsoleManager.Show() somewhere before any call to Console.Write...

[SuppressUnmanagedCodeSecurity]
public static class ConsoleManager
{
private const string Kernel32_DllName = "kernel32.dll";

[DllImport(Kernel32_DllName)]
private static extern bool AllocConsole();

[DllImport(Kernel32_DllName)]
private static extern bool FreeConsole();

[DllImport(Kernel32_DllName)]
private static extern IntPtr GetConsoleWindow();

[DllImport(Kernel32_DllName)]
private static extern int GetConsoleOutputCP();

public static bool HasConsole
{
get { return GetConsoleWindow() != IntPtr.Zero; }
}

/// <summary>
/// Creates a new console instance if the process is not attached to a console already.
/// </summary>
public static void Show()
{
//#if DEBUG
if (!HasConsole)
{
AllocConsole();
InvalidateOutAndError();
}
//#endif
}

/// <summary>
/// If the process has a console attached to it, it will be detached and no longer visible. Writing to the System.Console is still possible, but no output will be shown.
/// </summary>
public static void Hide()
{
//#if DEBUG
if (HasConsole)
{
SetOutAndErrorNull();
FreeConsole();
}
//#endif
}

public static void Toggle()
{
if (HasConsole)
{
Hide();
}
else
{
Show();
}
}

static void InvalidateOutAndError()
{
Type type = typeof(System.Console);

System.Reflection.FieldInfo _out = type.GetField("_out",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

System.Reflection.FieldInfo _error = type.GetField("_error",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

System.Reflection.MethodInfo _InitializeStdOutError = type.GetMethod("InitializeStdOutError",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

Debug.Assert(_out != null);
Debug.Assert(_error != null);

Debug.Assert(_InitializeStdOutError != null);

_out.SetValue(null, null);
_error.SetValue(null, null);

_InitializeStdOutError.Invoke(null, new object[] { true });
}

static void SetOutAndErrorNull()
{
Console.SetOut(TextWriter.Null);
Console.SetError(TextWriter.Null);
}
}

Calling AllocConsole & FreeConsole multiple times and keep In- & Output functionality of Console object in C# .NET

I found a way to simulate the above behaviour by not destroying the console I created before but instead simply hiding and displaying it again.

if (FirstTime)
{
FirstTime = false;
Win32Wrapper.SetStdHandle(Win32Wrapper.STD_OUTPUT_HANDLE, HWND.Zero);
Win32Wrapper.SetStdHandle(Win32Wrapper.STD_INPUT_HANDLE, HWND.Zero);
Win32Wrapper.AllocConsole(); // show implicitly
}
else
{
Console.Clear(); // clear => simulate new console
Win32Wrapper.ShowWindow(Win32Wrapper.GetConsoleWindow(), 5); // show (again)
}

Console.WriteLine("Hello World!");
Console.Read();
Console.ReadKey(true);

Win32Wrapper.ShowWindow(Win32Wrapper.GetConsoleWindow(), 0); // hide

Only the first function call allocates a new console further calls only show the already existing console again. All I need is a static variable to take track of it.



Related Topics



Leave a reply



Submit