FreeConsole() does not detach application from cmd - c++

I launch my application in cmd. I compiled it by Cmake without WIN32_EXECUTABLE, so it hangs in cmd (i.e. is launched as not detached). Now I want to close the console and try to achieve this by calling FreeConsole().
This works in case I double-click the application -- the black console is flashes quickly and gets closed. But it does not work when I launch it in cmd. The cmd is still attached to the launched application and FreeConsole() does not help.
Is there any way to detach it from cmd programmatically? I have found the opportunity to run start /b myapp, but I would like to do it in a programmatical way.
UPDATE
A rough implementation of the answer of Anders for those who are interested -- see below. In this implementation I pass all the arguments, supplied to main.com, to the child process main.exe.
// main.cpp
// cl main.cpp
// link main.obj /SUBSYSTEM:WINDOWS /ENTRY:"mainCRTStartup"
//
#include <stdio.h>
#include <Windows.h>
int main(int argc, char** argv)
{
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
freopen("CONIN$", "r", stdin);
}
for (int i = 0; i < argc; i++)
printf("--%s", argv[i]);
printf("Hello\n");
int k = 0;
scanf("%d", &k);
printf("%d\n", k);
return 0;
}
// helper.cpp
// cl helper.cpp
// link helper.obj /OUT:main.com
//
#include <windows.h>
#include <stdio.h>
#include <string.h>
void main( int argc, char **argv )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Reconstructing the command line args for main.exe:
char cmdLine[32767] = { 0 };
strcpy(cmdLine, "main.exe ");
int shift = strlen("main.exe ");
for (int i = 1 ; i < argc; i++)
{
strcpy(cmdLine + shift, argv[i]);
const int argLength = strlen(argv[i]);
cmdLine[shift + argLength] = ' ';
shift += (argLength + 1);
}
printf("\n!!!!%s!!!!!%s\n", cmdLine, GetCommandLine());
// Start the child process.
// https://learn.microsoft.com/en-us/windows/win32/procthread/creating-processes
//
if( !CreateProcess(NULL, // No module name (use command line)
cmdLine, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}

Creating a "perfect" application that can be both GUI or console is not possible on Windows.
When a .exe has its subsystem set to console, two things happen:
CreateProcess will attach it to the parents console. If the parent does not have one, a new console is created. This can only be suppressed by passing flags to CreateProcess.
cmd.exe will wait for the process to finish.
The trick of setting the subsystem to Windows and using AttachConsole is sub-optimal because cmd.exe will not wait.
The best solution is to create your main .exe as a Windows application. Create another console helper application that you rename from .exe to .com. The helper application will just launch the main app in GUI mode and then quit. In console mode it has to tell the main app that it needs to attach and you need to WaitForSingleObject on it. Example application available here .
Visual Studio uses this .com trick. The trick works because .com is listed before .exe in %pathext%.

Related

Creating "dir" command using CreateProcess function failed with error code 2

I was just playing with Win32-API and wanted to create a process using CreateProcess function. I used the following code from MSDN website:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
void _tmain( int argc, TCHAR *argv[] )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if( argc != 2 )
{
printf("Usage: %s [cmdline]\n", argv[0]);
return;
}
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
argv[1], // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
But surprisingly I can't create a dir process using this piece of code. Error code indicated that 'The system cannot find the file specified.'
I'm using Visual studio 2015 and Windows 7 64Bit. But when I run the same executable in Windows 10, everything is OK.
dir is not an external command that can be run. It's a command internal to the Windows Command Prompt. You'll need to call your program as myprogram "cmd /c dir" to do that.
Of course, there are better ways to iterate a directory than calling an external program, but that's a separate question.
After hours of going through 1500 lines of C code, it finally dawned on me what my problem was and why it worked on one Windows 10 system of mine but not on another. The system that it worked on, I really did have a DIR.EXE. But is was not the COMSPEC DIR that was running. I had DIR.EXEs in Git and MinGW folders.
Read this for how to correctly use CREATEPROCESS.
https://learn.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessa

How to execute another exe from a C++ program in Windows

I want my C++ program to execute another .exe, in Windows. How would I do this? I am using Visual C++ 2010.
Here is my code
#include "stdafx.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
unsigned int input;
cout << "Enter 1 to execute program." << endl;
cin >> input;
if(input == 1) /*execute program here*/;
return 0;
}
This is a solution I found when looking for an answer previously.
It stated that you should always avoid using system() because:
It is resource heavy
It defeats security -- you don't know you it's a valid command or does the same thing on every system, you could even start up programs you didn't intend to start up. The danger is that when you directly execute a program, it gets the same privileges as your program -- meaning that if, for example, you are running as system administrator then the malicious program you just inadvertently executed is also running as system administrator.
Anti virus programs hate it, your program could get flagged as a virus.
Instead CreateProcess() can be used. Createprocess() is used to just start up an .exe and creating a new process for it. The application will run independent from the calling application.
#include <Windows.h>
void startup(LPCSTR lpApplicationName)
{
// additional information
STARTUPINFOA si;
PROCESS_INFORMATION pi;
// set the size of the structures
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// start the program up
CreateProcessA
(
lpApplicationName, // the path
argv[1], // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NEW_CONSOLE, // Opens file in a separate console
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi // Pointer to PROCESS_INFORMATION structure
);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
you can use the system function
int result = system("C:\\Program Files\\Program.exe");
Use the CreateProcess() Function.
See http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29.aspx for details
You can make a call using system
system("./some_command")
I believe this answer should work with different programs, I tested it with Chrome.
// open program.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "string"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string command = "start chrome https://www.google.com/";
system(command.c_str());
return 0;
}

