How to conditionally enable console without opening separate console window - c++

I'd like to create a windows application that, under normal conditions, does not have any connected terminal, but may have one in some conditions. I tried two different routes. Option A, creating a normal console application, and conditionally calling FreeConsole():
int main()
{
if (someCondition) {
HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsoleA(stdOutHandle, "hello world\n", 12, NULL, NULL);
} else {
FreeConsole();
// normal operation
}
return 0;
}
And option B, creating a WinMain based application, and conditionally calling AllocConsole().
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow)
{
if (someCondition) {
AllocConsole();
HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsoleA(stdOutHandle, "hello world\n", 12, NULL, NULL);
}
else {
// normal operation
}
return 0;
}
The problem with option A, is that it doesn't act exactly like a windows application, in that you can very briefly see a console window open up before normal operation continues. This isn't a huge problem, but I'd prefer the program to act, as I said, exactly like a normal windows application.
The problem with option B is that, if the program is invoked from an existing terminal, it opens up a separate terminal window and outputs to that, instead of outputting to the terminal from which it was invoked. This is a much bigger problem.
What is the appropriate solution to conditionally behave as either a console program or a windows program, without either of the problems described above?
Edit
Based on a suggestion in the comments, I tried to use the AttachConsole function.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow)
{
if (someCondition) {
AttachConsole(ATTACH_PARENT_PROCESS);
HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
Sleep(3000);
WriteConsoleA(stdOutHandle, "hello world\n", 12, NULL, NULL);
FreeConsole();
}
else {
// normal operation
}
return 0;
}
This seems to be on the right track, but there is still something missing, because my shell prompt is immediately printed out without waiting for the program to finish.

Impossible.
AttachConsole does not work 100% because cmd.exe actually checks if the process it is about to start is a GUI app or not, and alters its behavior.
The only way to make it work is to have two programs; myapp.com and myapp.exe. %PathExt% lists .com before .exe so you can make a console .exe and rename it .com at it will be executed if the user runs "myapp" (but will not work if the user types "myapp.exe"). If your program is not very big you can just ship two versions. If the program is large you can move most of the code to a .dll or make the .com a small helper that calls the .exe with a command line parameter and some pipes for stdin/stdout. Visual Studio does this (devenv.com).

If you want to check if there is already a console, check for a NULL return from GetConsoleWindow(). If it returns null, then do the AllocConsole procedure and other setup (SetWindowLong, SetConsoleMode etc)
int main() programs don't make a console by default, they happen to attach into a console if run through cmd/ps.

One way is the following:
BOOL WINAPI
AttachOrCreateConsole()
{
if(AttachConsole(ATTACH_PARENT_PROCESS))
{
return TRUE;
}
return AllocConsole();
}
This will use the parent console if available and fall back to creating one if needed.
Note that if yo do this and want to use the standard C/C++ I/O mechanisms (stdin/std::cin, stdout/std::cout) you will need to do the work needed to associate those streams to the console handle. There is plenty of material available on how to do that.

Related

My program doesn't put characters out on the screen

