Can one executable be both a console and GUI application? - c#

I want to make a C# program that can be run as a CLI or GUI application depending on what flags are passed into it. Can this be done?
I have found these related questions, but they don't exactly cover my situation:
How to write to the console in a GUI application
How do I get console output in C++ with a Windows program?

Jdigital's answer points to Raymond Chen's blog, which explains why you can't have an application that's both a console program and a non-console* program: The OS needs to know before the program starts running which subsystem to use. Once the program has started running, it's too late to go back and request the other mode.
Cade's 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 effect of allowing the program to write back to the console window of the command prompt that started the program. But the comments in that article point out what I consider to be a fatal flaw: The child process doesn't really control the console. The console continues accepting input on behalf of the parent process, and the parent process is not aware that it should wait for the child to finish running before using the console for other things.
Chen's article points to an article by Junfeng Zhang that explains a couple of other techniques.
The first is what devenv uses. It works by actually having two programs. One is devenv.exe, which is the main GUI program, and the other is devenv.com, which handles console-mode tasks, but if it's used in a non-console-like manner, it forwards its tasks to devenv.exe and exits. The technique relies on the Win32 rule that com files get chosen ahead of exe files when you type a command without the file extension.
There's a simpler variation on this that the Windows Script Host does. It provides two completely separate binaries, wscript.exe and cscript.exe. Likewise, Java provides java.exe for console programs and javaw.exe for non-console programs.
Junfeng's second technique is what ildasm uses. He quotes the process that ildasm's author went through when making it run in both modes. Ultimately, here's what it does:
The program is marked as a console-mode binary, so it always starts out with a console. This allows input and output redirection to work as normal.
If the program has no console-mode command-line parameters, it re-launches itself.
It's not enough to simply call FreeConsole to make the first instance cease to be a console program. That's because the process that started the program, cmd.exe, "knows" that it started a console-mode program and is waiting for the program to stop running. Calling FreeConsole would make ildasm stop using the console, but it wouldn't make the parent process start using the console.
So the first instance restarts itself (with an extra command-line parameter, I suppose). When you call CreateProcess, there are two different flags to try, DETACHED_PROCESS and CREATE_NEW_CONSOLE, either of which will ensure that the second instance will not be attached to the parent console. After that, the first instance can terminate and allow the command prompt to resume processing commands.
The side effect of this technique is that when you start the program from a GUI interface, there will still be a console. It will flash on the screen momentarily and then disappear.
The part in Junfeng's article about using editbin to change the program's console-mode flag is a red herring, I think. Your compiler or development environment should provide a setting or option to control which kind of binary it creates. There should be no need to modify anything afterward.
The bottom line, then, is that you can either have two binaries, or you can have a momentary flicker of a console window. Once you decide which is the lesser evil, you have your choice of implementations.
* I say non-console instead of GUI because otherwise it's a false dichotomy. Just because a program doesn't have a console doesn't mean it has a GUI. A service application is a prime example. Also, a program can have a console and windows.

Check out Raymond's blog on this topic:
https://devblogs.microsoft.com/oldnewthing/20090101-00/?p=19643
His first sentence: "You can't, but you can try to fake it."

http://www.csharp411.com/console-output-from-winforms-application/
Just check the command line arguments before the WinForms Application. stuff.
I should add that in .NET it is RIDICULOUSLY easy to simply make a console and GUI projects in the same solution which share all their assemblies except main. And in this case, you could make the command line version simply launch the GUI version if it is launched with no parameters. You would get a flashing console.

There is an easy way to do what you want. I'm always using it when writing apps that should have both a CLI and a GUI. You have to set your "OutputType" to "ConsoleApplication" for this to work.
class Program {
[DllImport("kernel32.dll", EntryPoint = "GetConsoleWindow")]
private static extern IntPtr _GetConsoleWindow();
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
/*
* This works as following:
* First we look for command line parameters and if there are any of them present, we run the CLI version.
* If there are no parameters, we try to find out if we are run inside a console and if so, we spawn a new copy of ourselves without a console.
* If there is no console at all, we show the GUI.
* We make an exception if we find out, that we're running inside visual studio to allow for easier debugging the GUI part.
* This way we're both a CLI and a GUI.
*/
if (args != null && args.Length > 0) {
// execute CLI - at least this is what I call, passing the given args.
// Change this call to match your program.
CLI.ParseCommandLineArguments(args);
} else {
var consoleHandle = _GetConsoleWindow();
// run GUI
if (consoleHandle == IntPtr.Zero || AppDomain.CurrentDomain.FriendlyName.Contains(".vshost"))
// we either have no console window or we're started from within visual studio
// This is the form I usually run. Change it to match your code.
Application.Run(new MainForm());
else {
// we found a console attached to us, so restart ourselves without one
Process.Start(new ProcessStartInfo(Assembly.GetEntryAssembly().Location) {
CreateNoWindow = true,
UseShellExecute = false
});
}
}
}