why Commands are not executed with CreateProcess

i hev problem with CreatProcess function introduced in windows.h header for c++.
whenever i try to pass it a TCHAR variable containing a cmd command it returns error : CreateProcess failed (2) .
and for this am waiting for your explanations and solutions.
consider code below:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
int _tmain( int argc, TCHAR *argv[] )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if( argc != 2 )
{
printf("Usage: %s [cmdline]\n", argv[0]);
return 0;
}
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
argv[1], // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return 0;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
notice:when i launch an application with specifying its path ..it works fine like=> "c:\code.exe";
If you want to run a command DOS, you have to run the shell cmd before.
CreateProcess doesn't do that for you.
The option /c of cmd permits to run a command in the shell and terminate. You just have to build a command line of the type cmd /c <your command here>.
I compiled your code on VS2012 and I tried : test.exe "cmd /c dir" and it works like a charm.
From the Microsoft documentation :
To run a batch file (or a batch command), you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following arguments: /c plus the name of the batch file.
Source : http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
In order to execute a command implemented by the command shell aka cmd.exe, you need to actually run cmd.exe. CreateProcess doesn't automatically do that for you.
Build a command line of the form cmd.exe /c <your command here>. /c means "run one command, then terminate".

Redirecting stdout output in cpp

I've been searching for an answer regarding this issue for a few days now, I hope you guys will be able to assist me. (I've searched and found some solutions, but each has its own issue...).
Here is the thing:
I'm writing an automation at work, which is responsible for launching an external ".exe" file of a code written by my colleagues. As those programs they write go to customers, I'm not allowed to make any modification to their code. Those programs, once launched, are waiting for specific key strokes, and prints a message when a legal key stroke has been received.
My goal is this:
To write a program which will execute the external program, send it key strokes, and receive the output from their stdout.
So far, I have been able to run the program from my program (using ShellExecute), and simulate some sort of keyboard listener (using SendMessage) to the other program. I can see that it works - I can see the output in the tested program's console.
I'm trying to fetch the messages printed on the tested program's shell in real-time (and just get a bulk of data when the program terminates) so that I could analyse it when it occurs.
Those I've tried:
Writing an external batch file with inline output redirection to a text file.
Using freopen.
Redirecting the output while exectuing "ShellExecute".
You use handles for stdin, stdout, and stderr. Create process with CreateProcess function to get that handles.
Sample code - incomplete for your case, but good example of how to do it:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
/*for test.exe
#include <iostream>
#include <string> */
void _tmain( int argc, TCHAR *argv[] )
{
/*for test.exe
std::cout << "test output" << std::endl;
for (;;)
{
std::string line;
std::getline(std::cin, line);
std::cout << "line: " << line << std::endl;
}
return;*/
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
"test.exe", // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d)\n", GetLastError() );
return;
}
/* HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;*/
HANDLE me_hStdInput = GetStdHandle(STD_INPUT_HANDLE);
HANDLE me_hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE proc_hStdInput = si.hStdInput;
HANDLE proc_hStdOutput = si.hStdOutput;
char buff[64];
DWORD chars;
while (!ReadConsole(me_hStdInput, buff, sizeof(buff), &chars, NULL))
{
for (DWORD written = 0, writtenThisTime; written < chars; written += writtenThisTime)
if (!WriteConsole(proc_hStdOutput, buff + written, chars - written, &writtenThisTime, NULL))
{
//handle error - TODO
}
}
//possibly handle error for ReadConsole - TODO
// Wait until child process exits.
//WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}

Launching an application from a thread with C++

I need to launch a 3rd party program inside a thread, wait to get the results both from stdout/stderr with C++.
What methods are available?
Are they cross-platform? I mean, can I use them both for cl/gcc?
On Unix:
http://linux.die.net/man/3/execl
#include <sys/types.h>
#include <unistd.h>
void run_process (const char* path){
pid_t child_pid;
/* Duplicate this process. */
child_pid = fork ();
if (child_pid != 0){
/* This is the parent process. */
int ret = waitpid(child_pid, NULL, 0);
if (ret == -1){
printf ("an error occurred in waitpid\n");
abort ();
}
}
else {
execl (path, path);
/* The execvp function returns only if an error occurs. */
printf ("an error occurred in execl\n");
abort ();
}
}
On Windows:
http://msdn.microsoft.com/en-us/library/ms682425%28v=vs.85%29.aspx
# include <windows.h>
void run_process (const char* path){
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
bool ret = = CreateProcess(
NULL, // No module name (use command line)
path, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
false, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi // Pointer to PROCESS_INFORMATION structure
)
if (!ret){
printf("Error");
abort();
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
system should be platform independant, but you might want to stick with createprocess (win)/ exec (others) if there is a concern about running the program with the same security privledges.
There is a set of posix functions to launch an external executable - see exec - which are cross platform. To do some specific tasks on windows you may need to use windows specific createprocess.
These generally block so you would have to start them in a new thread. Threading is generally not cross platform, although you can use posix (pthreads) on windows.
An alternative is to use somthing like Qt or wxWidgets cross platform libraries.