Program both as Console and GUI [duplicate] - delphi

This question already has answers here:
Can one executable be both a console and GUI application?
(9 answers)
Closed 6 years ago.
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...

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.

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.

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

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.

AttachConsole() may be used to get a hold of the parents console.
E.g. if the application is started from a cmdline shell, AllocConsole() can be avoided:
if not AttachConsole(ATTACH_PARENT_PROCESS)
then AllocConsole;
More info here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms681952(v=vs.85).aspx

Related

How to show/hide a console window app?

I have a small console app. I want to hide its window when it is called from my main program (with -hide as command line parameter) and show it when the user starts it (no command line param).
This question suggests that using {$APPTYPE GUI} instead of {$APPTYPE CONSOLE} will hide the window. And indeed it works. But how do I make the window visible when ran by user?
Purpose: I want my main program to interact with the console app silently in the background (console is invisible). So, when the user starts the console app alone, I just want to give him a warning: 'This console app is doing x task. You cannot start it manually'.
Leave the program alone, as a console application. Do not make it into a GUI application because that means that when users start it directly, it will not be given a console.
When you start the program from your main app, use CreateProcess to do so, passing the CREATE_NO_WINDOW flag. That flag ensures that no console window will be created.

Tab order in a console app with a single VCL form

I have a Windows console app created with Embarcadero XE 6 (in fact converted from a Borland C++Builder5 project). It has a single form with a few buttons and edit controls. All these controls have set TabStop=True and appropriate TabOrder's. However, pressing Tab in runtime when the form is shown does not do anything (it just produces a sound when a cursor/focus is in an Edit control and does nothing when a button is focused).
I have read in docs that Tab order would not work unless the Parent of the form is set. However, this is the only VCL form (the other windows are the console and the GLUT window), so there is no VCL parent AFAIK. I tried to set
Parent=Application->MainForm;
in the Form's constructor, but the Application->MainForm is also NULL. Any ideas?
Your problem is that you don't have a message loop. This is because console applications are not expected to have windows and do not come with message loops by default.
You can run a message loop by calling:
Application->Run();
However this will probably stop the console part of your application from working properly. How can your main thread service the console synchronously and the asynchronous GUI message loop at the same time?
I suspect you will need to have a more serious re-think of your application design.
Regarding your update, it seems that you do have a message loop, but it is the message loop for the GLUT framework. The VCL framework requires its message loop to handle dialog messages like TAB key presses.
It's plausible that running the VCL message loop in place of the GLUT message loop would give better results. But it's quite likely that would just break the GLUT part of the app.
Trying to run two incompatible GUI frameworks out of a single message loop is hard to get right. There's probably no quick fix here. You'll need to dig deeper. Perhaps it would be best to give up on the VCL and stick to the one GUI framework.

How can I stop executing .wlua files?

Is it possible to force stop a .wlua file? I figured that I would have to use the Lua Command Line to do this, but I can't seem to find out how to stop them.
If it's possible, how can it be done?
Because wlua.exe doesn't open the console window (that's the purpose) and you can't send Ctrl-C, the only way to terminate such application is to use Processes window in Task Manager. Note, however, that the process name will be wlua.exe for every file opened that way.
Of course, it's meant only to be used when the application isn't responding. Your GUI application should provide a way to close it, such as close button, listening for ESC key etc.

How can I detect a debugger or other tool that might be analysing my software?

A very simple situation. I'm working on an application in Delphi 2007 which is often compiled as 'Release' but still runs under a debugger. And occasionally it will run under SilkTest too, for regression testing. While this is quite fun I want to do something special...
I want to detect if my application is running within a debugger/regression-tester and if that's the case, I want the application to know which tool is used! (Thus, when the application crashes, I could report this information in it's error report.)
Any suggestions, solutions?
You can check the parent process that started your application.
With CreateToolhelp32Snapshot/Process32First/Process32Next get the parent PID (PROCESSENTRY32.th32ParentProcessID or TProcessEntry32.th32ParentProcessID) for your application PID. Then get the filename for the parent PID to compare with the applications you want to check for, like SilkTest.
Check this article for code usage.
In addition to IsDebuggerPresent and CheckRemoteDebuggerPresent, you can also query PEB.BeingDebugged (PEB is Process Environment Block, to get PEB you must query TEB, which is the Thread Enviroment Block).
You're probably looking for the IsDebuggerPresent function.
To detect SilkTest, you could try to attach to a DLL which is used only by SilkTest in order to detect its presence. For example, if the Open Agent is attached to a process, Win32HookDll_x86.dll or Win32HookDll_amd64.dll will be present (the names can be easily found out with a tool like Process Explorer.
You can also do
if DebugHook <> 0 then ...

How to tell if process is run by the Service Control Manager

I have a few Windows Services written in C# that I have setup to support being run from the command line as a console app if a specific parameter is passed. Works great but I would love to be able to detect whether the app is being run by the service control mananger or from a command line.
Is there any way to tell at runtime if my app was started by the SCM?
Environment.UserInteractive will return false if the process is running under the SCM.
The SCM will call your OnStart method, so you could mark that event and make sure when you run from the command line, you don't call OnStart. Or, you could check the startup parameters to see how the application was started.
In C the function StartServiceCtrlDispatcher() will fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT. This is the best way in C, wonder if C# exposes any of this?
ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
This error is returned if the program is being run as a console application rather than as a service. If the program will be run as a console application for debugging purposes, structure it such that service-specific code is not called when this error is returned.

Resources