![]() |
|
#1
|
||||
|
||||
[TUTORIAL] Calling an external program in C (Linux)Executing programs with C(Linux) Introduction I have seen several posts recently that want to call a program from another program. This seems like a fairly simple task because it can be done in a shell script or a batch program with a single line. That is the reason why the most simple solution is to call a system command with the system call, like CPP / C++ / C Code:
While this works, you loose all control of your program until this process finishes. Beyond that what if you want a more interactive approach where the calling process could send information to the called process? The standard posix C library provides several functions for calling and controlling processes. These commands are: fork(), execl(), pipe() and dup2(). Why is this so complex? When I first looked into this, I always wondered why the "simple" task of calling a program from a C program was so convoluted. The simple answer is portability. When a program is called, it is up to the Operating System to set up the memory space, program space and effectively spawn the new process. So for portability reasons there can't be a standard C call that will simply "start" a new program because C doesn't know anything about your operating system. The code that I have included below should compile and run on any Posix standard C compiler under any operating system. C function: fork() The fork command is very simple. It "forks" a unique process that is absolutely identical to the current process at the time of forking. This is the cheap and easy way to set up a process with everything in order. But why would you want to have two identical processes? First the processes are only identical at the instant that they are split. From there execution can follow seperate paths. The fork function will return the pid number to the parent process and return a 0 to to the child process upon success. Therefore by simply testing the return value of the fork call, execution can follow different paths. Here is a quick sample of fork: CPP / C++ / C Code:
Second, by using the exec family of functions, it is possible to replace an entire process with a brand new process. C function: execl() From the man page for execl: Quote:
CPP / C++ / C Code:
Several things of note. The first two parameters are the name of the process to execute. The last parameter to the function must be NULL, even if there are no arguments to be passed to the child. C function: pipe() Using the pipe function, we can easily set up a conduit of communication between the parent and child process. Basically a pipe has two ends. Input goes in one end and output comes out of the other. It only works in one direction. You can not read out of the write end and vice-a-versa. In order to use the pipe command, you must pass a 2-element integer array that will hold the file descriptors for the input side and the output side. CPP / C++ / C Code:
In the above example, commpipe[0] is the input side of the pipe and commpipe[1] is the output side of the pipe. Data can be put in and taken out of the pipe by using the read & write commands respectively with the proper file descriptors. This is a big advantage when coupled with the use of a fork. A pipe is an internal element that can only be known to the calling process. If I create a pipe prior to forking, this pipe will exist across both the parent and the child process, since the fork command duplicates everything about the calling process. C function: dup2() While using the read/write commands on a pipe is a sufficient way to accomplish Interprocess Communication, it is necessary for the child to be written specifically for this case. What if we want to call a child that has not been written for this type of communication? This is where dup comes in. By using dup, the stdin and stdout streams can be replaced with a different file descriptor. When we created our pipe, we were given back two file descriptors. Now we can assign these to the stdin/stdout. The file descriptors for stdin, stdout and stderr and 0,1 and 2 respectively. So to replace the stdin with the "in" side of the pipe is done by calling dup2 as such: CPP / C++ / C Code:
Miscellaneous A child process needs to be able to return a value upon exit to someone. It is important that the parent knows to look for this value. The command wait is used for this purpose. The return status is passed as a pointer to an integer in the argument list. By defaulf, stdout is a line buffered process. Therefore, the buffer is not written until a new-line is encountered. While this is not apparent in a typical process, it is very apparent when using a pipe line for stdout. There are two ways to handle this problem. The first is to flush the stdout buffer whenever something is printed with it. The second way (and better way - from what I understand) is to change the stdout to be unbuffered. This can be accomplished with a call to setvbuf. CPP / C++ / C Code:
The two important arguments are stdout (the stream that we want to change the buffer on) and _IONBF (indicating not to use a buffer). The other two are used to assign a new buffer and size, neither of which we need because we are using non-buffered output. Lastly, there is a couple of calls to close. It is always a good idea to "close" the unused sides of the pipe. That way there is no chance of accidently reading from the write side, etc. Example Okay, that is about it. How about a quick and dirty example? In this example, the parent process will call the child process. Notice that flow control stays with the parent. Although easy to compile, here is the commands I used to compile these functions: Code:
parent.c CPP / C++ / C Code:
child.c CPP / C++ / C Code:
Conclusion That is about it. This is a fun little exercise and can be very useful. I investigated this in order to call and control a process for which I don't have the source code. This is fairly *nix code. I have not investigated the windows side of doing this beyond knowing that dev-cpp has all of these commands, except fork (d'oh!). If any one can give a windows way of doing this, I am sure it would be of interest. __________________
The best damn Sports Blog period. |
||||
|
#2
|
|||
|
|||
|
in windows, you can do this with the notoriously complicated Windows API. I am mostly learning this off MSDN as I go along, so bear with me.
first of all, you must include the windows.h header. there is one function, CreateProcess(), that runs an external program. However, like many functions in the Windows API, it requires an insane list of structures and other parameters. we will later use some of these for pipes and stuff. (I say "and stuff" because there is no one analog to the Linux "pipe" in Windows, or I don't know about it). CPP / C++ / C Code:
so, a bit more complicated than fork(), execl(), and dup2(), but it works. for more information, here are the MSDN pages on: CreateProcess SOON, I will find out how to do pipes, and edit this post. when I do that, I'll add a reply onto the end saying I've updated this. someone feel free to correct me with a shorter and more intuitive version of this extremely unfriendly-looking and complicated code. (please!) |
|
#3
|
||||
|
||||
|
Hello,
There is a more intuitive way, but it's not shorther. Rather, it contains extensive error-handling and command processing; such as the exe path, etc... An example code can be found here: C++ CreateProcess Example Or, a slight shorter version of your current code: CPP / C++ / C Code:
- Stack Overflow __________________
Following the rules will ensure you get a prompt answer to your question. If posting code, please include BB [C] / [C++] tags. Your question may have been asked before, try the search facility. |
|
#4
|
|||
|
|||
|
all right. I'm going to have to refer you to the MSDN sample code for "Creating Child Processes with Redirected Input and Output."
Here The idea seems to be to create two pipes: One that the parent writes to and the child reads from (stdin/cin), and one that the child writes to (stdout/cout) and parent reads from. The parent process creates the pipes and therefore has the handles. It specifies that those handles should be inheritable, so that the child process can use them. But it also has to duplicate its own stdin/out/err handles so that the child doesn't inherit those. MSDN also gives some Windows API stuff for the child process, but from what I understand the child could just be a regular console C or C++ program that uses stdin/stdout or cin/cout, respectively. Also their child program is a bad idea because it goes into an infinite loop, and uses an uninitialized variable (chBuf). |
|
#5
|
|||
|
|||
|
Well, here's a sort of external command prompt launcher that utilizes pipes. Sort of like a shell. I'm sure it could be more efficient in many ways, but it's a start.
CPP / C++ / C Code:
|
Recent GIDBlog
Non-US citizens serving in the military by crystalattice
| Thread Tools | Search this Thread |
| Rate This Thread | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Mozilla Thunderbird | dsmith | Computer Software Forum - Linux | 9 | 01-Mar-2005 11:56 |
| Need help with a C program (Long) | McFury | C Programming Language | 3 | 29-Apr-2004 20:06 |
| Re: Piping and Redirection | WaltP | C Programming Language | 1 | 11-Apr-2004 08:01 |
| Linux Kernel Upgrade Mini Howto | dsmith | Computer Software Forum - Linux | 3 | 05-Apr-2004 22:10 |
| Call a C program through Linux shell script | nuwandee | C Programming Language | 3 | 29-Mar-2004 21:54 |
Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The