I have tried several things but none of them did work. Does someone know what the problem is? Here's my code:
#include <iostream>
#include <Windows.h>
#include <iomanip>
#include <fstream>
#include <stdio.h>
using namespace std;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int CmdShow) {
cout << "Hello World" << endl;
return 0;
}
Thanks
If you are using visual studio, and create a Win32 application, it will not create a console so the output does not appear on any window. If you create a Win32 Console application, std::cout will be directed to the console window but you will need to use a standard main() program entry point.
To avoid creating a new project, modify your code as shown here:
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int CmdShow) {
AllocConsole();
AttachConsole(GetCurrentProcessId());
freopen("CONOUT$", "w", stdout);
cout << "Hello World" << endl;
return 0;
}
On Windows, there are two main types of programs:
Console applications for single textual input and output. These are typically started from the command line in a command prompt.
GUI applications which use windows, buttons, the mouse, touch, etc. These are typically started by choosing from the start menu or double-clicking on an icon.
(There are ways to have a single application work both ways, but that's almost certainly not what you're after.)
Your code is exhibiting indications of trying to be both. It has a wWinMain, which suggests it's a GUI application, but it does regular textual output using std::cout, which suggests it's a console application.
I think you want a console application, but you accidentally started by choosing a Win32 application in the Visual Studio New Project Wizard. To fix this without starting over:
First, get rid of the unnecessary includes, specifically, delete #include <windows.h>.
Next Change the wWinMain to a standard C++ main function, like this:
int main() {
cout << "Hello World" << endl;
return 0;
}
Finally, right-click on your project in the Solution Explorer, and choose Properties from the pop-up menu. At the top of the pop-up dialog, set Configuration to All Configurations. In the left side, expand Linker and choose System, then, on the right side, change the SubSystem field to Console (/SUBSYSTEM:CONSOLE). Click OK.
Now you should be able to rebuild your program and it'll work.
One word of warning: If you run it directly from Visual Studio, a new console window will appear and, in the blink of an eye, your program will complete and the new console window will disappear, which makes it hard to tell if you did the right thing.
If you start your program from a CMD prompt, you won't have that problem. If you want to run from the debugger, put a breakpoint on the return statement in your main function. That will halt the program in the debugger just before it ends, and you'll be able to see what's in the console window. Some people have the program ask for keyboard input right before it finishes, which gives the user a change to see what's in the console window before it vanishes.
It appears you have created a windows application rather than a console application.
A console application has a main function with signature:
int main(int argc, char ** argv);
A windows application has a main function with signature:
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int CmdShow);
The latter is intended for applications that actually create a window. You choose which to create using the wizard in Visual Studio when you go to create a new project (assuming you are using Visual Studio).
Use:
https://msdn.microsoft.com/en-us/library/ms235629.aspx
Also, it is possible your application is exiting before you see the output.
In this case, we can use a non-standard platform specific call to ::system("pause") to make it wait until you hit a key to continue.
#include <iostream>
#include <iomanip>
#include <fstream>
#include <windows.h>
using namespace std;
int main(int argc, char ** argv)
{
cout << "Hello World" << endl;
system("pause");
return 0;
}
Alternativly, place a break point on the line where it says return 0; and use F5 to debug.

system() without prompt, c++, winmain

I am using c++ and i have a program that works with winmain.
I do not want the system() call to open and close a window.
example:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
system("dir > nul 2> nul");
return 0;
}
I want to use system calls but I don't want them to open a new window.
Thanks in advance.
edit:
I found this solution:
To execute cmd commands without opening a window i create a bat file (the program does this) then i use this code:
ShellExecute(NULL, "open", "Directory_Of_Bat_File", NULL, NULL, 0);
This opens the bat file and executes the commands.
I also noticed that you don't need system() to delete the bat file but you can delete it by writing:
del Directory_Of_Bat_File
Inside the bat file and this will delete it when you execute the bat file (it will delete itself).
This without opening a new window.
Since system, by its definition, creates a new process with a command interpreter, you can't do that.
From MSDN subject system
The system function passes command to the command interpreter, which
executes the string as an operating-system command.
If you want to do "dir", since that's a built-in command in the "cmd.exe" or whatever command interpreter you are using, it's pretty difficult to "fix" this issue - even using ShellExecute or CreateProcess will not help a whole lot, since you will get a window either way - it may be minimizes or something like that, but it will still be a window there.
Use CreateProcess or ShellExecute to launch the process, there you can pass options related to windows. what system() executes can normally be found in environment, getenv("ComSpec")
I found this solution:
To execute cmd commands without opening a window I create a bat file (the program does this) then I use this code:
ShellExecute(NULL, "open", "Directory_Of_Bat_File", NULL, NULL, 0);
This opens the bat file and executes the commands. I also noticed that you don't need system() to delete the bat file but you can delete it by writing:
del Directory_Of_Bat_File
Inside the bat file and this will delete it when you execute the bat file (it will delete itself). This without opening a new window.

C++ WIN32: Running a program without a command prompt window