I think the preferred technique is what Rob called the devenv technique of using two executables: a launcher ".com" and the original ".exe". This is not that tricky to use if you have the boilerplate code to work with (see below link).
The technique uses tricks to have that ".com" be a proxy for the stdin/stdout/stderr and launch the same-named .exe file. This give the behavior of allowing the program to preform in a command line mode when called form a console (potentially only when certain command-line arguments are detected) while still being able to launch as a GUI application free of a console.
I hosted a project called dualsubsystem on Google Code that updates an old codeguru solution of this technique and provides the source code and working example binaries.

Here is what I believe to be the simple .NET C# solution to the problem. Just to restate the problem, when you run the console "version" of the app from a command line with a switch, the console keeps waiting (it doesn't return to the command prompt and the process keeps running) even if you have an Environment.Exit(0) at the end of your code. To fix this, just before calling Environment.Exit(0), call this:
SendKeys.SendWait("{ENTER}");
Then the console gets the final Enter key it needs to return to the command prompt and the process ends. Note: Don't call SendKeys.Send(), or the app will crash.
It's still necessary to call AttachConsole() as mentioned in many posts, but with this I get no command window flicker when launching the WinForm version of the app.
Here's the entire code in a sample app I created (without the WinForms code):
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ConsoleWriter
{
static class Program
{
[DllImport("kernel32.dll")]
private static extern bool AttachConsole(int dwProcessId);
private const int ATTACH_PARENT_PROCESS = -1;
[STAThread]
static void Main(string[] args)
{
if(args.Length > 0 && args[0].ToUpperInvariant() == "/NOGUI")
{
AttachConsole(ATTACH_PARENT_PROCESS);
Console.WriteLine(Environment.NewLine + "This line prints on console.");
Console.WriteLine("Exiting...");
SendKeys.SendWait("{ENTER}");
Environment.Exit(0);
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
}
Hope it helps someone from also spending days on this problem. Thanks for the hint go to #dantill.

/*
** dual.c Runs as both CONSOLE and GUI app in Windows.
**
** This solution is based on the "Momentary Flicker" solution that Robert Kennedy
** discusses in the highest-rated answer (as of Jan 2013), i.e. the one drawback
** is that the console window will briefly flash up when run as a GUI. If you
** want to avoid this, you can create a shortcut to the executable and tell the
** short cut to run minimized. That will minimize the console window (which then
** immediately quits), but not the GUI window. If you want the GUI window to
** also run minimized, you have to also put -minimized on the command line.
**
** Tested under MinGW: gcc -o dual.exe dual.c -lgdi32
**
*/
#include <windows.h>
#include <stdio.h>
static int my_win_main(HINSTANCE hInstance,int argc,char *argv[],int iCmdShow);
static LRESULT CALLBACK WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);
static int win_started_from_console(void);
static BOOL CALLBACK find_win_by_procid(HWND hwnd,LPARAM lp);
int main(int argc,char *argv[])
{
HINSTANCE hinst;
int i,gui,relaunch,minimized,started_from_console;
/*
** If not run from command-line, or if run with "-gui" option, then GUI mode
** Otherwise, CONSOLE app.
*/
started_from_console = win_started_from_console();
gui = !started_from_console;
relaunch=0;
minimized=0;
/*
** Check command options for forced GUI and/or re-launch
*/
for (i=1;i<argc;i++)
{
if (!strcmp(argv[i],"-minimized"))
minimized=1;
if (!strcmp(argv[i],"-gui"))
gui=1;
if (!strcmp(argv[i],"-gui-"))
gui=0;
if (!strcmp(argv[i],"-relaunch"))
relaunch=1;
}
if (!gui && !relaunch)
{
/* RUN AS CONSOLE APP */
printf("Console app only.\n");
printf("Usage: dual [-gui[-]] [-minimized].\n\n");
if (!started_from_console)
{
char buf[16];
printf("Press <Enter> to exit.\n");
fgets(buf,15,stdin);
}
return(0);
}
/* GUI mode */
/*
** If started from CONSOLE, but want to run in GUI mode, need to re-launch
** application to completely separate it from the console that started it.
**
** Technically, we don't have to re-launch if we are not started from
** a console to begin with, but by re-launching we can avoid the flicker of
** the console window when we start if we start from a shortcut which tells
** us to run minimized.
**
** If the user puts "-minimized" on the command-line, then there's
** no point to re-launching when double-clicked.
*/
if (!relaunch && (started_from_console || !minimized))
{
char exename[256];
char buf[512];
STARTUPINFO si;
PROCESS_INFORMATION pi;
GetStartupInfo(&si);
GetModuleFileNameA(NULL,exename,255);
sprintf(buf,"\"%s\" -relaunch",exename);
for (i=1;i<argc;i++)
{
if (strlen(argv[i])+3+strlen(buf) > 511)
break;
sprintf(&buf[strlen(buf)]," \"%s\"",argv[i]);
}
memset(&pi,0,sizeof(PROCESS_INFORMATION));
memset(&si,0,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwX = 0; /* Ignored unless si.dwFlags |= STARTF_USEPOSITION */
si.dwY = 0;
si.dwXSize = 0; /* Ignored unless si.dwFlags |= STARTF_USESIZE */
si.dwYSize = 0;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
/*
** Note that launching ourselves from a console will NOT create new console.
*/
CreateProcess(exename,buf,0,0,1,DETACHED_PROCESS,0,NULL,&si,&pi);
return(10); /* Re-launched return code */
}
/*
** GUI code starts here
*/
hinst=GetModuleHandle(NULL);
/* Free the console that we started with */
FreeConsole();
/* GUI call with functionality of WinMain */
return(my_win_main(hinst,argc,argv,minimized ? SW_MINIMIZE : SW_SHOWNORMAL));
}
static int my_win_main(HINSTANCE hInstance,int argc,char *argv[],int iCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASSEX wndclass;
static char *wintitle="GUI Window";
wndclass.cbSize = sizeof (wndclass) ;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = NULL;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = wintitle;
wndclass.hIconSm = NULL;
RegisterClassEx (&wndclass) ;
hwnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,wintitle,0,
WS_VISIBLE|WS_OVERLAPPEDWINDOW,
100,100,400,200,NULL,NULL,hInstance,NULL);
SetWindowText(hwnd,wintitle);
ShowWindow(hwnd,iCmdShow);
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return(msg.wParam);
}
static LRESULT CALLBACK WndProc (HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
if (iMsg==WM_DESTROY)
{
PostQuitMessage(0);
return(0);
}
return(DefWindowProc(hwnd,iMsg,wParam,lParam));
}
static int fwbp_pid;
static int fwbp_count;
static int win_started_from_console(void)
{
fwbp_pid=GetCurrentProcessId();
if (fwbp_pid==0)
return(0);
fwbp_count=0;
EnumWindows((WNDENUMPROC)find_win_by_procid,0L);
return(fwbp_count==0);
}
static BOOL CALLBACK find_win_by_procid(HWND hwnd,LPARAM lp)
{
int pid;
GetWindowThreadProcessId(hwnd,(LPDWORD)&pid);
if (pid==fwbp_pid)
fwbp_count++;
return(TRUE);
}

I have written up an alternative approach which avoids the console flash. See How to create a Windows program that works both as a GUI and console application.

Run AllocConsole() in a static constructor works for me

Related

C# Console-Application with no console but winforms

We have an application that is a WinForms-Application. It accepts startup parameters and can perform certain jobs with no UI by using the command line.
Now, we also want some console-output, like for example when using application.exe /help.
The Issue we are now facing is: How to bring both worlds together in a "nice" way:
When setting the Output Type to "Windows Application",all the UI stuff works fine, but Console.WriteLine() doesn't show results when used from cmd.
When setting the Output Type to "Console", generally both things work, BUT: The Application (when used in UI-Mode so to say) raises a console window, that stays open until the application terminates.
Is there a way to bypass the visibility of the console-window?
In the real world, I can find applications using one of three approaches - but I don't like either of them:
Leave the console window open when running in UI-Mode, who cares?
Use user32.dll to hide the window (it still flashes, tho)
Use Windows-Application as Output-Type and show Console-Output as "message boxes", when used from the command line.
I've figured out a solution, thx to #Luaan s comment:
I'm now using the Output Type Windows Application (so, no console window) - but simply registering the Console with the Applications "Parent" Console.
This now behaves as expected:
No console is shown during normal startup.
When used from within an existing console window (ps / cmd) the output is printed, because that consoles are then technically the parent-console of the application.
public class GUIConsoleWriter
{
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool AttachConsole(int dwProcessId);
private const int ATTACH_PARENT_PROCESS = -1;
public static void RegisterGUIConsoleWriter()
{
AttachConsole(ATTACH_PARENT_PROCESS);
}
}
And then, firstline in Main():
static void Main(String[] args)
{
GUIConsoleWriter.RegisterGUIConsoleWriter();
}
Now, using regular Console.WriteLine() works. Ofc. this is limited to writing output, but for the scope of my projects that is sufficent, as input has to be provided with arguments, no interactive console-options.
When another application needs to fetch output programmatically, you ofc. can't do myApp.exe /doSomething but need to do cmd /C myApp.exe /doSomething because the application itself doesn't own a console.
AND you have to manually take care to "exit" your application, after providing output, otherwhise the process won't return.

What is the Purpose of Console.WriteLine() in Winforms

I once saw the source code of a winform application and the code had a Console.WriteLine();. I asked the reason for that and i was told that it was for debugging purposes.
Pls what is the essence of Console.WriteLine(); in a winform and what action does it perform because when i tried using it, it never wrote anything.
It writes to the Console.
The end user won't see it, and to be honest its much cleaner to put it into a proper log, but if you run it through VS the Console window will populate.
Winforms are just console apps that show windows. You can direct your debug info to the console app.
As you can see in the below example there is a command that attaches the parent window then pumps info to 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() );
}
}
}
Here is the resource for this example:http://www.csharp411.com/console-output-from-winforms-application/
You wouldn't really use it normally but if you've attached a Console or use AllocConsole, it will function like in any other console application and the output will be visible there.
For quick debugging, I prefer Debug.WriteLine but for a more robust solution, the Trace class may be preferable.
It wouldn't perform anything unless the Console was redirected to say the Output window. Really, they should be leveraging Debug.WriteLine instead.
The benefit of Debug.WriteLine is that it gets optimized away when building in Release mode.
NOTE: as pointed out by Brad Christie and Haedrian, apparently it will in fact write to the Console window in Visual Studio when running a Windows Forms application. You learn something new every day!

