How do I write a program that can be run either as a console or a GUI application?
You can't, but you can try to fake it.
Each PE application contains a field in its header that specifies
which subsystem it was designed to run under.
You can say IMAGE_SUBSYSTEM_WINDOWS_GUI
to mark yourself as a Windows GUI application,
or you can say
IMAGE_SUBSYSTEM_WINDOWS_CUI to say that
you are a console application.
If you are GUI application, then the program will run
without a console.
The subsystem determines how the kernel prepares the execution environment
for the program.
If the program is marked as running in the console subsystem,
then the kernel will connect the program's console to the console
of its parent, creating a new console if the parent doesn't have a
console.
(This is an incomplete description, but the details aren't relevant
to the discussion.)
On the other hand, if the program is marked as running as a GUI
application,
then the kernel will run the program without any console at all.
There are some people who want to write what I call an
"opportunistic" console program.
These are programs that will use the console of their parent
if available, but do not want a console created for them if not.
The kernel doesn't support this type of program,
but that hasn't stopped
some people from coming up with clever workarounds.
Note that if such a program type were introduced,
it would create problems with programs such as
cmd.exe and Explorer which change their behavior
depending on what subsystem a program belongs to.
These programs would have to be modified to understand a new
pseudo-subsystem called "both".
I've also seen requests for what I call a
"dynamic" console program.
These are programs that want to decide at run time whether they
want a console or not.
For example, a program might want to run with a console
only if a special command line switch is passed.
To do this the kernel would have to have psychic powers:
It would somehow have to know whether to hook up a console
to your program or not (which happens before the program
begins executing)
based on something that happens in the future
(when your program actually runs and parses its command line
and decides whether it wants to run as a console or a GUI program).
Again, people have come up with workarounds (see earlier link).