I have written a program which triggers a relay switch on a serial port. The relay is closed for 10ms, after which the program closes. However, the program insists on running in a small command prompt window. I would like the program to run without stealing focus; either by running in the background or, even better, without opening a window at all.
Here is the complete program:
#include <windows.h>
//Initialise Windows module
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance,
LPSTR lpszArgument, int nFunsterStil)
{
//Define the serial port precedure
HANDLE hSerial;
//Open the port
hSerial = CreateFile("COM1",GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
//Switch on relay
EscapeCommFunction(hSerial, SETDTR);
//Wait 10ms
Sleep(10);
//Switch off relay
EscapeCommFunction(hSerial, CLRDTR);
//Close the port
CloseHandle(hSerial);
//End with error code 0
return 0;
}
What must I change in order to prevent it running in a window?
Try adding #pragma comment(linker, "/SUBSYSTEM:WINDOWS")
If that does not work try to hide the window manually:
HWND hWnd = GetConsoleWindow();
ShowWindow( hWnd, SW_HIDE );
What type of project did you create? If you selected console application, the compiler is doing it. Make an empty Win32 application with the above source. No window should be created. If it is, consider how you're launching the application (start, cmd /c, etc)

Basic dialog box input for a strobe light implementation

I have connected a photographic flash unit to my computer using a relay switch connected to the serial port. The following code causes the strobe to flash at 4Hz for 10 flashes:
#include <windows.h>
//Initialise Windows module
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil)
{
//Define the serial port precedure
HANDLE hSerial;
int freq = 4;
int iterations = 10;
int x;
for ( x = 0; x < iterations; x++)
{
//Fire the flash (open the serial port, and immediately close it)
hSerial = CreateFile("COM1",GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
CloseHandle(hSerial);
//Sleep in between flashes for specified duration
Sleep (1000/freq);
}
return 0;
}
How do I implement dialog boxes at the beginning of the program so that the user can input the values of 'freq' and 'iterations'?
Open Visual Studio, New, Project,
Visual C++, Windows Forms
Application. This will give you a
GUI where you can drag and drop what
you need. If you don't have Visual
Studio then perhaps your IDE has
something similar?
Make this a console app that accepts the data in the command line. Call the app with an appropriate command line from a GUI created in any other programming language/ framework.
Make the GUI in C# and use P/Invoke to call CreateFile; it's not that hard.
Btw, does the CreateFile/CloseHandle approach really work? I find it to be a bit "hacky" and I'm not sure it's the best approach. Perhaps another answer or a comment will touch this aspect as well.

Create an Application without a Window

How would you program a C/C++ application that could run without opening a window or console?
When you write a WinMain program, you automatically get the /SUBSYSTEM option to be windows in the compiler. (Assuming you use Visual Studio). For any other compiler a similar option might be present but the flag name might be different.
This causes the compiler to create an entry in the executable file format (PE format) that marks the executable as a windows executable.
Once this information is present in the executable, the system loader that starts the program will treat your binary as a windows executable and not a console program and therefore it does not cause console windows to automatically open when it runs.
But a windows program need not create any windows if it need not want to, much like all those programs and services that you see running in the taskbar, but do not see any corresponding windows for them. This can also happen if you create a window but opt not to show it.
All you need to do, to achieve all this is,
#include <Windows.h>
int WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int cmdShow)
{
/* do your stuff here. If you return from this function the program ends */
}
The reason you require a WinMain itself is that once you mark the subsystem as Windows, the linker assumes that your entry point function (which is called after the program loads and the C Run TIme library initializes) will be WinMain and not main. If you do not provide a WinMain in such a program you will get an un-resolved symbol error during the linking process.
In windows:
#include <windows.h>
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
// <-- Program logic here
return 0;
}
Be sure to use the /SUBSYSTEM linker switch as mentioned by Adam Mitz.
On other platforms:
int main(int argc, char**argv)
{
// <-- Program logic here
return 0;
}
If you have a need to contiguously run your program without having console or window you might find useful deamon on *NIX or services on Windows, this .NET example if you need plain win32 just google a little bit for sample.
Since your question tagged as win32 i assume that services are more relevant for you.
This also processes messages:
#include <windows.h>
#include <stdio.h>
int CALLBACK WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MSG msg;
DWORD curThreadId;
curThreadId = GetCurrentThreadId();
// Send messages to self:
PostThreadMessage(curThreadId, WM_USER, 1, 2);
PostThreadMessage(curThreadId, WM_USER+1, 3, 4);
PostThreadMessage(curThreadId, WM_USER+2, 5, 6);
PostThreadMessage(curThreadId, WM_USER+3, 7, 8);
PostThreadMessage(curThreadId, WM_QUIT, 9, 10);
while (GetMessage(&msg, NULL, 0, 0)) {
printf("message: %d; wParam: %d; lParam: %d\n", msg.message, msg.wParam, msg.lParam);
}
return (int) msg.wParam;
}
In Visual Studio Express 2010 after setting the subsystem to windows (as suggested by user17224), alternatively to changing the main to WinMain (as suggested by user17224 and Brian R. Bondy), one can set the entry function to main in properties, linker, advanced, entry point: just type main in the text box.
Use Visual Studio wizard to create the Win32 Application. But don't create the window i.e., you remove the window creation function.
Alternatively we can create Win Service application.
If you are using MSVC or Visual Studio just use the new Project Wizard and select the Console Application.