I posted a thread about how to do this in batch but it turns out batch scripting isn't very popular and I barely even know it so now I'm asking for your help doing this in C++.
here's what I tried
#include <Windows.h>
using namespace std;
void openBat(char* path) {
system(path);
}
int main() {
for(;;) {
openBat("C:\\Users\\Ivan\\Desktop\\folder\\run.bat");
Sleep(1800000);
//kill opened process
}
return 0;
}
I'm not sure how to kill the opened process because every time I run the bat script it will have a new ID and I can't kill by name because I need to have 4 of these open. All help is appreciated.
What you're doing there isn't really C++. You're basically using windows to interprete the commands you pass it like batch would do. Here is what you want to do in C++, even if it only runs on Windows.
#include <Windows.h>
#include <string>
std::wstring GetEnvString()
{
wchar_t* env = GetEnvironmentStrings();
std::wstring result{ env };
FreeEnvironmentStrings(env);
result.push_back('\0');
return result;
}
int main()
{
//Setup needed structures
STARTUPINFO si{ sizeof si };
PROCESS_INFORMATION pi;
//Command line (read- and writeable)
wchar_t cmd[] = L"cmd.exe /C C:\\Users\\Ivan\\Desktop\\folder\\run.bat";
//Create process
CreateProcess(nullptr, cmd, nullptr, nullptr, false, CREATE_UNICODE_ENVIRONMENT,
const_cast<wchar_t*>(GetEnvString().c_str()), nullptr, &si, &pi);
Sleep(1800000);
//Process Termination
TerminateProcess(pi.hProcess, 0);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
I'd recommend you read up on the CreateProcess function, as well as the Terminate Process one. There is also an example from Microsoft about how to use the former of the two. I hope this information can help you.
edit: Fixed stuff. Should work now. Credits to user4581301, his links were really useful.
I think the solution can be killing the self process tree without killing process itself.
Terminate a process tree (C for Windows)
When you create a process, hold onto the process handle and use the handle to terminate the when you are done. With the handle you know exactly which of possibly thousands of instances of the same process you want dead.
Note: Terminating a process may have undesirable results. You are almost always better off writing the processes in such a way that you can message them and request that they terminate themselves politely. How you would do this with a batch file... Smurfed if I know. Someone else may have a waaaaay better answer to this problem, and I'm fine with that. One day I might need that better solution.
On Windows you likely want CreateProcess and TerminateProcess.
Running a batchfile with CreateProcess is covered here: Use CreateProcess to Run a Batch File
Terminating a process launched with Create process is covered here:
how to terminate a process created by CreateProcess()?
Related
I am writing a baby program for practice. What I am trying to accomplish is basically a simple little GUI which displays services (for Linux); with buttons to start, stop, enable, and disable services (Much like the msconfig application "Services" tab in Windows). I am using C++ with Qt Creator on Fedora 21.
I want to create the GUI with C++, and populating the GUI with the list of services by calling bash scripts, and calling bash scripts on button clicks to do the appropriate action (enable, disable, etc.)
But when the C++ GUI calls the bash script (using system("path/to/script.sh")) the return value is only for exit success. How do I receive the output of the script itself, so that I can in turn use it to display on the GUI?
For conceptual example: if I were trying to display the output of (systemctl --type service | cut -d " " -f 1) into a GUI I have created in C++, how would I go about doing that? Is this even the correct way to do what I am trying to accomplish? If not,
What is the right way? and
Is there still a way to do it using my current method?
I have looked for a solution to this problem but I can't find information on how to return values from Bash to C++, only how to call Bash scripts from C++.
We're going to take advantage of the popen function, here.
std::string exec(char* cmd) {
FILE* pipe = popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
std::string result = "";
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);
return result;
}
This function takes a command as an argument, and returns the output as a string.
NOTE: this will not capture stderr! A quick and easy workaround is to redirect stderr to stdout, with 2>&1 at the end of your command.
Here is documentation on popen. Happy coding :)
You have to run the commands using popen instead of system and then loop through the returned file pointer.
Here is a simple example for the command ls -l
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *process;
char buff[1024];
process = popen("ls -l", "r");
if (process != NULL) {
while (!feof(process)) {
fgets(buff, sizeof(buff), process);
printf("%s", buff);
}
pclose(process);
}
return 0;
}
The long approach - which gives you complete control of stdin, stdout, and stderr of the child process, at the cost of fairly significant complexity - involves using fork and execve directly.
Before forking, set up your endpoints for communication - pipe works well, or socketpair. I'll assume you've invoked something like below:
int childStdin[2], childStdout[2], childStderr[2];
pipe(childStdin);
pipe(childStdout);
pipe(childStderr);
After fork, in child process before execve:
dup2(childStdin[0], 0); // childStdin read end to fd 0 (stdin)
dup2(childStdout[1], 1); // childStdout write end to fd 1 (stdout)
dup2(childStderr[1], 2); // childStderr write end to fd 2 (stderr)
.. then close all of childStdin, childStdout, and childStderr.
After fork, in parent process:
close(childStdin[0]); // parent cannot read from stdin
close(childStdout[1]); // parent cannot write to stdout/stderr
close(childStderr[1]);
Now, your parent process has complete control of the std i/o of the child process - and must safely multiplex childStdin[1], childStdout[0], and childStderr[0], while also monitoring for SIGCLD and eventually using a wait-series call to check the process termination code. pselect is particularly good for dealing with SIGCLD while dealing with std i/o asynchronously. See also select or poll of course.
If you want to merge the child's stdout and stderr, just dup2(childStdout[1], 2) and get rid of childStderr entirely.
The man pages should fill in the blanks from here. So that's the hard way, should you need it.
What I want to do is open an .exe from another .exe. I really don't know how to do this, so I searched the internet. I tried some suggested methods from the internet, but it didn't work.
Here's my code:
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
system ("OpenFile.exe");
system ("pause");
return 0;
}
When I run it in DEV C++, it compiles, but I get a error. Can someone please help me?
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. If that doesn't scare you silly, check your pulse.
Anti virus programs hate it, your program could get flagged as a virus.
You should use CreateProcess().
You can use Createprocess() to just start up an .exe and creating a new process for it.
The application will run independent from the calling application.
Here's an example I used in one of my projects:
#include <windows.h>
VOID startup(LPCTSTR lpApplicationName)
{
// additional information
STARTUPINFO 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
CreateProcess( lpApplicationName, // the path
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 (removed extra parentheses)
);
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
EDIT: The error you are getting is because you need to specify the path of the .exe file not just the name. Openfile.exe probably doesn't exist.
I've had great success with this:
#include <iostream>
#include <windows.h>
int main() {
ShellExecute(NULL, "open", "path\\to\\file.exe", NULL, NULL, SW_SHOWDEFAULT);
}
If you're interested, the full documentation is here:
http://msdn.microsoft.com/en-us/library/bb762153(VS.85).aspx.
Try this:
#include <windows.h>
int main ()
{
system ("start notepad.exe") // As an example. Change [notepad] to any executable file //
return 0 ;
}
You are getting this error because you are not giving full path. (C:\Users...\file.exe)
If you want to remove this error then either give full path or copy that application (you want to open) to the folder where your project(.exe) is present/saved.
#include <windows.h>
using namespace std;
int main()
{
system ("start C:\\Users\\Folder\\chrome.exe https://www.stackoverflow.com"); //for opening stackoverflow through google chrome , if chorme.exe is in that folder..
return 0;
}
When executable path has whitespace in system, call
#include<iostream>
using namespace std;
int main()
{
system("explorer C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe ");
system("pause");
return 0;
}
Provide the full path of the file openfile.exe
and remember not to put forward slash / in the path such as
c:/users/username/etc....
instead of that use
c:\\Users\\username\etc
(for windows)
May be this will help you.
I know this is a bit late but this is to help all the new the c++ devs.
Basically I found that if you set the file path to the location then call the program you can bypass the error.
cout << "Opening Firefox";
system("cd C:\\Program Files\\Mozilla Firefox");
Sleep(1000);
system("start firefox.exe -P");
As you can see I set the file path to the location of Firefox then launch it. In my case I'm launching the Profile manager of Firefox, if you want to launch just Firefox remove the -P. I also put in a Sleep() to give my computer time to switch file paths. if you want to go back to the default file path use, system(cd C:\\Windows\\System32);. I made this by replicating commands in the command line for windows, though you would use Linux specific commands + file paths if that is what you are using.
I developing on the Linux platform.
I want to create a new proccess in my library without replacing the current executing image.
Because I am developing a library, I don't have a main function.
And I want to continue the new process after the invoker application closes (Just like CreateProcess Windows API).
Is it possible in Linux or not?
something like this function:
void Linux_CreateProcess(const char* app_name)
{
// Executing app_name.
// ???????? what is the code ??????
// app_name is running and never close if current application close.
return;
}
Note:
system() blocks the current process, it is not good. I want to continue the current process.
exec() family replace the current executing image, it is not good.
popen() closes the new process if the current process closed.
The fork/exec combination was already mentioned, but there is also the posix_spawn family of functions that can be used as a replacement for fork + exec and is a more direct equivalent to CreateProcess. Here is an example for both possibilities:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <spawn.h>
#include <sys/wait.h>
extern char **environ;
void test_fork_exec(void);
void test_posix_spawn(void);
int main(void) {
test_fork_exec();
test_posix_spawn();
return EXIT_SUCCESS;
}
void test_fork_exec(void) {
pid_t pid;
int status;
puts("Testing fork/exec");
fflush(NULL);
pid = fork();
switch (pid) {
case -1:
perror("fork");
break;
case 0:
execl("/bin/ls", "ls", (char *) 0);
perror("exec");
break;
default:
printf("Child id: %i\n", pid);
fflush(NULL);
if (waitpid(pid, &status, 0) != -1) {
printf("Child exited with status %i\n", status);
} else {
perror("waitpid");
}
break;
}
}
void test_posix_spawn(void) {
pid_t pid;
char *argv[] = {"ls", (char *) 0};
int status;
puts("Testing posix_spawn");
fflush(NULL);
status = posix_spawn(&pid, "/bin/ls", NULL, NULL, argv, environ);
if (status == 0) {
printf("Child id: %i\n", pid);
fflush(NULL);
if (waitpid(pid, &status, 0) != -1) {
printf("Child exited with status %i\n", status);
} else {
perror("waitpid");
}
} else {
printf("posix_spawn: %s\n", strerror(status));
}
}
posix_spawn is probably the preferred solution these days.
Before that fork() and then execXX() was the way to do this (where execXX is one of the exec family of functions, including execl, execlp, execle, execv, execvp, and execvpe). In the GNU C library currently, at least for Linux, posix_spawn is implemented via fork/exec anyway; Linux doesn't have a posix_spawn system call.
You would use fork() (or vfork()) to launch a separate process, which will be a clone of the parent. In both the child and parent process, execution continues, but fork returns a different value in either case allowing you to differentiate. You can then use one of the execXX() functions from within the child process.
Note, however, this problem - text borrowed from one of my blog posts (http://davmac.wordpress.com/2008/11/25/forkexec-is-forked-up/):
There doesn’t seem to be any simple standards-conformant way (or even a generally portable way) to execute another process in parallel and be certain that the exec() call was successful. The problem is, once you’ve fork()d and then successfully exec()d you can’t communicate with the parent process to inform that the exec() was successful. If the exec() fails then you can communicate with the parent (via a signal for instance) but you can’t inform of success – the only way the parent can be sure of exec() success is to wait() for the child process to finish (and check that there is no failure indication) and that of course is not a parallel execution.
i.e. if execXX() succeeds, you no longer have control so can't signal success to the original (parent) process.
A potential solution to this problem, in case it is an issue in your case:
[...] use pipe() to create a pipe, set the output end to be close-on-exec, then fork() (or vfork()), exec(), and write something (perhaps errno) to the pipe if the exec() fails (before calling _exit()). The parent process can read from the pipe and will get an immediate end-of-input if the exec() succeeds, or some data if the exec() failed.
(Note that this solution through is prone to causing priority inversion if the child process runs at a lower priority than the parent, and the parent waits for output from it).
There is also posix_spawn as mentioned above and in other answers, but it doesn't resolve the issue of detecting failure to execute the child executable, since it is often implemented in terms of fork/exec anyway and can return success before the exec() stage fails.
You wrote:
I want to create a new proccess in my library without replacing the current executing image.
system() blocks the current process, it is not good. I want to continue current process.
Just add an ampersand after the command call.
Example: system("/bin/my_prog_name &");
Your process will not be blocked!
The classic way to do this is to use fork() to create a child process, and then use one of the exec() functions to replace the executing image of the child, leaving the parent untouched. Both process will then run in parallel.
I think posix_spawn does what you want. Internally it might do fork/exec, but maybe it also does some funky useful stuff.
You should be using fork() and then execvp().
fork() function creates a new child process. In the parent process you receive the process ID of the child process. In Child process the process ID returned is 0, which tells us that the process is a child process.
execvp() replaces the calling process image with a new process image. This has the effect of running a new program with the process ID of the calling process. Note that a new process is not started; the new process image simply overlays the original process image. The execvp function is most commonly used to overlay a process image that has been created by a call to the fork function.
Yes, fork() and exec..() is the correct solution. Look at this code if it can help you :
switch( fork() )
{
case -1 : // Error
// Handle the error
break;
case 0 :
// Call one of the exec -- personally I prefer execlp
execlp("path/to/binary","binary name", arg1, arg2, .., NULL);
exit(42); // May never be returned
break;
default :
// Do what you want
break;
}
I think fork is what you are looking for.
I am using CreateProcess() to run an external console application in Windows from my GUI application. I would like to somehow gather the output to know whether there were errors. Now I know I have to do something with hStdOutput, but I fail to understand what. I am new to c++ and an inexperienced programmer and I actually don't know what to do with a handle or how to light a pipe.
How do I get the output to some kind of variable (or file)?
This is what I have a the moment:
void email::run(string path,string cmd){
WCHAR * ppath=new(nothrow) WCHAR[path.length()*2];
memset(ppath,' ',path.length()*2);
WCHAR * pcmd= new(nothrow) WCHAR[cmd.length()*2];
memset(pcmd,' ',cmd.length()*2);
string tempstr;
ToWCHAR(path,ppath); //creates WCHAR from my std::string
ToWCHAR(cmd,pcmd);
STARTUPINFO info={sizeof(info)};
info.dwFlags = STARTF_USESHOWWINDOW; //hide process
PROCESS_INFORMATION processInfo;
if (CreateProcess(ppath,pcmd, NULL, NULL, FALSE, 0, NULL, NULL, &info, &processInfo))
{
::WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
delete[](ppath);
delete[](pcmd);
}
This code probably makes any decent programmer scream, but (I shouldn't even say it:) It works ;-)
The Question: How do I use hStdOutput to read the output to a file (for instance)?
Microsoft has an example in its knowledge base that demonstrates how to capture the output of a child console process. The basic principle is that the parent process creates pipes (one per standard handle to redirect) and passes the handles to CreateProcess.
The child process does not need to be modified for this to work, which is important if you do not have control over the child's source.
More information: How to spawn console processes with redirected standard handles
I have a process that interfaces with a library that launches another process. Occasionally this process gets stuck and my program blocks in a call to the library. I would like to detect when this has happened (which I am doing currently), and send a kill signal to all these hung processes that are a child of me.
I know the commands to kill the processes, but I am having trouble getting the pids of my children. Does anyone know of a way to do this?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fp = popen("ps -C *YOUR PROGRAM NAME HERE* --format '%P %p'" , "r");
if (fp == NULL)
{
printf("ERROR!\n");
}
char parentID[256];
char processID[256];
while (fscanf(fp, "%s %s", parentID, processID) != EOF)
{
printf("PID: %s Parent: %s\n", processID, parentID);
// Check the parentID to see if it that of your process
}
pclose(fp);
return 1;
}
This question is very similar to one asked the other day. I would suggest taking a look here to see if the answers are satisfactory in your case. Basically you will probably have to read through /proc.
I don't think "ps" is the answer. You could iterate the process list yourself to look for your own process's children, but it's a much better idea to modify the library so it provides the PIDs when you launch them.
This library must be pretty lame. What kind of deal do you have with its vendor? Can you not get on to their support to fix it?