Channels ▼
RSS

C/C++

Using Named Pipes to Connect a GUI to a Console App in Windows


The UI Thread

The UI thread, the main thread of the GUI Application, handles user input and renders UI elements. It starts the Worker thread when the user clicks the Start button, and updates the progress bar when it gets a WM_USER_PROGRESS_MSG_RECEIVED message.

The Worker Thread

The Worker thread launches the Code Analyzer process and passes it a command-line string containing the input directory, Progress Message pipe name, and other parameters. The Worker thread is the pipe server for the Progress Message named pipe. It creates a synchronous named pipe by calling the CreateNamedPipe API and specifying PIPE_WAIT mode. It establishes itself as the pipe server by calling ConnectNamedPipe, which blocks until a client connects to the pipe; the Code Analyzer is waiting to connect as explained below.

The Worker thread then performs these steps repeatedly:

  • Call ReadFile on the pipe; this blocks until a message arrives or the client disconnects.
  • Deserialize the progress message. Serialization is explained below.
  • Send the deserialized progress data to the GUI Application's main window using the SendMessage Windows API and a custom Windows message. SendMessage blocks until the UI thread has processed the message, so passing a pointer to the progress data is thread-safe. Alternatively, the Worker thread could notify the UI by calling PostMessage, passing data in a heap-allocated buffer for thread safety.

This loop exits when the client disconnects from the pipe. The Worker thread then waits for the Code Analyzer process to exit by calling the WaitForSingleObject API. The Worker thread gets the Code Analyzer's exit code, notifies the UI thread via a custom Windows message, and exits.

The Code Analyzer Thread

The Code Analyzer thread is the main thread of the Code Analyzer program. It gets the name of the progress message pipe via a CreateProcess parameter, and connects as a client by calling the Connect() method of the NamedPipeClientStream .NET class. It analyzes files one by one, periodically writing a progress message to the named pipe. When it finishes, it closes its connection to the named pipe, sets a success or failure exit code, and exits.

One problem I grappled with was how to connect the client and server to the pipe, since both API functions block and must be done in a certain order. Before a client can connect, a pipe server must make the pipe available by calling ConnectNamedPipe. How could I get the Code Analyzer to connect as the client after the GUI Application calls ConnectNamedPipe given that the latter blocks until a client connects? My solution to this Catch 22 was to use an overloaded Connect method of the .NET NamedPipeClientStream class that takes a parameter for "the number of milliseconds to wait for the [pipe] server to respond." When the Code Analyzer calls this Connect method, it waits for a few seconds if necessary for the GUI Application to make the pipe available.

The GUI Application creates the pipe by calling CreateNamedPipe and indicates with the PIPE_TYPE_MESSAGE and PIPE_READMODE_MESSAGE flags that data will be in message form. Each progress message has several elements, such as percent complete, elapsed time, subdirectory path, etc., and must be serialized in a way that can be deserialized later. The Code Analyzer serializes each element as a string using .NET PipeStream and StreamWriter objects. The GUI Application calls ReadFile to read the pipe's contents into a buffer and parses the buffer to deserialize each progress message element. The Code Analyzer writes only one progress message at a time; it waits for the pipe to drain before writing the next progress message, but rarely waits because UI updates are quicker than code analysis.

Using an Asynchronous Named Pipe for Stop Notification

A user can click the GUI Application's Stop button at any time (that is, asynchronously). I used an asynchronous named pipe to send the stop request to the Code Analyzer as shown in Figure 3. A second thread in the Code Analyzer called the Stop Request Handler monitors the pipe for a "STOP" message.

Figure 3: Sequence diagram of processes and thread interactions when user clicks Stop button.

The UI Thread

The UI thread creates the Stop Message Named Pipe by calling CreateNamedPipe, specifying FILE_FLAG_OVERLAPPED to make it asynchronous. The UI thread establishes itself as the pipe server by calling ConnectNamedPipe, which is non-blocking for asynchronous pipes, then starts the Worker thread. If the user clicks the Stop button, the UI thread notifies the Code Analyzer by writing "STOP" to the Stop Message Named Pipe.

The Worker Thread

The Worker Thread functions as described in the previous section.

The Stop Request Handler Thread

Writing code that reads from an asynchronous named pipe may sound daunting, but .NET makes it easy. The Code Analyzer creates a NamedPipeClientStream for the Stop Message Named Pipe and begins an asynchronous read operation by calling its BeginRead method. If data arrives on the pipe, .NET reads it to a buffer and calls ListenForStopMsgCallback on the Stop Request Handler Thread. If the message is the string "STOP," ListenForStopMsgCallback sets the StopRequested flag to true, notifying the Code Analyzer to stop.

The Code Analyzer Thread

The Code Analyzer should stop processing files if "STOP" arrives on the Stop Message Named Pipe. The Code Analyzer thread periodically checks the StopRequested flag and, if true, stops analyzing files and terminates with a suitable exit code.

Conclusion

This article shows how a Windows application can communicate with a .NET console application using named pipes. The devil is in the details, especially when writing software. Code is provided, along with notes, demonstrating the techniques discussed in this article. Writing this code was a fun challenge, particularly the multi-threaded pipe access, and I found that .NET made it easier to work with named pipes. I hope you find this article helpful if you're considering using named pipes in your applications.

Acknowledgments

I wish to thank Bob Zeidman for his support and inspiration for this article. Thanks also to Bob and my colleagues Nik Baer, Larry Melling, and Michael Everest for their technical and editorial reviews and suggestions.

References

Chappell, D. (2010, March). Introducing Windows Communication Foundation in .NET Framework 4. Retrieved May 11, 2011, from MSDN.

Fisher, S. (1988, October 17). IBM's OS/2 Named-Pipe Support Quells LAN Incompatibility Fears. InfoWorld , 10 (42), pp. 1, 8.

Lewandowski, S. M. (1997). Interprocess Communication in UNIX and Windows NT. Brown University, Computer Science. Department of Computer Science, Brown Univerity.

Microsoft. (2010, 9 7). Dynamic Data Exchange (DDE). Retrieved 4 19, 2911, from MSDN.

Microsoft. (2011, 2 24). File Mapping. Retrieved 4 19, 2011, from MSDN. Microsoft. (2011, 1 27). Mailslots. Retrieved 4 19, 2011, from MSDN.

Microsoft. (2011, 1 27). Pipes. Retrieved 4 20, 2011, from MSDN.

Microsoft. (2011, 4 5). Windows Sockets 2. Retrieved 4 19, 2011, from MSDN.

Microsoft. (2005, 7 19). Windows Version History. Retrieved 4 20, 2011, from Microsoft Support.

Ritchie, D. M. (1980). The Evolution of the Unix Time-sharing System. In J. M. Tobias (Ed.), Language Design and Programming Methodology 1979, Proceedings of a Symposium held in Sydney, Australia; Published in Lecture Notes in Computer Science. 79, pp. 25-36. Springer-Verlag.

Ritchie, D. (1977). The Unix Time Sharing System – A Retrospective. Retrieved 5 11, 2011, from cm.bell-labs.com.


Jim Zamiska is a software engineer and project manager with a background in Microsoft technologies.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video