Подтвердить что ты не робот

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

Если я установил свою программу как Windows Application и использовал API AttachConsole(-1), как мне получить 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 в С#/. Net?.

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

Репро

Здесь минимальная выборка. Обратите внимание, что для проекта задано значение 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, я получаю сообщение об ошибке "System.ComponentModel.Win32Exception (0x80004005): дескриптор недействителен". Я подозреваю, что присоединение к консоли вызывает Console.Out, чтобы запутаться, но я не уверен, как это исправить.

4b9b3361

Ответ 1

Вот как я это делаю в 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);
}

Ответ 2

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

Ответ 3

Я не вижу существенной разницы между нашими реализациями. Для чего это стоит, ниже - то, что у меня есть в моем приложении, и оно отлично работает. Я также создаю образец приложения 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);

Ответ 4

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

Ответ 5

+ 1

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

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

Ответ 6

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

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

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

Обновление

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

Ответ 8

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

Решение:

  • Проверить Включить процесс хостинга VS.
  • Запустите VS как администратор.

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

Ответ 9

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

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

Ответ 10

У меня была аналогичная проблема. Чтобы усугубить ситуацию, я использую WPF w/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().

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