views:

521

answers:

4

Is it possible to (and if so, how do I) make a single program work both as a console application and a GUI version using Delphi 2007?

What I am after is that if the program is run with the appropriate command-line options, it should function as a console program, printing output to the console using WRITELN, but if no command line arguments are given it should run as a normal Delphi GUI application?

The catch is that when running as a console application, the command line interpreter waits for the application to terminate before allowing you to enter a new command, whereas a GUI application started from the command line immediately returns you to the command line and the GUI application is started in a detached process. I want this behaviour retained.

I don't mind something like this:

IF GUI THEN StartApplicationAsGUI(ParamStr(0))

ie. I don't mind that I'll have to restart the application using some form of EXECUTE call to start it in GUI mode if needed, as long as the command line interface returns to the command line input when the GUI version is started.

I'd prefer a solution/suggestion that is along the lines of:

<Parse Comnand Line>
IF ConsoleMode THEN
   RunConsole(Parameters)
ELSE BEGIN
   Application.Initialize;
   Application.CreateForm(...)
   Application.Run;
END

(or vice-versa, ie. doing things a special way if GUI mode)

so that I can still use Delphi's IDE and VCL when making the GUI interface...

+4  A: 

Windows has different values in executable's header for console and UI application (see more details here). So it seems to be impossible to make the same executable to work in both modes.

As an alternative, you can open a console in you UI app, but it will be new console, not the one you've started app from.

elder_george
+7  A: 

On Windows this is a little bit tricky. Actually the distinction between a console application and a GUI one is a single flag in the PE header. You can easily write console applications that create windows but that way you always have the console window around (you could hide it, though, but that wouldn't be nice when people run your program from cmd).

You can, however write a GUI application that creates a console if it needs to, using the AllocConsole function:

A process can be associated with only one console, so the AllocConsole function fails if the calling process already has a console. A process can use the FreeConsole function to detach itself from its current console, then it can call AllocConsole to create a new console or AttachConsole to attach to another console.

If the calling process creates a child process, the child inherits the new console.

AllocConsole initializes standard input, standard output, and standard error handles for the new console. The standard input handle is a handle to the console's input buffer, and the standard output and standard error handles are handles to the console's screen buffer. To retrieve these handles, use the GetStdHandle function.

This function is primarily used by graphical user interface (GUI) application to create a console window. GUI applications are initialized without a console. Console applications are initialized with a console, unless they are created as detached processes (by calling the CreateProcess function with the DETACHED_PROCESS flag).

However, when run from cmd this will likely cause another console window to appear instead of re-using the existing one. I don't know whether a good solution exists there.

Joey
+7  A: 

http://blogs.msdn.com/oldnewthing/archive/2009/01/01/9259142.aspx

glob
The short answer (from this link) is that: "You can't, but you can try to fake it."
Mick
+5  A: 

IMO, the best approach here is to have non-visual classes that actually do the work of the program. Then you can call that from a GUI program, and you can also call it from a separate command line program. Both programs are just wrappers around the functionality of your class(es).

This forces the design to be clean too - your classes necessarily are separated from the GUI layer of your application.

JosephStyons
This is the right answer.
Tim
The problem with this approach is that it requires the distribution of three files if done properly: 1) A command-line executable, 2) A GUI executable and 3) A Library file containing the relevant core of the program. I would prefer a single executable, and the best option seems to be having a GUI program with a console bit in the header that then can restart the itself with a detached console if it needs to run as GUI. Just like ildasm in the various links supplied.
HeartWare
Well I would say just two executables is doable. If you build the EXE including your BPLs then there is no need to distribute any "core" files - just one exe per application. But obviously you are the one who knows your deployment needs; I'm glad ildasm's answer was helpful.
JosephStyons
You're right that it could be done with 2 files, but then the core functionality code would have to be compiled into both versions, which - IMO - is a waste. Depending upon how big the core functionality is, this would also significantly increase the size of the deployment.
HeartWare