Я наконец-то понял, как прозрачно прикрепить к консоли, если это окно переднего плана при запуске приложения Windows.
Не спрашивайте меня, почему STD_ERROR_HANDLE должен быть передан вместо STD_OUTPUT_HANDLE, но он просто работаетВозможно, из-за того, что стандартной ошибкой можно поделиться.
Примечание: консоль может принимать пользовательский ввод при отображении сообщений вашего приложения внутри, но использовать его во время вывода stderr из вашего приложения немного запутанно.
С помощью этого фрагмента кода, если вы запустите свое приложение из окна консоли с хотя бы одним параметром, оно присоединит к нему Console.Write, а если вы запустите приложение с параметром / debug, то оно присоединит дажеDebug.Write на консоль.
Вызовите Cleanup () перед выходом из приложения, чтобы освободить консоль, и отправьте клавишу Enter, чтобы освободить последнюю строку, чтобы консоль можно было использовать, как и до запуска приложения.
PS.Вы не можете использовать перенаправление вывода с этим методом, т. Е. Yourapp.exe> file.txt, потому что вы получите пустой файл.И даже не пытайтесь использовать myapp.exe> file.txt 2> & 1, потому что вы можете вызвать сбой приложения (перенаправление ошибки на выход означает, что мы пытаемся подключиться к несделенному буферу).
Вот код:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[DllImport("kernel32.dll",
EntryPoint = "GetStdHandle",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool FreeConsole();
private const int STD_OUTPUT_HANDLE = -11;
private const int STD_ERROR_HANDLE = -12;
private static bool _consoleAttached = false;
private static IntPtr consoleWindow;
[STAThread]
static void Main()
{
args = new List<string>(Environment.GetCommandLineArgs());
int prId;
consoleWindow = GetForegroundWindow();
GetWindowThreadProcessId(consoleWindow, out prId);
Process process = Process.GetProcessById(prId);
if (args.Count > 1 && process.ProcessName == "cmd")
{
if (AttachConsole((uint)prId)) {
_consoleAttached = true;
IntPtr stdHandle = GetStdHandle(STD_ERROR_HANDLE); // must be error dunno why
SafeFileHandle safeFileHandle = new SafeFileHandle(stdHandle, true);
FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write);
Encoding encoding = Encoding.ASCII;
StreamWriter standardOutput = new StreamWriter(fileStream, encoding);
standardOutput.AutoFlush = true;
Console.SetOut(standardOutput);
if (args.Contains("/debug")) Debug.Listeners.Add(new TextWriterTraceListener(Console.Out));
Console.WriteLine(Application.ProductName + " was launched from a console window and will redirect output to it.");
}
}
// ... do whatever, use console.writeline or debug.writeline
// if you started the app with /debug from a console
Cleanup();
}
private static void Cleanup() {
try
{
if (_consoleAttached)
{
SetForegroundWindow(consoleWindow);
SendKeys.SendWait("{ENTER}");
FreeConsole();
}
}
}