C# Windows application that doesn't fork (or Console Application with no console window) [duplicate]

I want to make a C# program that can be run as a CLI or GUI application depending on what flags are passed into it. Can this be done?
I have found these related questions, but they don't exactly cover my situation:
How to write to the console in a GUI application
How do I get console output in C++ with a Windows program?
Jdigital's answer points to Raymond Chen's blog, which explains why you can't have an application that's both a console program and a non-console* program: The OS needs to know before the program starts running which subsystem to use. Once the program has started running, it's too late to go back and request the other mode.
Cade's 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 effect of allowing the program to write back to the console window of the command prompt that started the program. But the comments in that article point out what I consider to be a fatal flaw: The child process doesn't really control the console. The console continues accepting input on behalf of the parent process, and the parent process is not aware that it should wait for the child to finish running before using the console for other things.
Chen's article points to an article by Junfeng Zhang that explains a couple of other techniques.
The first is what devenv uses. It works by actually having two programs. One is devenv.exe, which is the main GUI program, and the other is devenv.com, which handles console-mode tasks, but if it's used in a non-console-like manner, it forwards its tasks to devenv.exe and exits. The technique relies on the Win32 rule that com files get chosen ahead of exe files when you type a command without the file extension.
There's a simpler variation on this that the Windows Script Host does. It provides two completely separate binaries, wscript.exe and cscript.exe. Likewise, Java provides java.exe for console programs and javaw.exe for non-console programs.
Junfeng's second technique is what ildasm uses. He quotes the process that ildasm's author went through when making it run in both modes. Ultimately, here's what it does:
The program is marked as a console-mode binary, so it always starts out with a console. This allows input and output redirection to work as normal.
If the program has no console-mode command-line parameters, it re-launches itself.
It's not enough to simply call FreeConsole to make the first instance cease to be a console program. That's because the process that started the program, cmd.exe, "knows" that it started a console-mode program and is waiting for the program to stop running. Calling FreeConsole would make ildasm stop using the console, but it wouldn't make the parent process start using the console.
So the first instance restarts itself (with an extra command-line parameter, I suppose). When you call CreateProcess, there are two different flags to try, DETACHED_PROCESS and CREATE_NEW_CONSOLE, either of which will ensure that the second instance will not be attached to the parent console. After that, the first instance can terminate and allow the command prompt to resume processing commands.
The side effect of this technique is that when you start the program from a GUI interface, there will still be a console. It will flash on the screen momentarily and then disappear.
The part in Junfeng's article about using editbin to change the program's console-mode flag is a red herring, I think. Your compiler or development environment should provide a setting or option to control which kind of binary it creates. There should be no need to modify anything afterward.
The bottom line, then, is that you can either have two binaries, or you can have a momentary flicker of a console window. Once you decide which is the lesser evil, you have your choice of implementations.
* I say non-console instead of GUI because otherwise it's a false dichotomy. Just because a program doesn't have a console doesn't mean it has a GUI. A service application is a prime example. Also, a program can have a console and windows.
Check out Raymond's blog on this topic:
https://devblogs.microsoft.com/oldnewthing/20090101-00/?p=19643
His first sentence: "You can't, but you can try to fake it."
http://www.csharp411.com/console-output-from-winforms-application/
Just check the command line arguments before the WinForms Application. stuff.
I should add that in .NET it is RIDICULOUSLY easy to simply make a console and GUI projects in the same solution which share all their assemblies except main. And in this case, you could make the command line version simply launch the GUI version if it is launched with no parameters. You would get a flashing console.
There is an easy way to do what you want. I'm always using it when writing apps that should have both a CLI and a GUI. You have to set your "OutputType" to "ConsoleApplication" for this to work.
class Program {
[DllImport("kernel32.dll", EntryPoint = "GetConsoleWindow")]
private static extern IntPtr _GetConsoleWindow();
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
/*
* This works as following:
* First we look for command line parameters and if there are any of them present, we run the CLI version.
* If there are no parameters, we try to find out if we are run inside a console and if so, we spawn a new copy of ourselves without a console.
* If there is no console at all, we show the GUI.
* We make an exception if we find out, that we're running inside visual studio to allow for easier debugging the GUI part.
* This way we're both a CLI and a GUI.
*/
if (args != null && args.Length > 0) {
// execute CLI - at least this is what I call, passing the given args.
// Change this call to match your program.
CLI.ParseCommandLineArguments(args);
} else {
var consoleHandle = _GetConsoleWindow();
// run GUI
if (consoleHandle == IntPtr.Zero || AppDomain.CurrentDomain.FriendlyName.Contains(".vshost"))
// we either have no console window or we're started from within visual studio
// This is the form I usually run. Change it to match your code.
Application.Run(new MainForm());
else {
// we found a console attached to us, so restart ourselves without one
Process.Start(new ProcessStartInfo(Assembly.GetEntryAssembly().Location) {
CreateNoWindow = true,
UseShellExecute = false
});
}
}
}
I think the preferred technique is what Rob called the devenv technique of using two executables: a launcher ".com" and the original ".exe". This is not that tricky to use if you have the boilerplate code to work with (see below link).
The technique uses tricks to have that ".com" be a proxy for the stdin/stdout/stderr and launch the same-named .exe file. This give the behavior of allowing the program to preform in a command line mode when called form a console (potentially only when certain command-line arguments are detected) while still being able to launch as a GUI application free of a console.
I hosted a project called dualsubsystem on Google Code that updates an old codeguru solution of this technique and provides the source code and working example binaries.
Here is what I believe to be the simple .NET C# solution to the problem. Just to restate the problem, when you run the console "version" of the app from a command line with a switch, the console keeps waiting (it doesn't return to the command prompt and the process keeps running) even if you have an Environment.Exit(0) at the end of your code. To fix this, just before calling Environment.Exit(0), call this:
SendKeys.SendWait("{ENTER}");
Then the console gets the final Enter key it needs to return to the command prompt and the process ends. Note: Don't call SendKeys.Send(), or the app will crash.
It's still necessary to call AttachConsole() as mentioned in many posts, but with this I get no command window flicker when launching the WinForm version of the app.
Here's the entire code in a sample app I created (without the WinForms code):
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ConsoleWriter
{
static class Program
{
[DllImport("kernel32.dll")]
private static extern bool AttachConsole(int dwProcessId);
private const int ATTACH_PARENT_PROCESS = -1;
[STAThread]
static void Main(string[] args)
{
if(args.Length > 0 && args[0].ToUpperInvariant() == "/NOGUI")
{
AttachConsole(ATTACH_PARENT_PROCESS);
Console.WriteLine(Environment.NewLine + "This line prints on console.");
Console.WriteLine("Exiting...");
SendKeys.SendWait("{ENTER}");
Environment.Exit(0);
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
}
Hope it helps someone from also spending days on this problem. Thanks for the hint go to #dantill.
/*
** dual.c Runs as both CONSOLE and GUI app in Windows.
**
** This solution is based on the "Momentary Flicker" solution that Robert Kennedy
** discusses in the highest-rated answer (as of Jan 2013), i.e. the one drawback
** is that the console window will briefly flash up when run as a GUI. If you
** want to avoid this, you can create a shortcut to the executable and tell the
** short cut to run minimized. That will minimize the console window (which then
** immediately quits), but not the GUI window. If you want the GUI window to
** also run minimized, you have to also put -minimized on the command line.
**
** Tested under MinGW: gcc -o dual.exe dual.c -lgdi32
**
*/
#include <windows.h>
#include <stdio.h>
static int my_win_main(HINSTANCE hInstance,int argc,char *argv[],int iCmdShow);
static LRESULT CALLBACK WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);
static int win_started_from_console(void);
static BOOL CALLBACK find_win_by_procid(HWND hwnd,LPARAM lp);
int main(int argc,char *argv[])
{
HINSTANCE hinst;
int i,gui,relaunch,minimized,started_from_console;
/*
** If not run from command-line, or if run with "-gui" option, then GUI mode
** Otherwise, CONSOLE app.
*/
started_from_console = win_started_from_console();
gui = !started_from_console;
relaunch=0;
minimized=0;
/*
** Check command options for forced GUI and/or re-launch
*/
for (i=1;i<argc;i++)
{
if (!strcmp(argv[i],"-minimized"))
minimized=1;
if (!strcmp(argv[i],"-gui"))
gui=1;
if (!strcmp(argv[i],"-gui-"))
gui=0;
if (!strcmp(argv[i],"-relaunch"))
relaunch=1;
}
if (!gui && !relaunch)
{
/* RUN AS CONSOLE APP */
printf("Console app only.\n");
printf("Usage: dual [-gui[-]] [-minimized].\n\n");
if (!started_from_console)
{
char buf[16];
printf("Press <Enter> to exit.\n");
fgets(buf,15,stdin);
}
return(0);
}
/* GUI mode */
/*
** If started from CONSOLE, but want to run in GUI mode, need to re-launch
** application to completely separate it from the console that started it.
**
** Technically, we don't have to re-launch if we are not started from
** a console to begin with, but by re-launching we can avoid the flicker of
** the console window when we start if we start from a shortcut which tells
** us to run minimized.
**
** If the user puts "-minimized" on the command-line, then there's
** no point to re-launching when double-clicked.
*/
if (!relaunch && (started_from_console || !minimized))
{
char exename[256];
char buf[512];
STARTUPINFO si;
PROCESS_INFORMATION pi;
GetStartupInfo(&si);
GetModuleFileNameA(NULL,exename,255);
sprintf(buf,"\"%s\" -relaunch",exename);
for (i=1;i<argc;i++)
{
if (strlen(argv[i])+3+strlen(buf) > 511)
break;
sprintf(&buf[strlen(buf)]," \"%s\"",argv[i]);
}
memset(&pi,0,sizeof(PROCESS_INFORMATION));
memset(&si,0,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwX = 0; /* Ignored unless si.dwFlags |= STARTF_USEPOSITION */
si.dwY = 0;
si.dwXSize = 0; /* Ignored unless si.dwFlags |= STARTF_USESIZE */
si.dwYSize = 0;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
/*
** Note that launching ourselves from a console will NOT create new console.
*/
CreateProcess(exename,buf,0,0,1,DETACHED_PROCESS,0,NULL,&si,&pi);
return(10); /* Re-launched return code */
}
/*
** GUI code starts here
*/
hinst=GetModuleHandle(NULL);
/* Free the console that we started with */
FreeConsole();
/* GUI call with functionality of WinMain */
return(my_win_main(hinst,argc,argv,minimized ? SW_MINIMIZE : SW_SHOWNORMAL));
}
static int my_win_main(HINSTANCE hInstance,int argc,char *argv[],int iCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASSEX wndclass;
static char *wintitle="GUI Window";
wndclass.cbSize = sizeof (wndclass) ;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = NULL;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = wintitle;
wndclass.hIconSm = NULL;
RegisterClassEx (&wndclass) ;
hwnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,wintitle,0,
WS_VISIBLE|WS_OVERLAPPEDWINDOW,
100,100,400,200,NULL,NULL,hInstance,NULL);
SetWindowText(hwnd,wintitle);
ShowWindow(hwnd,iCmdShow);
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return(msg.wParam);
}
static LRESULT CALLBACK WndProc (HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
if (iMsg==WM_DESTROY)
{
PostQuitMessage(0);
return(0);
}
return(DefWindowProc(hwnd,iMsg,wParam,lParam));
}
static int fwbp_pid;
static int fwbp_count;
static int win_started_from_console(void)
{
fwbp_pid=GetCurrentProcessId();
if (fwbp_pid==0)
return(0);
fwbp_count=0;
EnumWindows((WNDENUMPROC)find_win_by_procid,0L);
return(fwbp_count==0);
}
static BOOL CALLBACK find_win_by_procid(HWND hwnd,LPARAM lp)
{
int pid;
GetWindowThreadProcessId(hwnd,(LPDWORD)&pid);
if (pid==fwbp_pid)
fwbp_count++;
return(TRUE);
}
I have written up an alternative approach which avoids the console flash. See How to create a Windows program that works both as a GUI and console application.
Run AllocConsole() in a static constructor works for me

C#: Is it possible to have a single application behave as Console or Windows application depending on switches?

I have a simple application that I would like to sort of automate via switches. But when I do run it via switches I don't really want a user interface showing. I just want it to run, do it's job, print stuff out in the console, and exit. On the other hand if I don't run it with any switches I want the user interface to pop up. And in this case I don't really want a console window hanging around in the background.
Is there any way I can do this, or do I have to create two separate projects, one Console Application and one Windows Application?
Whilst not exactly what you have asked, I've achieved the appearance of this behaviour in the past by using the FreeConsole pInvoke to remove the console window.
You set the output type of the project to be a console application. You then define the extern call to FreeConsole:
[DllImport("kernel32.dll", SetLastError=true)]
private static extern int FreeConsole();
Then, in you Main method you switch based on your conditions. If you want a UI, call FreeConsole before opening the form to clear the console window.
if (asWinForms)
{
FreeConsole();
Application.Run(new MainForm());
}
else
{
// console logic here
}
A console window does briefly appear at startup, but in my case it was acceptable.
This is a bit of a hack though and has a bad smell, so I'd seriously consider whether you do want to go down this route.
From 'The Old New Thing'
How do I write a program that can be run either as a console or a GUI application?
You can't.
(I'll let you click on the article for the details of how to fake it)
Sure, just put a switch statement (or if else construction) in the static main(string[] args), based on arguments passed in command line. I also do this to switch between executing as a service or as a console...
NOTE: Set project type as Console App
[DllImport("kernel32.dll", SetLastError=true)]
private static extern int FreeConsole();
[STAThread]
static void Main(string[] args)
{
if (args.Length == 0 && args[0] == "C") // Console
{
// Run as console code
Console.WriteLine("Running as Console App");
Console.WriteLine("Hit any Key to exit");
Console.ReadLine();
}
else
{
//Console.SetWindowSize(1,1);
//string procName = Assembly.GetExecutingAssembly().FullName;
//ProcessStartInfo info = new ProcessStartInfo(procName );
//info.WindowStyle = ProcessWindowStyle.Minimized;
// EDIT: Thanks to Adrian Bank's answer -
// a better approach is to use FreeConsole()
FreeConsole();
Application.Run(new MyForm());
}
}
EDIT: Thanks to Adrian Bank's answer, FreeConsole() is much better approach to "dispense" with Console window than just minimizing it...
They are two different paradigms, I don't think that using a command line switch like this is a good idea. Why not build the core logic into a console application and then call that from the GUI when needed? This would nicely separate the UI from the implementation but would still provide a way to use the Console app stand alone when needed.
I believe the answer is no, or it was last time I looked into this problem.
The executable is marked as either a windowed application or a console application. You can see this in the properties for you project in Visual Studio, under application, Output type
You could simulate the behavior by having two application, a console application that if executed with no arguments launches the GUI application. You may see a console window flash, unless you ran in from an already open console.
Without implementing your own version of a console window the answer is no. When Windows loads you executable it decides whether or not to give you a console window based on data in the PE header. So you can make a windowed app not have a window but you can't make a windoed app have a console.
You can, but with some drawbacks:
You can prevent having this black window on start up if you compile for subsystem Windows.
But then you have to attach the process to the calling console (cmd.exe) manually via AttachConsole(-1)
http://msdn.microsoft.com/en-us/library/windows/desktop/ms681952%28v=vs.85%29.aspx
This alone does not do the job. You also have to redirect the three std streams to the console via these calls:
// redirect unbuffered STDOUT to the console
lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "w" );
*stdout = *fp;
setvbuf( stdout, NULL, _IONBF, 0 );
fp = _fdopen( hConHandle, "r" );
*stdin = *fp;
setvbuf( stdin, NULL, _IONBF, 0 );
// redirect unbuffered STDERR to the console
lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "w" );
*stderr = *fp;
setvbuf( stderr, NULL, _IONBF, 0 );
// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
// point to console as well
ios::sync_with_stdio();
Sample from: http://cygwin.com/ml/cygwin/2004-05/msg00215.html
The problem with your WinMain call is that windows already has forked out your process so the calling cmd.exe console will have returned from your .exe already and proceed with the next command.
To prevent that you can call your exe with start /wait myexe.exe
This way you also get the return value of your app and you can check it with %errorlevel% as usual.
If there is a way to prevent that process forking with subsystem windows please let me know.
Hope this helps.

What is the different between API functions AllocConsole and AttachConsole(-1)?

Could you please explain me, what is the different between API functions AllocConsole and AttachConsole(-1) ? I mean if AttachConsole gets ATTACH_PARENT_PROCESS(DWORD)-1.
Well, the fundamental difference is:
AllocConsole() will create a new console (and attach to it)
AttachConsole( ATTACH_PARENT_PROCESS /* -1 */) will not create a new console, it will attach to the existing console of the parent process.
In the first case you get a whole new console window, in the second case, you use an existing console window.
Of course, if you're already attached to a console (ie., you're a console mode program launched from cmd.exe) there's not much difference - you'll get an error with either API.
Also note that just because you detach from a console doesn't mean the detached console will be useful - for example, if you're a console process launched from a cmd window, that window essentially blocks until your process ends.
Some code to play with:
int main( int argc, char* argv[])
{
int ch;
BOOL bResult;
printf( "default console\n");
ch = getchar();
bResult = FreeConsole();
bResult = AllocConsole();
printf( "AllocConsole()\n");
ch = getchar();
bResult = FreeConsole();
bResult = AttachConsole( ATTACH_PARENT_PROCESS);
printf( "AttachConsole( ATTACH_PARENT_PROCESS)\n");
ch = getchar();
return 0;
}
I don't think there's a function called CreateConsole, but there's AllocConsole.
Assuming that's what you meant, I think the difference is that AttachConsole(ATTACH_PARENT_PROCESS) can return ERROR_INVALID_HANDLE if the parent process doesn't have a console.
Try running this code from both a command prompt and Start -> Run:
#include <windows.h>
#pragma comment ( lib, "user32.lib" )
int main()
{
BOOL b;
char msg[1024];
b = FreeConsole();
sprintf(msg, "%d", b);
MessageBox(NULL, msg, "FreeConsole", 0);
b = AttachConsole(ATTACH_PARENT_PROCESS);
sprintf(msg, "%d", b);
MessageBox(NULL, msg, "AttachConsole", 0);
return 0;
}
When run from a command prompt, two message boxes containing a 1 are displayed, meaning both calls succeeded. When run from Start -> Run, the first box contains 1 and the second contains 0, meaning that only the first call succeeded. The second one fails because explorer.exe (which is the parent of a process launched from Start -> Run) doesn't have a console.
On Windows 7, when you execute cmd.exe, CreateProcess will have the CREATE_NEW_CONSOLE flag, which will allocate a new console rather than being attached to the parent console (which is default behaviour when the PE header contains Subsystem = 3 i.e. IMAGE_SUBSYSTEM_WINDOWS_CUI indicating that it is a console application). This means that AllocConsole will be called before the .exe image entry point in the current process address space.
AllocConsole creates a new conhost.exe instance, which paints the GUI window, handles the mouse and keyboard events and maintains and writes to the the input buffer and maintains and reads from the screen buffer, and when there is a keyboard event, it updates the input buffer. AllocConsole also sets the stdin handle in the ParameterBlock in the cmd.exe process PEB to the console input buffer and the stdout and stderr to the the console pseudohandles, and sets the ConsoleHandle in the ParameterBlockto the PID of theconhost.exe` instance that it is attached to.
cmd.exe is a console application written in C, like diskpart.exe or setx.exe, which displays the command prompt to the screen buffer (stdout of cmd.exe) and reads a command from the stdin of cmd.exe and interprets the key press events to display to stdout as well as determine what command to call and what to display to stdout as a result (which might be a file in the handle in the PEB and not sent to conhost). A command itself has an stdin of either nothing, the read side of an anonymous pipe, a file or the con file.
cmd.exe calls functions like WriteFile which will call WriteConsole (which is an alias of WriteConsoleA) if it is writing to a standard handle (otherwise it calls NtWriteFile). This will initiate an ALPC call to conhost.exe PID in ParameterBlock->ConsoleHandle, passing the console pseudohandle and the buffer to write the result to (or the buffer to read from).
When you execute cmd /c from inside cmd.exe, it creates a child cmd.exe, but does not supply CREATE_NEW_CONSOLE, which results in the child cmd.exe attaching to the same visible console i.e. conhost.exe instance and AttachConsole is called before the entry point. This is not the case with a child created with admin /c (admin version of cmd.exe) if done in a non-elevated cmd.exe, which needs to have a new conhost.exe instance because it has different privileges. Similarly, when starting a program, start supplies CREATE_NEW_CONSOLE, which opens a new conhost.exe for its child process, but call and specifying the program filename + extension as a raw command do not open another console window, but attach to the parent. cmd /c diskpart creates a cmd.exe child that attaches to the console that the parent is attached to and then that child creates its own child diskpart.exe, which attaches to the console that the parent is attached to.
When you execute a GUI application, it is not allocated or attached to a console. If you use AllocConsole within the application, it will create a new conhost.exe console window (which can be hidden by the application, i.e. blender has window > toggle system console, and it does this by getting a handle to the conhost.exe console window and then using using ShowWindow with SW_HIDE on it), but will not create a child process, because it is the console window of the current process, so now there will be 2 windows. You can also instead attach to a console (using AttachConsole) belonging to a process of pid. AttachConsole(-1) attaches to the parent pid. This will use the conhost that that process is attached to.
You cannot AttachConsole if you are already attached to a console without using FreeConsole and you can't AttachConsole to connect to the parent's console if you create the process with DETACHED_PROCESS. CREATE_NO_WINDOW has the same effect as DETACHED_PROCESS in that it does not attach to or allocate a console for the console application but does allow it to attach to the parent console.
It has been a while since I used the winapi, but I looked up the MSDN documentation and I was not able to find the CreateConsole API function. So my guess is that CreateConsole is legacy stuff and has been replaced by AttachConsole. So there is probably no difference, but CreateConsole has probably been deprecated.

Categories

Resources