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
, чтобы запутаться, но я не уверен, как это исправить.
Ответы
Ответ 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)
вернулся в нормальное состояние.
Ответ 7
DETACHED_PROCESS and CREATE_NEW_CONSOLE
является проблемой здесь.
см. fooobar.com/questions/79895/...
Ответ 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().
Надеюсь, что это поможет.