You may wish to enable your WinForms application to run from a console window or command line. And when it does, you probably want to send output messages to the console window that launched your WinForms application.
Unfortunately Console.WriteLine()–the standard method of writing to the console window–by default will not work from a WinForms application. That’s because the console window that launched your WinForms application belongs to the cmd.exe process, which is separate from your WinForms application process.
So to redirect output from a WinForms application to the console window that launched it, use the AttachConsole Win32 method introduced in Windows XP. AttachConsole attaches the current process to the console window of another process. The special parameter ATTACH_PARENT_PROCESS attaches to the parent process, which in this case is the console window that launched the WinForms application.
Simple Example
Following is a simple WinForms application that redirects its output to the console window that launched it:
using System; using System.Runtime.InteropServices; using System.Windows.Forms; namespace MyWinFormsApp { static class Program { [DllImport( "kernel32.dll" )] static extern bool AttachConsole( int dwProcessId ); private const int ATTACH_PARENT_PROCESS = -1; [STAThread] static void Main( string[] args ) { // redirect console output to parent process; // must be before any calls to Console.WriteLine() AttachConsole( ATTACH_PARENT_PROCESS ); // to demonstrate where the console output is going int argCount = args == null ? 0 : args.Length; Console.WriteLine( "nYou specified {0} arguments:", argCount ); for (int i = 0; i < argCount; i++) { Console.WriteLine( " {0}", args[i] ); } // launch the WinForms application like normal Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault( false ); Application.Run( new Form1() ); } } }
One Gotcha
There is one problem with this approach. If you redirect the console window output to a text file, for example using the redirect arrow:
MyWinFormsApp.exe >output.txt arg1 arg2
In this case, output will not redirect to the “output.txt” text file as expected, but instead will continue to appear in the console window. Please comment if you have a solution to this issue.
Thanks for the how-to, it really helped me out. I haven’t found a solution to your gotcha, but I have another gotcha to tack on.
While this solution successfully redirects output to the console, it doesn’t seem to “grab” the console’s full attention. That is to say, as soon as my application has loaded, the console drops down and represents the command prompt. Even as output is being printed out from my program to the console, I can navigate folders, run other applications, etc. from the same instance of cmd.exe. For my purposes, this isn’t a huge deal, just something I noticed.
Thanks again for the post.
Though the reason is not palpable, but the solution works…
Nicely done….
Thanks so much…
Lalit.
Hello!
I think this try.
Microsoft sux… how can this not be standard??
Really nice =)
Does this change the prompt style if you run it from a cmd.exe window? It might be something else I’m doing, that I only noticed after finding your (very helpful!) tutorial…?
Brian,
I noticed the same behavior as well. I also noticed that my application doesn’t properly exit. The enter key must be pressed ey before the application will exit.
Though I thank and commend the writer for his efforts, I cannot honestly say that this was “nicely done” as some others have stated.
There has to be another way to achieve console output from a C# Windows Application. I’ll find it :o)
CupOfJoe,
you don’t have to press any key to exit the app. It’s just that console output of WinForms apps isn’t handled synchronously by the Windows command processor cmd.exe. So cmd.exe will print its own user prompt (“C:whatever>”) before the console output of the WinForms app. On my machine, it looks like this:
C:test>MyWinFormsApp.exe
C:test>
You specified 0 arguments:
_ start “” /WAIT MyWinFormsApp.exe
or
C:test>cmd /c MyWinFormsApp.exe
Sorry, my last post what somehow messed up at the end. I’ll try again:
…
On my machine, it looks like this:
C:test>MyWinFormsApp.exe
C:test>
You specified 0 arguments:
_ {=cursor blinks here
So while it may look like the app isn’t finished yet, it actually is. Try entering “dir”, and you’ll see.
To make cmd.exe wait for the WinFormsApp to finish, try:
C:test>start “” /WAIT MyWinFormsApp.exe
or
C:test>cmd /c MyWinFormsApp.exe
I might have found a solution to your “gotcha”. It involves duplicating the original Stdout / Stderr handles before calling “AttachConsole()” and resetting them afterwards.
static class Program
{
[DllImport(“kernel32.dll”)]
static extern bool AttachConsole(UInt32 dwProcessId);
[DllImport(“kernel32.dll”)]
private static extern bool GetFileInformationByHandle(SafeFileHandle hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);
[DllImport(“kernel32.dll”)]
private static extern SafeFileHandle GetStdHandle(UInt32 nStdHandle);
[DllImport(“kernel32.dll”)]
private static extern bool SetStdHandle(UInt32 nStdHandle, SafeFileHandle hHandle);
[DllImport(“kernel32.dll”)]
private static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, SafeFileHandle hSourceHandle, IntPtr hTargetProcessHandle,
out SafeFileHandle lpTargetHandle, UInt32 dwDesiredAccess, Boolean bInheritHandle, UInt32 dwOptions);
private const UInt32 ATTACH_PARENT_PROCESS = 0xFFFFFFFF;
private const UInt32 STD_OUTPUT_HANDLE = 0xFFFFFFF5;
private const UInt32 STD_ERROR_HANDLE = 0xFFFFFFF4;
private const UInt32 DUPLICATE_SAME_ACCESS = 2;
struct BY_HANDLE_FILE_INFORMATION
{
public UInt32 FileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
public UInt32 VolumeSerialNumber;
public UInt32 FileSizeHigh;
public UInt32 FileSizeLow;
public UInt32 NumberOfLinks;
public UInt32 FileIndexHigh;
public UInt32 FileIndexLow;
}
static void InitConsoleHandles()
{
SafeFileHandle hStdOut, hStdErr, hStdOutDup, hStdErrDup;
BY_HANDLE_FILE_INFORMATION bhfi;
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
hStdErr = GetStdHandle(STD_ERROR_HANDLE);
// Get current process handle
IntPtr hProcess = Process.GetCurrentProcess().Handle;
// Duplicate Stdout handle to save initial value
DuplicateHandle(hProcess, hStdOut, hProcess, out hStdOutDup,
0, true, DUPLICATE_SAME_ACCESS);
// Duplicate Stderr handle to save initial value
DuplicateHandle(hProcess, hStdErr, hProcess, out hStdErrDup,
0, true, DUPLICATE_SAME_ACCESS);
// Attach to console window – this may modify the standard handles
AttachConsole(ATTACH_PARENT_PROCESS);
// Adjust the standard handles
if (GetFileInformationByHandle(GetStdHandle(STD_OUTPUT_HANDLE), out bhfi))
{
SetStdHandle(STD_OUTPUT_HANDLE, hStdOutDup);
}
else
{
SetStdHandle(STD_OUTPUT_HANDLE, hStdOut);
}
if (GetFileInformationByHandle(GetStdHandle(STD_ERROR_HANDLE), out bhfi))
{
SetStdHandle(STD_ERROR_HANDLE, hStdErrDup);
}
else
{
SetStdHandle(STD_ERROR_HANDLE, hStdErr);
}
}
[STAThread]
static void Main(string[] args)
{
// initialize console handles
InitConsoleHandles();
// to demonstrate where the console output is going
int argCount = args == null ? 0 : args.Length;
Console.WriteLine(“You specified {0} arguments:”, argCount);
Console.Error.WriteLine(“This is the error channel”);
for (int i = 0; i < argCount; i++)
{
Console.WriteLine(” {0}”, args[i]);
}
}
}
Hi Hartmut Honisch,
This is working greatly in my test application. after i add it in to my original application it is not working. why its behaving like this working in one application, not working in another.
First off, great post thanks, it has helped a lot so far.
Hopefully it is not so old, as to have died! In response to the post by Hartmut Honisch, I have a quick question/favour to ask.
Do you have any solutions to the problem posted by CupOfJoe, where as the enter key must be pressed before the application will exit?
I have one potential solution which is to use:
System.Windowns.Forms.SendKeys.SendWait(“{ENTER}”);
after you have finished with your app/printing to the console. However this adds in an extra line if you output via batch or stream to file.
eg: C:>myapp.exe -help > dump.txt
will give an output of
C:>
C:>[Cursor here]
So as a solution, do you know if we could detect if the app was run via batch or the commandline, or if it streamed (piped?) to the console or file?
Then we could trigger if the System.Windowns.Forms.SendKeys.SendWait(“{ENTER}”) event needs to be fired.
Any ideas would be great.
Here is my sample program.cs file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace ConsoleOutTesting
{
static class Program
{
#region Stuff used to attach a command window to the win forms exe
[DllImport("kernel32.dll")]
static extern bool AttachConsole(UInt32 dwProcessId);
[DllImport("kernel32.dll")]
static extern bool FreeConsole();
[DllImport("kernel32.dll")]
private static extern bool GetFileInformationByHandle(SafeFileHandle hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);
[DllImport("kernel32.dll")]
private static extern SafeFileHandle GetStdHandle(UInt32 nStdHandle);
[DllImport("kernel32.dll")]
private static extern bool SetStdHandle(UInt32 nStdHandle, SafeFileHandle hHandle);
[DllImport("kernel32.dll")]
private static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, SafeFileHandle hSourceHandle, IntPtr hTargetProcessHandle,
out SafeFileHandle lpTargetHandle, UInt32 dwDesiredAccess, Boolean bInheritHandle, UInt32 dwOptions);
private const UInt32 ATTACH_PARENT_PROCESS = 0xFFFFFFFF;
private const UInt32 STD_OUTPUT_HANDLE = 0xFFFFFFF5;
private const UInt32 STD_ERROR_HANDLE = 0xFFFFFFF4;
private const UInt32 DUPLICATE_SAME_ACCESS = 2;
static SafeFileHandle hStdOut, hStdErr, hStdOutDup, hStdErrDup;
static BY_HANDLE_FILE_INFORMATION bhfi;
private struct BY_HANDLE_FILE_INFORMATION
{
public UInt32 FileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
public UInt32 VolumeSerialNumber;
public UInt32 FileSizeHigh;
public UInt32 FileSizeLow;
public UInt32 NumberOfLinks;
public UInt32 FileIndexHigh;
public UInt32 FileIndexLow;
}
private static void InitConsoleHandles()
{
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
hStdErr = GetStdHandle(STD_ERROR_HANDLE);
// Get current process handle
IntPtr hProcess = Process.GetCurrentProcess().Handle;
// Duplicate Stdout handle to save initial value
DuplicateHandle(hProcess, hStdOut, hProcess, out hStdOutDup,
0, true, DUPLICATE_SAME_ACCESS);
// Duplicate Stderr handle to save initial value
DuplicateHandle(hProcess, hStdErr, hProcess, out hStdErrDup,
0, true, DUPLICATE_SAME_ACCESS);
// Attach to console window – this may modify the standard handles
AttachConsole(ATTACH_PARENT_PROCESS);
// Adjust the standard handles
if (GetFileInformationByHandle(GetStdHandle(STD_OUTPUT_HANDLE), out bhfi))
{
SetStdHandle(STD_OUTPUT_HANDLE, hStdOutDup);
}
else
{
SetStdHandle(STD_OUTPUT_HANDLE, hStdOut);
}
if (GetFileInformationByHandle(GetStdHandle(STD_ERROR_HANDLE), out bhfi))
{
SetStdHandle(STD_ERROR_HANDLE, hStdErrDup);
}
else
{
SetStdHandle(STD_ERROR_HANDLE, hStdErr);
}
Console.WriteLine("");
}
private static void ReleaseConsoleHandles()
{
SendKeys.SendWait("{ENTER}");
FreeConsole();
}
#endregion
///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args)
{
if (args.Length == 1 && args[0] == "-help")
{
InitConsoleHandles();
Console.WriteLine("MyApp help is this");
ReleaseConsoleHandles();
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
}
Thanks.
Jonathan.
Jonathan, this is the code I’m using to know if the app is run from cmd.exe:
char Title[MAX_PATH] = “”;
if(GetConsoleTitle(Title, MAX_PATH) &&
strcmp(&Title[strlen(Title) – 7], “cmd.exe”) == 0)
{
// Launch by cmd.exe
}
You might want to add some protection:
char Title[MAX_PATH] = “”;
if(GetConsoleTitle(Title, MAX_PATH) && strlen(Title) >= 7 && strcmp(&Title[strlen(Title) – 7], “cmd.exe”) != 0)
{
// Launched by cmd.exe
}
Thanks Crayon for your post. I have modified what you have posted to fit my situation but unfortunately I can’t seem to get GetConsoleTitle to work! The error code I get is 183, “Cannot create a file when that file already exists.” and I have no idea why! The string builder comes back empty.
I have followed this post http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=109 to use the GetConsoleTitle, but I can’t seem to get it to work.
My code for the main function is currently this:
StringBuilder sb = new StringBuilder(1000000);
UInt32 buffSize = (UInt32)sb.Capacity;
UInt32 titleLen = GetConsoleTitle(sb, buffSize);
if (titleLen > 0 &&
(sb.ToString().Substring(sb.Length – 7, 7) == “cmd.exe”))
{
//LaunchedByCmdexe = true;
}
if (args.Length == 1 && args[0] == “-help”)
{
InitConsoleHandles();
Console.WriteLine(“MyApp help is this”);
ReleaseConsoleHandles();
}
else
{
Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
Any ideas? Thanks.
Jonathan, in my code I’m calling GetConsoleTitle after
AttachConsole(ATTACH_PARENT_PROCESS).
For the rest, I can’t really help you. I never programmed in .NET. That’s why the code pasted above is in C/C++.
Good luck…
Hi Crayon, Thanks, I tried putting GetConsoleTitle after the AttachConsole call, but no luck so far, still the same error.
I’ll keep looking for an answer and post it here if I find one.
Cheers.
This seems to work well for my needs. Greatly appreciated.
Jonathan,
You are simply a genius da!!!!
If you attach the Standard input with the output and error then you won’t have to use the sendkeys command and it will fix the issue with not grabbing the attention of the entire console. I edited the code posted above to the following:
[DllImport(“kernel32.dll”)]
static extern bool AttachConsole(UInt32 dwProcessId);
[DllImport(“kernel32.dll”)]
static extern bool FreeConsole();
[DllImport(“kernel32.dll”)]
static extern bool AllocConsole();
[DllImport(“kernel32.dll”)]
private static extern bool GetFileInformationByHandle(SafeFileHandle hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);
[DllImport(“kernel32.dll”)]
private static extern SafeFileHandle GetStdHandle(UInt32 nStdHandle);
[DllImport(“kernel32.dll”)]
private static extern bool SetStdHandle(UInt32 nStdHandle, SafeFileHandle hHandle);
[DllImport(“kernel32.dll”)]
private static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, SafeFileHandle hSourceHandle, IntPtr hTargetProcessHandle,
out SafeFileHandle lpTargetHandle, UInt32 dwDesiredAccess, Boolean bInheritHandle, UInt32 dwOptions);
private const UInt32 ATTACH_PARENT_PROCESS = 0xFFFFFFFF;
private const UInt32 STD_INPUT_HANDLE = 0xFFFFFFF6;
private const UInt32 STD_OUTPUT_HANDLE = 0xFFFFFFF5;
private const UInt32 STD_ERROR_HANDLE = 0xFFFFFFF4;
private const UInt32 DUPLICATE_SAME_ACCESS = 2;
static SafeFileHandle hStdIn, hStdOut, hStdErr, hStdOutDup, hStdErrDup, hStdInDup;
static BY_HANDLE_FILE_INFORMATION bhfi;
private struct BY_HANDLE_FILE_INFORMATION
{
public UInt32 FileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
public UInt32 VolumeSerialNumber;
public UInt32 FileSizeHigh;
public UInt32 FileSizeLow;
public UInt32 NumberOfLinks;
public UInt32 FileIndexHigh;
public UInt32 FileIndexLow;
}
private static void InitConsoleHandles()
{
hStdIn = GetStdHandle(STD_INPUT_HANDLE);
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
hStdErr = GetStdHandle(STD_ERROR_HANDLE);
// Get current process handle
IntPtr hProcess = Process.GetCurrentProcess().Handle;
// Duplicate Stdout handle to save initial value
DuplicateHandle(hProcess, hStdIn, hProcess, out hStdInDup, 0, true, DUPLICATE_SAME_ACCESS);
// Duplicate Stdout handle to save initial value
DuplicateHandle(hProcess, hStdOut, hProcess, out hStdOutDup, 0, true, DUPLICATE_SAME_ACCESS);
// Duplicate Stderr handle to save initial value
DuplicateHandle(hProcess, hStdErr, hProcess, out hStdErrDup, 0, true, DUPLICATE_SAME_ACCESS);
// Attach to console window – this may modify the standard handles
AttachConsole(ATTACH_PARENT_PROCESS);
//AllocConsole();
// Adjust the standard handles
if (GetFileInformationByHandle(GetStdHandle(STD_INPUT_HANDLE), out bhfi))
{
SetStdHandle(STD_INPUT_HANDLE, hStdInDup);
}
else
{
SetStdHandle(STD_INPUT_HANDLE, hStdIn);
}
if (GetFileInformationByHandle(GetStdHandle(STD_OUTPUT_HANDLE), out bhfi))
{
SetStdHandle(STD_OUTPUT_HANDLE, hStdOutDup);
}
else
{
SetStdHandle(STD_OUTPUT_HANDLE, hStdOut);
}
if (GetFileInformationByHandle(GetStdHandle(STD_ERROR_HANDLE), out bhfi))
{
SetStdHandle(STD_ERROR_HANDLE, hStdErrDup);
}
else
{
SetStdHandle(STD_ERROR_HANDLE, hStdErr);
}
}
private static void ReleaseConsoleHandles()
{
FreeConsole();
}
Hi all,
I have developed a C# Windows application and I need to add command line support for it. Using the AttachConsole method I succeeded to output messages from the application to the console window that launched the application.
The problem is that the console also prints the user prompt (“C:[path]>”) before the apllication messages are printed.
Is there any way to avoid printing the user prompt? I just want to output my messages from the Windows application directly to the cursor location.
Just an FYI, this may not be a huge concern, I’ve noticed that when ran from a batch file, this solution works well which was the point of me adding cmd line functionality, so I’m happy, although obviously I still want “perfect” 🙂
Perfect – just what I needed! (I don’t mind the dumping to txt file issue)
reverse it create a winform app,
process commandline arguments and specify in the properties of you project that it is a console app.
http://csharpdeveloper.wordpress.com/2010/03/09/run-the-same-c-program-in-a-console-or-a-windows-form/
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Text;
namespace QDB
{
static class Program
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args)
{
bool NoGui = false;
string name = “”;
int number = 0;
for (int i = 0; i != args.Length; ++i)
{
switch (args[i])
{
case “/NoGui”: NoGui = true; break;
case “/name” : name = args[++i]; break;
case “/number”: number = int.Parse(args[++i]); break;
default: Console.WriteLine(“Invalid args!”); return;
}
}
if (!NoGui)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmAppMain());
}
else
{
foreach (string arg in args)
{
Console.WriteLine(” the vars: {0}”, arg);
}
Console.ReadLine();
}
}
}
}
Many thanks to winform,Hartmut Honisch,Jonathan Counihan and of course Timm.
I combined your logic and code…Below is what you wanted!
Test Run:-
1)d:>ConsoleTest.exe
RESULT:- Opens up only GUI.
2)d:>ConsoleTest.exe /NoGui
RESULT:- Opens up only Console.
3)d:>ConsoleTest.exe /NoGui 1>a.txt 2>b.txt
RESULT:- Opens up only Console. It redirect standard output to a.txt and standard error to b.txt
—————————————————————————————————————–
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.Win32.SafeHandles;
using System.Diagnostics;
namespace ConsoleTest
{
static class Program
{
[DllImport(“kernel32.dll”)]
static extern bool AttachConsole(UInt32 dwProcessId);
[DllImport(“kernel32.dll”)]
private static extern bool GetFileInformationByHandle(SafeFileHandle hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);
[DllImport(“kernel32.dll”)]
private static extern SafeFileHandle GetStdHandle(UInt32 nStdHandle);
[DllImport(“kernel32.dll”)]
private static extern bool SetStdHandle(UInt32 nStdHandle, SafeFileHandle hHandle);
[DllImport(“kernel32.dll”)]
private static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, SafeFileHandle hSourceHandle, IntPtr hTargetProcessHandle,
out SafeFileHandle lpTargetHandle, UInt32 dwDesiredAccess, Boolean bInheritHandle, UInt32 dwOptions);
private const UInt32 ATTACH_PARENT_PROCESS = 0xFFFFFFFF;
private const UInt32 STD_OUTPUT_HANDLE = 0xFFFFFFF5;
private const UInt32 STD_ERROR_HANDLE = 0xFFFFFFF4;
private const UInt32 DUPLICATE_SAME_ACCESS = 2;
struct BY_HANDLE_FILE_INFORMATION
{
public UInt32 FileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
public UInt32 VolumeSerialNumber;
public UInt32 FileSizeHigh;
public UInt32 FileSizeLow;
public UInt32 NumberOfLinks;
public UInt32 FileIndexHigh;
public UInt32 FileIndexLow;
}
static void InitConsoleHandles()
{
SafeFileHandle hStdOut, hStdErr, hStdOutDup, hStdErrDup;
BY_HANDLE_FILE_INFORMATION bhfi;
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
hStdErr = GetStdHandle(STD_ERROR_HANDLE);
// Get current process handle
IntPtr hProcess = Process.GetCurrentProcess().Handle;
// Duplicate Stdout handle to save initial value
DuplicateHandle(hProcess, hStdOut, hProcess, out hStdOutDup,
0, true, DUPLICATE_SAME_ACCESS);
// Duplicate Stderr handle to save initial value
DuplicateHandle(hProcess, hStdErr, hProcess, out hStdErrDup,
0, true, DUPLICATE_SAME_ACCESS);
// Attach to console window – this may modify the standard handles
AttachConsole(ATTACH_PARENT_PROCESS);
// Adjust the standard handles
if (GetFileInformationByHandle(GetStdHandle(STD_OUTPUT_HANDLE), out bhfi))
{
SetStdHandle(STD_OUTPUT_HANDLE, hStdOutDup);
}
else
{
SetStdHandle(STD_OUTPUT_HANDLE, hStdOut);
}
if (GetFileInformationByHandle(GetStdHandle(STD_ERROR_HANDLE), out bhfi))
{
SetStdHandle(STD_ERROR_HANDLE, hStdErrDup);
}
else
{
SetStdHandle(STD_ERROR_HANDLE, hStdErr);
}
}
///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args)
{
bool NoGui = false;
string name = “”;
int number = 0;
for (int i = 0; i != args.Length; ++i)
{
switch (args[i])
{
case “/NoGui”: NoGui = true; break;
case “/name”: name = args[++i]; break;
case “/number”: number = int.Parse(args[++i]); break;
default: Console.WriteLine(“Invalid args!”); return;
}
}
if (!NoGui)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else
{
// initialize console handles
InitConsoleHandles();
// to demonstrate where the console output is going
int argCount = args == null ? 0 : args.Length;
Console.WriteLine(“nnn************Console Application Starting!!!*************”);
Console.WriteLine(“You specified {0} arguments:”, argCount);
Console.Error.WriteLine(“This is the error channel”);
for (int i = 0; i < argCount; i++)
{
Console.WriteLine(" {0}", args[i]);
}
Console.WriteLine("*************Console Application Ended!***********");
System.Windows.Forms.SendKeys.SendWait("{ENTER}");
}
}
}
}
————————————————————————————————————
Thanks for posting this (and great comments)!
Got a better solution:
Right click the project and select “Property”, in the Application tab, you can see “Output Type:” is “Windows Application” in default for Form application. Change it to Console Application, there is no modification needed in your source code. All problem solved. The output can be redirected to text file, and the command prompt is not messed up.
@Ben: Yeah, except it’s no longer a WinForms application when you change it to Console Application.
Ben, I like your solution with one reservation that unfortunately makes it unusable for me.
After changing the application property “Output Type” from “Windows Application” to “Console Application” the application still functions as a Windows Application. Starting it as a console application gives the usual console application capabilities such as console output and I/O redirection.
The unfortunate part is that, when running as a Windows Application a console window is automatically opened (which disappears when the Windows Application is closed). Does anyone know a way to inhibit display of the console window?
@Jeff
If you call AttachConsole( ATTACH_PARENT_PROCESS ) then it “shouldn’t” open up a new window. AllocConsole always does, though. I think.
Hi Jeff, my final solution is to FreeConsole if the console is not needed. Please check my post for details:
http://benincampus.blogspot.com/2011/03/re-console-output-from-winforms.html
I like the simplicity of Ben’s solution, however, the flashing console window is annoying. So I still like the I/O redirection approach above better.
Additionally, I found that this line is not really necessary. My program exits properly w/o waiting for an Enter.
System.Windows.Forms.SendKeys.SendWait(“{ENTER}”); // not needed
Thanks all!
Sorry, please ignore my comment regarding the SendWait line!
It’s not needed when the application’s output type is “Console Application”, but it IS needed when the type is “Windows Application”.
I managed to hide the command prompt in by filling the entire row with spaces, works fine for me:
using System;
using System.IO;
static class Program
{
[DllImport(“kernel32.dll”)]
static extern bool AttachConsole(UInt32 dwProcessId = 0xffffffff);
[STAThread]
static void Main()
{
try
{
AttachConsole();
Console.Write(“r”); // go back to the first column of a console window
for (int i = 0; i < Console.WindowWidth – 1; ++i, Console.Write(" ")) ; // fill a row with spaces, overwriting command prompt. note: the last character can't be overwritten, because console cursor moves to the next line
Console.Write("r"); // go back to the first column
}
// Console.WindowWidth throws an IOException when there's no console window, so ignore it
catch (IOException ex) { }
// …
}
}
[…] Infos und auch eine kleine Diskussion gibts hier und hier. Share and […]
[…] answer points to an article about running a .Net WinForms application with a console. It uses the technique of calling AttachConsole after the program starts running. This has the […]
This is very helpful. I also want my WinFoms application to behave like Console application when I return a code(integer) from main method. Basically when I do that from Console application the %ERRORLEVEL% is set with return value and I want the same thing to happen when I run my WinForms type application from command prompt. How do I do that?
[…] https://www.csharp411.com/console-output-from-winforms-application/ […]
Any idea how to capture another process’ output? Say you’ve started a batch file from a cmd.exe process (pid 1234). Batch file creates output… Can we caputure this output from another process?
@Meraydin: Offhand, the easiest solution would be to redirect the batch file output to a text file, such as:
cmd.exe > output.txt
Then you can open and inspect the contents of the text file.
You made my day !
It’s the best solution I found to get exactly what I wanted.
Thank you !
very informative, Worked for me, as i want to print Exceptions on to the console rather than choosing MessageBox over form. Thank you
really simple ,windows form application so much fun 🙂
[…] Console Output from a WinForms Application : C# 411 – You may wish to enable your WinForms application to run from a console window or command line. And when it does, you probably want to send output messages to the …… […]
[…] answer points to an article about running a .Net WinForms application with a console. It uses the technique of calling AttachConsole after the program starts running. This has the […]