How do I call ::CreateProcess in c++ to launch a Windows executable? - c++

Looking for an example that:
Launches an EXE
Waits for the EXE to finish.
Properly closes all the handles when the executable finishes.

Something like this:
STARTUPINFO info={sizeof(info)};
PROCESS_INFORMATION processInfo;
if (CreateProcess(path, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
{
WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}

There is an example at http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx
Just replace the argv[1] with your constant or variable containing the program.
#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 );
}

If you application is a Windows GUI application then using the code below to do the waiting is not ideal as messages for your application will not be getting processing. To the user it will look like your application has hung.
WaitForSingleObject(&processInfo.hProcess, INFINITE)
Something like the untested code below might be better as it will keep processing the windows message queue and your application will remain responsive:
//-- wait for the process to finish
while (true)
{
//-- see if the task has terminated
DWORD dwExitCode = WaitForSingleObject(ProcessInfo.hProcess, 0);
if ( (dwExitCode == WAIT_FAILED )
|| (dwExitCode == WAIT_OBJECT_0 )
|| (dwExitCode == WAIT_ABANDONED) )
{
DWORD dwExitCode;
//-- get the process exit code
GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
//-- the task has ended so close the handle
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
//-- save the exit code
lExitCode = dwExitCode;
return;
}
else
{
//-- see if there are any message that need to be processed
while (PeekMessage(&message.msg, 0, 0, 0, PM_NOREMOVE))
{
if (message.msg.message == WM_QUIT)
{
return;
}
//-- process the message queue
if (GetMessage(&message.msg, 0, 0, 0))
{
//-- process the message
TranslateMessage(&pMessage->msg);
DispatchMessage(&pMessage->msg);
}
}
}
}

if your exe happens to be a console app, you might be interested in reading the stdout and stderr -- for that, I'll humbly refer you to this example:
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q190351
It's a bit of a mouthful of code, but I've used variations of this code to spawn and read.

On a semi-related note, if you want to start a process that has more privileges than your current process (say, launching an admin app, which requires Administrator rights, from the main app running as a normal user), you can't do so using CreateProcess() on Vista since it won't trigger the UAC dialog (assuming it is enabled). The UAC dialog is triggered when using ShellExecute(), though.

Here is a new example that works on windows 10. When using the windows10 sdk you have to use CreateProcessW instead. This example is commented and hopefully self explanatory.
#ifdef _WIN32
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <tchar.h>
#include <cstdlib>
#include <string>
#include <algorithm>
class process
{
public:
static PROCESS_INFORMATION launchProcess(std::string app, std::string arg)
{
// Prepare handles.
STARTUPINFO si;
PROCESS_INFORMATION pi; // The function returns this
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
//Prepare CreateProcess args
std::wstring app_w(app.length(), L' '); // Make room for characters
std::copy(app.begin(), app.end(), app_w.begin()); // Copy string to wstring.
std::wstring arg_w(arg.length(), L' '); // Make room for characters
std::copy(arg.begin(), arg.end(), arg_w.begin()); // Copy string to wstring.
std::wstring input = app_w + L" " + arg_w;
wchar_t* arg_concat = const_cast<wchar_t*>( input.c_str() );
const wchar_t* app_const = app_w.c_str();
// Start the child process.
if( !CreateProcessW(
app_const, // app path
arg_concat, // Command line (needs to include app path as first argument. args seperated by whitepace)
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() );
throw std::exception("Could not create child process");
}
else
{
std::cout << "[ ] Successfully launched child process" << std::endl;
}
// Return process handle
return pi;
}
static bool checkIfProcessIsActive(PROCESS_INFORMATION pi)
{
// Check if handle is closed
if ( pi.hProcess == NULL )
{
printf( "Process handle is closed or invalid (%d).\n", GetLastError());
return FALSE;
}
// If handle open, check if process is active
DWORD lpExitCode = 0;
if( GetExitCodeProcess(pi.hProcess, &lpExitCode) == 0)
{
printf( "Cannot return exit code (%d).\n", GetLastError() );
throw std::exception("Cannot return exit code");
}
else
{
if (lpExitCode == STILL_ACTIVE)
{
return TRUE;
}
else
{
return FALSE;
}
}
}
static bool stopProcess( PROCESS_INFORMATION &pi)
{
// Check if handle is invalid or has allready been closed
if ( pi.hProcess == NULL )
{
printf( "Process handle invalid. Possibly allready been closed (%d).\n");
return 0;
}
// Terminate Process
if( !TerminateProcess(pi.hProcess,1))
{
printf( "ExitProcess failed (%d).\n", GetLastError() );
return 0;
}
// Wait until child process exits.
if( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_FAILED)
{
printf( "Wait for exit process failed(%d).\n", GetLastError() );
return 0;
}
// Close process and thread handles.
if( !CloseHandle( pi.hProcess ))
{
printf( "Cannot close process handle(%d).\n", GetLastError() );
return 0;
}
else
{
pi.hProcess = NULL;
}
if( !CloseHandle( pi.hThread ))
{
printf( "Cannot close thread handle (%d).\n", GetLastError() );
return 0;
}
else
{
pi.hProcess = NULL;
}
return 1;
}
};//class process
#endif //win32

Perhaps this is the most complete?
http://goffconcepts.com/techarticles/createprocess.html

Bear in mind that using WaitForSingleObject can get you into trouble in this scenario. The following is snipped from a tip on my website:
The problem arises because your application has a window but isn't pumping messages. If the spawned application invokes SendMessage with one of the broadcast targets (HWND_BROADCAST or HWND_TOPMOST), then the SendMessage won't return to the new application until all applications have handled the message - but your app can't handle the message because it isn't pumping messages.... so the new app locks up, so your wait never succeeds.... DEADLOCK.
If you have absolute control over the spawned application, then there are measures you can take, such as using SendMessageTimeout rather than SendMessage (e.g. for DDE initiations, if anybody is still using that). But there are situations which cause implicit SendMessage broadcasts over which you have no control, such as using the SetSysColors API for instance.
The only safe ways round this are:
split off the Wait into a separate thread, or
use a timeout on the Wait and use PeekMessage in your Wait loop to ensure that you pump messages, or
use the MsgWaitForMultipleObjects API.

Here is a solution for CreateProcessA
STARTUPINFOW initInfo = { 0 };
initInfo.cb = sizeof(initInfo);
PROCESS_INFORMATION procInfo = { 0 };
CreateProcessA(PATH_FOR_EXE, NULL, NULL, NULL, FALSE, 0, NULL, NULL, (LPSTARTUPINFOA)&initInfo, &procInfo);

#include <Windows.h>
void my_cmd()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// CMD command here
char arg[] = "cmd.exe /c E:/Softwares/program.exe";
// Convert char string to required LPWSTR string
wchar_t text[500];
mbstowcs(text, arg, strlen(arg) + 1);
LPWSTR command = text;
// Run process
CreateProcess (NULL, command, NULL, NULL, 0,
CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
}
This works fine for me. No popup windows and cmd command runs as expected. Just needed to convert the CHAR pointer into WCHAR pointer and add extra "cmd.exe /c" before every command.

Related

How do I call the unicode function CreateProcessW in c++ to launch a Windows executable?

There is an example of how to call CreateProcess on stack exchange here, however this seems to be no longer supported on Windows 10, and you must use the unicode version CreateProcessW.
In a similar vein to the ASCI version, I am looking for an example that:
Launches an EXE
Waits for the EXE to finish.
Properly closes all the handles when the executable finishes.
There is nothing new about Windows 10 in this respect. Your question is really about Unicode versus ANSI, and Visual Studio's new default settings which use Unicode.
CreateProcess is a macro, it is defined as
#ifdef UNICODE
#define CreateProcess CreateProcessW
#else
#define CreateProcess CreateProcessA
#endif // !UNICODE
In addition STARTUPINFO is a macro for STARTUPINFOA and STARTUPINFOW
CreateProcessA uses ANSI char strings char* and STARTUPINFOA
CreateProcessW uses Unicode wide char strings wchar_t* and STARTUPINFOW
If you insist on using ANSI (not recommended) then go to Project Settings -> Character Set and disable Unicode.
If you insist on using ANSI version with Unicode settings (still not recommended), you need
//Using ANSI when UNICODE is defined (not recommended):
STARTUPINFOA si = { sizeof(si) };
PROCESS_INFORMATION pi;
std::string path = "c:\\windows\\notepad.exe \"c:\\test\\_text.txt\"";
//if not using C++11 or later, force a zero at the end
//to make sure path is null-ternminated
path.push_back(0);
if(CreateProcessA(NULL, &path[0], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Above code will work as long as the directory names are ANSI compatible. But the recommended version is:
//recommended:
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
std::wstring path = L"c:\\windows\\notepad.exe \"c:\\test\\_text.txt\"";
//if not using C++11 or later, force a zero at the end
//to make sure path is null-ternminated
path.push_back(0);
if(CreateProcess(0, &path[0], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
Also, don't cast from constant string to string as follows:
wchar_t* arg_concat = const_cast<wchar_t*>( input.c_str() );
The second argument in CreateProcess should be wchar_t* because the process may modify the command line.
This example is commented and hopefully self explanatory.
#ifdef _WIN32
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <cstdlib>
#include <string>
#include <algorithm>
class process
{
public:
static PROCESS_INFORMATION launchProcess(std::string app, std::string arg)
{
// Prepare handles.
STARTUPINFO si;
PROCESS_INFORMATION pi; // The function returns this
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
//Prepare CreateProcess args
std::wstring app_w(app.length(), L' '); // Make room for characters
std::copy(app.begin(), app.end(), app_w.begin()); // Copy string to wstring.
std::wstring arg_w(arg.length(), L' '); // Make room for characters
std::copy(arg.begin(), arg.end(), arg_w.begin()); // Copy string to wstring.
std::wstring input = app_w + L" " + arg_w;
wchar_t* arg_concat = const_cast<wchar_t*>( input.c_str() );
const wchar_t* app_const = app_w.c_str();
// Start the child process.
if( !CreateProcessW(
app_const, // app path
arg_concat, // Command line (needs to include app path as first argument. args seperated by whitepace)
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() );
throw std::exception("Could not create child process");
}
else
{
// Return process handle
return pi;
}
}
static bool checkIfProcessIsActive(PROCESS_INFORMATION pi)
{
// Check if handle is closed
if ( pi.hProcess == NULL )
{
printf( "Process handle is closed or invalid (%d).\n");
return FALSE;
}
// If handle open, check if process is active
DWORD lpExitCode = 0;
if( GetExitCodeProcess(pi.hProcess, &lpExitCode) == 0)
{
printf( "Cannot return exit code (%d).\n", GetLastError() );
throw std::exception("Cannot return exit code");
}
else
{
if (lpExitCode == STILL_ACTIVE)
{
return TRUE;
}
else
{
return FALSE;
}
}
}
static bool stopProcess( PROCESS_INFORMATION &pi)
{
// Check if handle is invalid or has allready been closed
if ( pi.hProcess == NULL )
{
printf( "Process handle invalid. Possibly allready been closed (%d).\n");
return 0;
}
// Terminate Process
if( !TerminateProcess(pi.hProcess,1))
{
printf( "ExitProcess failed (%d).\n", GetLastError() );
return 0;
}
// Wait until child process exits.
if( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_FAILED)
{
printf( "Wait for exit process failed(%d).\n", GetLastError() );
return 0;
}
// Close process and thread handles.
if( !CloseHandle( pi.hProcess ))
{
printf( "Cannot close process handle(%d).\n", GetLastError() );
return 0;
}
else
{
pi.hProcess = NULL;
}
if( !CloseHandle( pi.hThread ))
{
printf( "Cannot close thread handle (%d).\n", GetLastError() );
return 0;
}
else
{
pi.hProcess = NULL;
}
return 1;
}
};//class process
#endif //win32

How to execute external programm in the parent C++ programm in Windows?

int system(const char *str);
declared in stdlib.h
As I know, this code will spawn a new process not within parent process and in Task Manager will be two processes - parent and child.
How to spawn child process in the parent process? ie in Task Manager must be only one - parent - process.
#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 );
}
Source: MSDN

CreateProcess not in primary thread

I use CreateProcess() to start a other programm from my C++ code.
The helppage says that it
Creates a new process and its primary thread. The new process runs in the security context of the calling process.
I would like to have it in his own thread, so the application would keep on going. Is there any simple way to do so? I am not familar with boost and Co.
My code:
bool startup(LPWSTR lpApplicationName)
{
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)
lpApplicationName, // 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 false;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return true;
}
and how to call the function:
int _tmain(int argc, _TCHAR* argv[])
{
wchar_t path[] = L"C:\\path\\to\\paridise.exe";
startup(path);
}
Transforming the comment by ElderBug in a reply
The problem in your code is the presence of an infinite wait after the CreateProcess call:
WaitForSingleObject( pi.hProcess, INFINITE );
Just comment it and the program execution will not stop.
I also did this same error and I stumbled in this SO question; the fact is that many of us get the code from the MSDN example here (without much attention), which has in fact this infinite wait.

How do you write to a second console?

I had the idea of using a second console in my programs for the purpose of logging programming activity. I looked around on msdn for related functions/examples and tried to put together a simple program to do so:
//function in parent that communicates with child
void writeToChild()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
HANDLE inWrite, inRead,
outWrite, outRead;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&inRead, &inWrite, &saAttr, 0))
{
exit(0xbad);
}
if ( ! SetHandleInformation(inRead, HANDLE_FLAG_INHERIT, 0) )
{
exit(0xbad);
}
if (!CreatePipe(&outRead, &outWrite, &saAttr, 0))
{
exit(0xbad);
}
if ( ! SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, 0) )
{
exit(0xbad);
}
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
si.lpTitle = "Log";
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = outWrite;
si.hStdError = outWrite;
si.hStdInput = inRead;
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL,
"Logger",
NULL,
NULL,
TRUE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi )
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
exit(0xbad);
}
unsigned long numWritten = 0;
WriteFile(inWrite, "Test", 4, &numWritten, NULL);
cout<<"wrote "<<numWritten<<" characters"<<endl;
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
//Logger
#include <windows.h>
#define BUFSIZE 4096
int main()
{
HANDLE stdin, stdout;
stdin = GetStdHandle(STD_INPUT_HANDLE);
stdout = GetStdHandle(STD_OUTPUT_HANDLE);
char buffer[BUFSIZE];
unsigned long numRead;
while (true)
{
ReadFile(stdin, buffer, BUFSIZE, &numRead, NULL);
if (numRead > 0)
WriteFile(stdout, buffer, numRead, NULL, NULL);
}
return 0;
}
The problem is that while the parent displays that 4 characters were written, nothing appears on the child console. I'm not sure how to go about debugging this because I have next to no experience with windows programming.
I am not quite sure where you are going with the separate process in your code snippet. However, you can't have more than one console associated with a single process in Windows, although you can have multiple screen buffers associated with a single console and toggle between them (see SetConsoleActiveScreenBuffer and go from there), but you'll have to implement a user-interface for that toggling; it's not a built-in thing.
If the screen buffers do not work for you, you could have a second logger process that you communicate with via pipes or loopback sockets or some other IPC method, though, e.g.:
You can use syslog, which is a common logging facility used by various applications and hardware.
You can also write to a log file and use a program to watch the file, e.g. the Windows equivalent of tail -f. This has the bonus of storing the logged data in a file for easy review later.
You could have your application act as a TCP server, telnet to it, and dump log messages via telnet.
Note that for any of the above options, as a convenience to your user, you can have your application start the second log watching process separately (with just a simple call to ShellExecute, don't go overboard).
Other options include:
You could use the Windows event log, although it can be a bit cumbersome.
You could create a separate GUI window with a text field or a list in it that displays log messages.
If your program is a GUI application that doesn't have its own console (from your description, this does not seem to be the case, but just for completeness) you can create a single console for it with AllocConsole and friends (but note that closing that console while it is still attached will also terminate your application).
There are many choices here. But you can't have two consoles for the same process.
Here is a summary of how I've managed to do it:
//parent process
YourString pipeName = format(L"\\\\.\\pipe\\%s", pName);
HANDLE hPipe = CreateNamedPipe(pipeName, /*dwOpenMode*/PIPE_ACCESS_OUTBOUND,
/*dwPipeMode*/PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
/*nMaxInstances*/PIPE_UNLIMITED_INSTANCES,
/*nOutBufferSize*/10000, /*nInBufferSize*/10000, /*nDefaultTimeOut*/50,
/*lpSecurityAttributes*/NULL);
//[check return value]
PROCESS_INFORMATION pi = {};
STARTUPINFOW si = {};
YourString commandLine = format(L"\"%s\" \"%s\"", childProcessExeFileName, pipeName);
HANDLE hProcess = CreateProcess(
/*lpApplicationName*/NULL, /*lpCommandLine*/commandLine,
/*lpProcessAttributes*/NULL, /*lpThreadAttributes*/NULL,
/*bInheritHandles*/TRUE, /*dwCreationFlags*/CREATE_NEW_CONSOLE,
/*lpEnvironment*/NULL, /*lpCurrentDirectory*/NULL,
&si, &pi);
//[check return value]
lpBuffer = ...
nNumberOfBytesToWrite = len(lpBuffer);
WriteFile(hPipe, lpBuffer, nNumberOfBytesToWrite, /*lpNumberOfBytesWritten*/NULL, /*lpOverlapped*/NULL);
//child process
int main(int argc, char ** argv) {
HANDLE hPipe = CreateFile(argv[1], GENERIC_READ, 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
//[check return value]
ULONG PID;
BOOL ok = GetNamedPipeServerProcessId(hPipe, &PID);
//[check return value]
HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, PID);
//[check return value]
char buffer[1000];
DWORD nByteRead;
while (WaitForSingleObject(hProcess, 0) == WAIT_TIMEOUT) {
if (hPipe) {
ok = ReadFile(hPipe, buffer,
sizeof(buffer) - 1, &nByteRead, NULL);
buffer[nByteRead] = 0;
if (!ok) {
if (GetLastError() != ERROR_BROKEN_PIPE) ERROR();
hPipe = NULL;
}
else printf("%s", buffer);
}
else Sleep(1000);
}
return 1;
}
If you are interested I could send you a class that uses this, with a simple syntax:
WinConsole secondConsole;
secondConsole.Printf("Hello %s\n", "World");
This let you have as many consoles as you want.

how to save executed output cmd line in file in c++

I have this code for execute CMD line in c++
#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 );
}
I want save executed output in file.but how?
In CreateProcess you pass a STARTUPINFO-structure. You can set the STARTF_USESTDHANDLES in si.dwFlags and then fill out the hStdInput, hStdOutput, and hStdError-fields with valid file-descriptors, especially hStdOutput should be a handle to a previously opened file (returned by successful CreateFile) which will then receive the std-output of the started process.
Edit:
This was kind of mean answer, because it needs more work to make that thing work: You need to create that file with the right SECURITY_ATTRIBUTES and have to set the Set handle inheritance to TRUE in CreateProcess. So it's also kind of purists nightmare to do it that way.
#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);
si.dwFlags |=STARTF_USESTDHANDLES ;
si.hStdInput=GetStdHandle(STD_INPUT_HANDLE);
si.hStdError=GetStdHandle(STD_ERROR_HANDLE);
SECURITY_ATTRIBUTES sa;
ZeroMemory( &sa, sizeof(sa) );
sa.nLength=sizeof(sa);
sa.bInheritHandle=TRUE;
si.hStdOutput=CreateFile ("log.txt", GENERIC_READ|GENERIC_WRITE, 0, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
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
TRUE, // Set handle inheritance to TRUE
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 );
CloseHandle (si.hStdOutput);
}
Either redirect stdout to a file with
freopen("file.txt", "w", stdout);
Or, pipe the output to a file with windows
cmd> prg.exe > file.txt