Launching a sub process under Unix, Windows and wxWidgets Atom Feed 1

A quick overview of the necessary code for spawning a sub-process under Windows, Linux (POSIX API) and wxWidgets.

1   Motivation

It is pretty obvious that without the ability to launch a sub-process today's operating system would be pretty boring. After all your shell, whether explorer.exe, bash or (if you are hardcore) csh, itself is a program that allows you to launch other programs like text editors and web browsers. But you knew that. So why would you want to launch any programs from your application?

The main reason you might want launch a sub-process from your program is so that you can take advantage of 3rd party code without building against complex libraries. Infact if such libraries are unavailable for your environment or come under a restrictive license your only choice would be to use a sub-processes.

For example the Tesseract OCR engine is a powerful Optical Character Recognition system that can extract the text content of TIFF images. The engine is just that, an engine, it has no user interface and is designed to be called and fed data from another program. If you were building an image scanning application you could easily add OCR capabilities to it by launching tesseract in a sub-process. Even better, you can allow users and 3rd party developers to add more OCR engines by making the process launch code configurable.

Another example is the typical Integrated Development Environment (IDE), like Eclipse or MS Visual Studio, which uses a sub-processes to compile program source code or perform analysis of source files.

Yet another example, and a shameless plug no doubt, is something like fe3d [1]. A visualization application, fe3d initiates a network scan using the nmap program and then reads and processes the resulting output file in order to display 1980s looking 3D information.

2   Launching a Process

The difference between the POSIX and the Windows way of launching a process perfectly illustrates the difference between the philosophies of the two APIs. The POSIX API follows (or maybe leads) the UNIX philosophy of having many small pieces working together to create more complex systems. On the other hand the Windows API provides API functions that perform every conceivable tasks. It would be somewhat foolish to argue which way is better as the designers of both APIs probably had very good reasons for their design choices.

It must be said here that my preferred method of process launching (and other GUI programming) is by using wxWidgets, simply because it is object oriented and cross platform.

2.1   The POSIX way

The POSIX standard provides two function calls that work together to allow for the launching of a sub-process: fork and exec [2].

The fork call creates an exact duplicate [3] of the current process at the location of the call. The new process, the child, continues on the same execution path as the original process, the parent. The value returned by fork is the process id for the child, in the parent, or 0 in the child. This allows each processes to determine if it is the child or the parent so that they can continue on different execution paths.

The exec call replaces the current process image with that of another process.

Putting it together we have something like this

# 's
 1switch (pid = fork())
2 {
3 case -1: // ERROR!
4 printf("Error with code %i" % errno);
5 break;
6 case 0: // Child
7 status = execv(m_Config->getNmapPath().c_str(), args);
8 break;
9 default: // Parent
10 wait(0); // Wait for all sub-processes to finish
11 // Process the data
12 break;
13 }

Of course you don't have to, and probably should not, "sit there and wait" for the child process to terminate since that would freeze the user interface and might result in the user kill -9'ing your program and sending you hate mail.

See Launching a sub process using the POSIX API for a self contained example

2.2   The Windows way

In order to launch a process under windows one must simply supply the necessary arguments to the Windows CreateProcess function.

The CreateProcess function takes ten arguments (most of them can be NULL) and requires two structures in order to operate correctly: PROCESS_INFORMATION and STARTUPINFO.

# 's
 1// Initialize StartupInfo structure
2STARTUPINFO StartupInfo;
3memset(&StartupInfo, 0, sizeof(StartupInfo));
4StartupInfo.cb = sizeof(StartupInfo);
5
6// This will contain the information about the newly created process
7PROCESS_INFORMATION ProcessInformation;
8
9BOOL results = CreateProcess(0,
10 procName, // Process and arguments
11 0, // Process Attributes
12 0, // Thread Attributes
13 FALSE, // Inherit Handles
14 0, // CreationFlags,
15 0, // Environment
16 0, // Current Directory
17 &StartupInfo, // StartupInfo
18 &ProcessInformation // Process Information
19 );
20// Cleanup
21CloseHandle(ProcessInformation.hProcess);
22CloseHandle(ProcessInformation.hThread);

Warning

Make sure you close the Process and thread handles, using CloseHandle, when you are done or you'll anger the Windows gods.

If you have never programmed with the Windows API you may think that the CreateProcess function is something of an overkill, taking way too many arguments and requiring too much setup code. Yes, for very simple applications, it is a bit annoying to have to write pages of initialization code for massive structures, however if you had to modify the execution environment or security attributes you would end up writing a similar amount of code in POSIX.

See Launching a sub-process under Windows for a self contained example

2.3   The wxWidgets way

Simply put, wxWidgets is a cross platform [mostly GUI] toolkit that wraps the underlying operating system features inside C/C++ Macro's [4], allowing you to achieve native look and feel but with cross platform code. The framework also provides a set of APIs for manipulating files, processes, and other operating system primitives.

wxWidgets is my preferred GUI toolkit, even for writing purely Windows based applications, because it is object oriented, cross platform, and lightweight [5] and I advise you to take the time to learn and use it for your own GUI needs.

In order to launch a sub process with wxWidgets, you must first create a wxProcess object, providing information about the target process, then call wxExecute function to spawn the process.

# 's
 1// Create the process string
2wxString launchCommand = _("foo -arg1 -arg2 -argN");
3wxEvtHandler *eventHandler = NULL;
4
5proc = new wxProcess(eventHandler);
6proc->Redirect();
7wxInputStream* stdErr = proc->GetErrorStream();
8wxInputStream* stdOut = proc->GetInputStream();
9
10if(::wxExecute(launchCommand, wxEXEC_ASYNC, proc) != 0){
11 cerr<<"Process launch error"<<endl;
12}

If you provide a window (or another event handler) to the wxProcess constructor a wxEVT_END_PROCESS event will be sent to it when the sub-process terminates.

3   Notes

[1]The topic of this quick tutorial is one of the motivating factors behind Siafoo articles. Years ago while working on fe3d, I was trying to figure out how to launch a process in a cross platform way. Once I had figured it out, I decided to write a quick blog entry about it but since blogs are not very structured, and information can quickly become aged, I tried to figure out a better way... years later Siafoo was born.
[2]exec is actually a family of calls.
[3]The child and the parent processes are not exactly the same, see the man page for fork for more information.
[4]This explanation does not really do wxWidgets justice...
[5]Don't roll your eyes. Unlike other toolkits (like Qt to a certain extent), wxWidgets uses a lot of macros and other tricks in order to use native APIs and widgets.