AttachConsole(-1), but Console.WriteLine won't

2019-03-08 20:28发布

If I have set my program to be a Windows Application, and used the AttachConsole(-1) API, how do I get Console.WriteLine to write to the console I launched the application from? It isn't working for me.

In case it is relevant, I'm using Windows 7 x64, and I have UAC enabled. Elevating doesn't seem to solve the problem though, nor does using start /wait.

Update

Some additional background that might help:

I've just discovered that if I go to the command prompt and type cmd /c MyProgram.exe, Then console output works. The same is true if I launch a command prompt, open a cmd.exe sub-process, and run the program from that sub-shell.

I've also tried logging out and back in, running from a cmd.exe launched from the start menu (as opposed to right-click -> command prompt), and running from a console2 instance. None of those work.

Background

I've read on other sites and in several SO answers that I can call the win32 API AttachConsole to bind my Windows Application to the console that ran my program, so I can have something that is "both a console application, and a Windows application".

For example, this question: Is it possible to log message to cmd.exe in C#/.Net?.

I've written a bunch of logic to make this work (using several other APIs), and I have gotten every other scenario to work (including redirection, which others have claimed won't work). The only scenario left is to get Console.WriteLine to write to the console I launched my program with. From everything I've read this is supposed to work if I use AttachConsole.

Repro

Here's a minimal sample - Note that the project is set to be a Windows Application:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;

class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        if (!AttachConsole(-1))
        {
            MessageBox.Show(
                new Win32Exception(Marshal.GetLastWin32Error())
                    .ToString()
                );
        }

        Console.WriteLine("Test");
    }

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    private static extern bool AttachConsole(int processId);
}
  • When I run this from a command prompt, I don't get an error, but I don't get any console output either. This is the problem
  • If I add extra message boxes anywhere in the execution flow of the app, the message box gets displayed. I expect this, so all good here.
  • When I run this from Visual Studio or by double clicking on it, a message box with an error is displayed. I expect this, so no worries here (will use AllocConsole in my real app).

If I call Marshal.GetLastWin32Error after the call to Console.WriteLine, I get the error "System.ComponentModel.Win32Exception (0x80004005): The handle is invalid". I suspect that attaching to the console is causing Console.Out to get messed up, but I'm not sure how to fix it.

10条回答
We Are One
2楼-- · 2019-03-08 20:42

I cannot see any significant difference between our implementations. For what it is worth, below is what I have in my application and it works fine. I also create a sample WPF application and it also worked fine.

I suspect that your issue is elsewhere. Sorry I couldn't be more help.

[STAThread]
public static void Main()
{            
    AttachProcessToConsole();    
}

private static void AttachProcessToConsole()
{
    AttachConsole(-1);
}

// Attaches the calling process to the console of the specified process.
// http://msdn.microsoft.com/en-us/library/ms681952%28v=vs.85%29.aspx
[DllImport("Kernel32.dll")]
private static extern bool AttachConsole(int processId);
查看更多
我命由我不由天
3楼-- · 2019-03-08 20:44

I was suffering from the same problem with my application's current version (targeting .NET 4.0) but am sure AttachConsole(-1) did work as expected in earlier versions (which targeted .NET 2.0).

I found that I could get console output as soon as I removed my (custom) TraceListener from my application's .exe.config file, even though I don't know why yet.

Perhaps this is what's swallowing your console output as well...

Update

In fact I had a Console.WriteLine() in my custom trace listener's c'tor which was messing things up. After removing this line, console output after AttachConsole(-1) went back to normal.

查看更多
时光不老,我们不散
4楼-- · 2019-03-08 20:47

Had the same problem and it appears that when running cmd.exe in Administrator mode AttachConsole() call succeeds but Console.Write() and Console.WriteLine() don't work. If you run cmd.exe normally (non-admin) everything seems to work fine.

查看更多
再贱就再见
5楼-- · 2019-03-08 20:48

This is how I do it in Winforms. Using WPF would be similar.

static class SybilProgram
{
    [STAThread]
    static void Main(string[] args)
    {
        if (args.Length > 0)
        {
            // Command line given, display console
            if ( !AttachConsole(-1) )  // Attach to a parent process console
                AllocConsole(); // Alloc a new console if none available


            ConsoleMain(args);
        }
        else
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());  // instantiate the Form
        }
    }

    private static void ConsoleMain(string[] args)
    {
        Console.WriteLine("Command line = {0}", Environment.CommandLine);
        for (int ix = 0; ix < args.Length; ++ix)
            Console.WriteLine("Argument{0} = {1}", ix + 1, args[ix]);
        Console.ReadLine();
    }

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern bool AllocConsole();

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern bool AttachConsole(int pid);
}
查看更多
\"骚年 ilove
6楼-- · 2019-03-08 20:49

Same problem here. I was using gflags.exe, (part of Debugging Tools for Windows) to attach a commandline WPF application to vsjitdebugger.exe (See this post). As long as my application was coupled with vsjitdebugger.exe, no output was written to the console.

From the moment I detached my application, output to the console, from where I launched my application, was restored.

查看更多
女痞
7楼-- · 2019-03-08 20:50

I had a similar situation: could not get a Windows Application to output anything in the programmatically attached console. Eventually, it turned out that I was using Console.WriteLine once before AttachConsole, and that was tampering with everything that followed after.

查看更多
登录 后发表回答