AttachConsole (-1), но Console.WriteLine не будет выводиться в родительскую командную строку? - PullRequest
22 голосов
/ 08 ноября 2011

Если я установил свою программу на Windows Application и использовал AttachConsole(-1) API, как мне получить Console.WriteLine для записи в консоль, с которой я запустил приложение?Это не работает для меня.

В случае, если это актуально, я использую Windows 7 x64, и у меня включено UAC.Повышение, похоже, не решает проблему, равно как и использование start /wait.

Обновление

Некоторые дополнительные сведения, которые могут помочь:

Я только что обнаружил, что если я иду в командную строку и набираю cmd /c MyProgram.exe, , то консольный вывод работает .То же самое верно, если я запускаю командную строку, открываю подпроцесс cmd.exe и запускаю программу из этой вложенной оболочки.

Я также пытался выйти из системы и вернуться обратно, запустив изcmd.exe запускается из меню «Пуск» (в отличие от щелчка правой кнопкой мыши -> командная строка) и запускается из экземпляра console2 .Ничего из этого не работает.

Справочная информация

Я читал на других сайтах и ​​в нескольких SO-ответах, что я могу вызвать win32 API AttachConsole для привязки моей WindowsПриложение к консоли, на котором запущена моя программа, поэтому у меня может быть что-то «и консольное приложение, и приложение Windows».

Например, этот вопрос: Можно ли записать сообщение вcmd.exe в C # /. Net? .

Я написал кучу логики, чтобы сделать эту работу (используя несколько других API), и я получил все остальные сценарии для работы (включая перенаправление, который другие утверждали, не будет работать).Единственный оставшийся сценарий - заставить Console.WriteLine записать на консоль, с которой я запустил свою программу.Из всего, что я прочитал, это должно работать, если я использую AttachConsole.

Repro

Вот минимальный пример - Обратите внимание, что проект настроен на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);
}
  • Когда я запускаю это из командной строки, я не получаю сообщение об ошибке, но также не получаю никакого вывода на консоль. Это проблема
  • Если я добавлю дополнительные окна сообщений в любом месте потока выполнения приложения, появится окно сообщения.Я ожидаю этого, так что все хорошо здесь.
  • Когда я запускаю это из Visual Studio или дважды щелкаю по нему, появляется окно сообщения с ошибкой.Я ожидаю этого, так что не беспокойтесь здесь (буду использовать AllocConsole в моем реальном приложении).

Если я позвоню Marshal.GetLastWin32Error после вызова Console.WriteLine, я получу ошибку "Система.ComponentModel.Win32Exception (0x80004005): дескриптор недействителен ».Я подозреваю, что при подключении к консоли происходит сбой Console.Out, но я не уверен, как это исправить.

Ответы [ 10 ]

14 голосов
/ 08 ноября 2011

Вот как я это делаю в Winforms. Использование WPF было бы похоже.

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);
}
1 голос
/ 02 ноября 2014

Была такая же проблема.Все отлично работало, когда я запускал встроенный файл .exe, но не запускался внутри VS.

Решение:

  1. Проверка Включение процесса VS Hosting .
  2. Запустите VS от имени Администратор .

Возможно, это поможет другим людям решить эту проблему.

1 голос
/ 23 января 2013

Была такая же проблема, и кажется, что при запуске cmd.exe в Режим администратора AttachConsole() вызов успешен, но Console.Write() и Console.WriteLine() не работают. Если вы запускаете cmd.exe нормально (без прав администратора), кажется, все работает нормально.

0 голосов
/ 01 июня 2017

У меня была похожая проблема.Для компоновки вещей я использую WPF с PRISM, поэтому мне нужно также запретить создание «оболочки» в «режиме CLI», но я отвлекся ...

Это был единственныйвещь, которую я обнаружил, что в итоге сработало

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

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    private static extern IntPtr GetStdHandle(int nStdHandle);

    public static void InitConsole()
    {
        const int STD_OUTPUT_HANDLE = -11;

        AttachConsole(-1);

        var stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
        var safeFileHandle = new SafeFileHandle(stdHandle, true);
        var fileStream = new FileStream(safeFileHandle, FileAccess.Write);
        var standardOutput = new StreamWriter(fileStream) { AutoFlush = true };
        Console.SetOut(standardOutput);
        Console.WriteLine();
        Console.WriteLine("As seen on StackOverflow!");
    }

Все вызовы Console.WriteLine () выводятся в окно CLI после вызова InitConsole ()

Надеюсь, это поможет.

0 голосов
/ 27 декабря 2016

Та же проблема здесь.Я использовал gflags.exe (часть Средства отладки для Windows ), чтобы прикрепить приложение WPF командной строки к vsjitdebugger.exe (см. этот пост).Пока мое приложение было связано с vsjitdebugger.exe, вывод на консоль не производился.

С того момента, как я отсоединил свое приложение, вывод на консоль, откуда я запустил свое приложение, был восстановлен.

0 голосов
/ 26 сентября 2013
0 голосов
/ 25 марта 2013

У меня была та же проблема с текущей версией моего приложения (для .NET 4.0), но я уверен, что AttachConsole(-1) работал как и ожидалось в более ранних версиях (которые предназначались для .NET 2.0).

Я обнаружил, что могу получить консольный вывод, как только удаляю свой (настраиваемый) TraceListener из файла .exe.config моего приложения, хотя я пока не знаю, почему.

Возможно, это и есть то, что поглощает вывод вашей консоли ...

Обновление

На самом деле у меня был Console.WriteLine() в c'or моего пользовательского слушателя трассировки, который все испортил. После удаления этой строки вывод консоли после AttachConsole(-1) вернулся в нормальное состояние.

0 голосов
/ 19 ноября 2012

+ 1

У меня была такая же проблема. Вывод на консоль не будет отображаться с использованием различных вариантов AllocConsole или AttachConsole.

Проверьте, не отключили ли вы Включите хостинг Visual Studio в конфигурации вашего проекта. Включение этой опции волшебным образом заставляло все сообщения консоли отображаться как ожидалось для меня. Я использую VS2010 и .NET4, но этот пост предполагает, что «функция» все еще присутствует в VS2012.

0 голосов
/ 20 апреля 2012

У меня была похожая ситуация: не удалось заставить приложение Windows выводить что-либо на программно подключенную консоль. В конце концов оказалось, что я использовал Console.WriteLine один раз до AttachConsole, и это вмешивалось во все, что последовало после.

0 голосов
/ 08 ноября 2011

Я не вижу каких-либо существенных различий между нашими реализациями. Для того, что это стоит, ниже, что у меня есть в моем приложении, и он отлично работает. Я также создаю пример приложения WPF, и он также работал нормально.

Я подозреваю, что ваша проблема в другом месте. Извините, я не могу больше помочь.

[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);
...