Introduction

One of the questions that often comes up on the forum is the question about "How do I run another program?" This is often supplemented by a line like "I read about processes but they seem too complex". Well, sorry, you don't have a choice. You need to launch a process. This essay discusses several of the issues of process management. This is written primarily for C++/MFC programmers. This discussion supplements the discussion in our book, Win32 Programming, but you can use the information here without needing the book.

Creating a Process

There are many answers to this, depending on what you need to accomplish. The old-fashioned C functions spawn and system still work. However, these are considered somewhat obsolete. They don't give you the control you need to receive a notification that the process completed, because you can't get the process handle.

The underlying Win32 API call to spawn a process is ::CreateProcess. This also gives you the ability to specify, for a windowing application, where on the screen the window will appear. However, ::CreateProcess is the lowest-level interface to process spawning. Microsoft recommends you use ShellExecute, which is still not good enough; while it provides the high-level interface for the best integration into the Windows environment (for example, you can give it a URL and it will launch Internet Explorer automatically if it is not running, or send the request directly to a running instance) it still doesn't provide what you need to receive a notification.

To determine if a process has stopped, you will need a process handle. This is the token Win32 uses to represent a process to an application. You can get the process handle by using either ::CreateProcess or ::ShellExecuteEx. For the best integration into Windows, Microsoft suggests (urges, demands) that you use ::ShellExecute.

Here are two examples of how to get the process handle and store it in a variable hProcess: In both cases, the functions are called with the name of the program to launch and a pointer to any arguments for its command line. If there are no arguments, the argument pointer can be NULL. The functions return a HANDLE to the process that was created, or NULL if they failed to create a process. If they return NULL, the caller can call ::GetLastError() to determine what went wrong. Note that these are "bare bones" launchers; if you want fancy control of position, startup state, console state, initial view, etc. you can work theme-and-variations on these schemes. If you want to launch a console-mode program and feed information to stdin or receive data from stdout, you will have to use ::CreateProcess, but that's the subject of another essay.

The nature of Windows is that a launched process takes on a life of its own. If you have a Unix background, there is nothing like the "process groups" of Unix. Once a process is launched, it has a life of its own. You have explicit control of it if you retain the process handle (and the window handle, if you get that), but if your process dies, any processes you started keep right on running. The aliveness or deadness of your process has no effect on them, unless of course they were waiting for your process to do something for them (like supply stdin text). In this case, they won't die, but they will block waiting for the desired event. So if you want to terminate a process, you have to provide a way of accomplishing this.

Killing a Process

You might think that the way to terminate a process is to call the obvious API call, ::TerminateProcess. Wrong. Bad Move.

When you call ::TerminateProcess, the process stops. No matter what it is doing, it dies. Instantly. If it has a semaphore locked, or a mutex, or is in the middle of kernel code, or doing something else important, too bad. Boom! No more process. Imagine lots of Hollywood special effects with massive fireballs. Not a nice way to die.

A process should always have a "clean" way to be shut down. If you have hold of the handle of a process that has a window, you can send it a WM_CLOSE message via PostMessage to that window. If it is a console app, you should provide a way for it to shut down, such as detecting EOF on stdin, or receiving a particular text string. But don't use ::TerminateProcess unless you are willing to live with potentially serious consequences.

When Did It Stop?

Often you will want to launch a process, often a console application, and let it run until it completes. When it completes, you can then deal with its results. For example, I have a case where I spawn (of all things) a 16-bit compiler (it is written in assembly code, and no, I had nothing to do with it; I just had to use it in a client app). I spawn it with a commandline

compilername inputfile, listingfile, outputfile

and I have to wait for it to complete before I can let the user examine the listing file or download the output file.

This is any easy one, because the compiler works with very tiny programs, and runs in under 5 seconds. So for this application, I just wait for it to complete.

However, not all programs have this property. In this case, you want to get an asynchronous notification of the completion. I do this by what appears to be a complex method, but in fact is very simple: I spawn a thread that blocks on the process handle. When the process completes, the thread resumes execution, posts a message to my main GUI window, and terminates.

I'm reproducing the code for the WaitInfo class here because it is so small. This is also part of a demo project you can download from this site. The link is at the top of the article.

The way this is used is that after you have created your process, you call the requestNotification method to request a notification. You pass in the handle of the process and the window which is to receive the notification. When the process terminates, a notification message is sent to the specified window. You must have a WaitInfo object that is created before the requestNotification is called and remains valid until the notification message is received; this means that it cannot be a variable on the stack. In the example code I provide, I put it in the class header of the window class that launches the program.

In the header file for my class, I add the following:

WaitInfo requestor;
afx_msg LRESULT OnCompletion(WPARAM, LPARAM)

In the MESSAGE_MAP of the window, you need to add a line for the handler. Because this uses a qualified name, the ClassWizard is emotionally unprepared to deal with it, so you have to place it as shown, after the //}}AFX_MSG_MAP line.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

This error message was designed by Microsoft to be deliberately confusing and misleading. The correct error message is "Unable to find DLL named <name here>", which is what it used to say. If you are building it from the source, though, it should work.

Hi,
I intend to launch some windows application ( media player).The application Window should be able to be positioned any where in the screen ,to hide or unhide at will. How can it be acheived?
Thanx.
kkismu@gmail.com

Having the parent thread wait for itself to end would be pretty silly. I think you have misread the code.

To wait, and I mean really wait, for a child thread to stop, you do WaitForMultipleObjects with an array of handles to the child threads, but this only works if you have <=64 threads (a limitation in WaitForMultipleObjects).

But doing a real wait for the child threads is usually a bad idea, so what I do is have the threads provide an asynchronous notification that they have completed. When I get as many notifications as I have threads that started, I know all the threads have finished. You can do this by having each thread PostMessage to the main GUI thread a notification that it has finished.

Thanks. Caused by the fact that I edit my Web site on a different machine that I do development (only one of my machines is allowed to have Internet access, because only one of my machines is heavily secured against various attacks, and I had a bit-drop in switching between the two while writing the article).

I would like to see some sample code that deals with gettting the process handle for a process by its name. I tried toolshelp CreateToolhelp32Snapshot API however it apeears it only works for windows 2000.

We know, when a child process is created in the parent process, the
child process can be killed with the TerminateProcess(hHandleProcess, 1),
But if others child processes are created by the child process, how can I
kill them all.
For Example (from Tornado IDE):
When we use GNU tools to compile and link the source files, we usually
use the make.exe to interpret the makefile document, so the make.exe can
be a child process of a application(may be an IDE). But we know make.exe
will create may sub-processes(gcc.exe, ld.exe, make.exe, ect.), so how can
I kill the child process(make.exe) and all it's sub-processes in the application(IDE).
I hope your help!!