Żaden z wcześniejszych odpowiedzi pracował dobrze dla mnie z VS2017 i Windows 10 (na przykład, że nie powiodło się, jeśli aplikacja uruchomi się w trybie debugowania).
Poniżej można znaleźć kod wzmocnionej trochę. Idea jest taka sama, ale magiczne liczby są usuwane (Ceztko już o tym wspomniała) i wszystkie niezbędne w \ out strumieniach są inicjowane.
Ten kod działa dla mnie, czy utworzyć nową konsolę (alwaysCreateNewConsole = true).
Mocowanie konsolę procesu macierzystego (alwaysCreateNewConsole = fałsz) ma kilka wad. Na przykład nie mogłem całkowicie naśladować zachowania aplikacji konsolowej uruchamianej z cmd. I nie jestem pewien, czy to w ogóle możliwe.
I najważniejsze: po rewizji Console class I rozważyć ogólną ideę korzystania z utworzonej klasy Console ręcznie konsoli. Działa dobrze (mam nadzieję) w większości przypadków, ale może przynieść wiele bólu w przyszłości.
static class WinConsole
{
static public void Initialize(bool alwaysCreateNewConsole = true)
{
bool consoleAttached = true;
if (alwaysCreateNewConsole
|| (AttachConsole(ATTACH_PARRENT) == 0
&& Marshal.GetLastWin32Error() != ERROR_ACCESS_DENIED))
{
consoleAttached = AllocConsole() != 0;
}
if (consoleAttached)
{
InitializeOutStream();
InitializeInStream();
}
}
private static void InitializeOutStream()
{
var fs = CreateFileStream("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, FileAccess.Write);
if (fs != null)
{
var writer = new StreamWriter(fs) { AutoFlush = true };
Console.SetOut(writer);
Console.SetError(writer);
}
}
private static void InitializeInStream()
{
var 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)
{
var file = new SafeFileHandle(CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true);
if (!file.IsInvalid)
{
var fs = new FileStream(file, dotNetFileAccess);
return fs;
}
return null;
}
#region Win API Functions and Constants
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();
[DllImport("kernel32.dll",
EntryPoint = "AttachConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern UInt32 AttachConsole(UInt32 dwProcessId);
[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 hTemplateFile
);
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;
private const UInt32 ERROR_ACCESS_DENIED = 5;
private const UInt32 ATTACH_PARRENT = 0xFFFFFFFF;
#endregion
}
Sprawdź w oknie Wyjście wyjątek "Pierwsza szansa". –
@HansPassant: Nie, nie ma wyjątków, ale twój komentarz pomógł mi znaleźć rozwiązanie (częściowe): Kiedy otwieram plik .exe bezpośrednio, to działa, ale kiedy debuguję moje rozwiązanie, wszystkie dane wyjściowe przechodzą do widoku "Wyjście" w VS. Ale wciąż są tu dwa pytania: Dlaczego tylko z x86 i jak można uzyskać wyjście konsoli podczas debugowania mojego rozwiązania? (Jeszcze +1 dla Ciebie: D) – teamalpha5441