The topic of Mailslots has been on my list of things to write about for a long time. Mailslots have been around since Windows NT 3.1 and Windows 95, but many developers Ive asked arent familiar with them. Mailsots might sound like something to do with POP3, but they have nothing to do with email. They are just one of the many forms of interprocess communication available to us in the Win32 world.
Mailslots are similar to named pipes in some ways, but named pipes are a little more flexible and thus much more commonly used. A single mailslot is a one-way communication mechanism only; the process that creates the mailslot is referred to as the server. A client application can open the mailslot and write messages to it but cant read messages from it. Only the server can read messages from the mailslot. Hence the one-way communication limitation. In practice, however, you can use two mailslots to achieve two-way communication, with each process acting as both a client and a server (see Figure 1). The mailslot acts like a queue for messages. Incoming messages are appended to the end of the mailslot queue so that the server can read messages in the order they arrived in the mailslot. A message is saved in the mailslot until the server reads it.
An advantage of mailslots, over named pipes, is that they support broadcasting messages. A message can be sent to the mailslot on the local computer, to the mailslot on a specific computer name, to the mailslot of each computer on a specified domain, or to the mailslot of each computer on the primary domain. According to the documentation, when broadcasting messages to a domain, the message cannot be longer than 400 bytes. I didnt test this limitation, but domains can be large, and limiting the message size is a good idea regardless of any limitations. When sending a message to a specific mailslot, the message size limitation is set by the mailslot server when the mailslot is created (more on this later).
One word of caution is in order: mailslots use datagrams to broadcast messages. Datagrams do not provide any means for the client to confirm receipt of the message by the server. The MSDN documentation is unusually melodramatic about this point. In what could almost be mistaken as a quote from Stephen Ambroses Undaunted Courage, the MSDN documentation reports: Like a radio or television broadcast, a datagram offers no confirmation of receipt; there is no way to guarantee that a datagram has been received. Just as mountains, large buildings, or interfering signals might cause a radio or television signal to get lost, there are things that can prevent a datagram from reaching a particular destination. Named pipes are like telephone calls: you talk only to one party, but you know that the message is being received.
Mailslot Server
To demonstrate how mailslot servers work, I wrote the sample msserver.exe application. The source code for this application is msserver.cpp (listing 1), msserver.h (listing 2), msserver.rc (listing 3), and msname.h (listing 4).
Remember, the mailslot server is the process that creates the mailslot. Only the mailslot server (or a process that inherits the mailslot handle from the server) can read messages from that mailslot. You cant get around this by trying to create a remote mailslot. (Creating remote mailslots is not supported.)
The msserver.exe sample application is a simple Win32 program that first creates a mailslot and then displays a dialog box for displaying mailslot information and mailslot messages (see Figure 2). To create a mailslot, server applications call CreateMailslot(). CreateMailslot() is one of the three routines that only mailslot server applications can call (see Table 1). Remember that a single application can act as both a mailslot server and a mailslot client.
CreateMailslot() takes as parameters the name of the mailslot (this name is used by the client to establish a connection to this mailslot), the maximum message size, the read timeout value, and a pointer to a SECURITY_ATTRIBUTES structure. The name of my mailslot is PaulaT_Mailslot (the actual syntax is \\.\\mailslot\PaulaT_Mailslot). The mailslot name is defined in the msname.h file (listing 4), which is included by both the client and server applications. Mailslot names are not case-sensitive. I specified a maximum message size of 0, which means the size is not limited (a maximum of 64K is recommended). I specified a read timeout value of 5000, so my server will wait up to five seconds while attempting to read a message. Specifying a value of 0 means the server will return immediately if no messages are available. Likewise, specifying MAILSLOT_WAIT_FOREVER will cause the server read request to wait until a message is available before returning. Unless you want the returned mailslot handle to be inheritable by other processes, you typically wont need to specify any special security information.
The dialog box procedure for the msserver.exe sample application is ServerDlgProc(). This dialog box only has two buttons: GetMailSlotInfo and Read Message. When the GetMailSlotInfo button (ID_GETINFO) is pressed, the server calls the GetMailslotInfo() routine and displays the returned information in the corresponding dialog box text fields. This information includes some of the parameters used to create the mailslot (maximum message size and read timeout) as well as the count of messages currently in the mailslot and the size of the next message. Barring handle inheritance, only the process that created the mailslot (the mailslot server) is allowed to get information about the mailslot.
When the Read Message button is pressed, the server uses the standard ReadFile() file I/O routine to read the next message from the mailslot. If no message is currently available, the ReadFile() will return as soon as specified by the read timeout value (five seconds, in this case). If a message was successfully read from the mailslot, it is displayed in the edit box, otherwise an error message is displayed. Note that for simplicity, I am using a static buffer to hold the message. A better solution in real life would be to dynamically allocate the buffer based on the size of the next message returned from GetMailslotInfo().
When the server application terminates, the mailslot handle is closed, one way or another. When the servers mailslot handle is closed, the mailslot, itself, is closed and any pending messages are lost.
Mailslot Client
The sample mailslot client application is called msclient.exe. The sources are in msclient.cpp (listing 5), msclient.h (listing 6), and msclient.rc (listing 7). The mailslot client application opens a handle to an existing mailslot and writes messages to it. The sample msclient.exe program is also a Win32 application (see Figure 2). Msclient.exe creates a dialog box that is handled by the ClientDlgProc() routine. This dialog box only has one button: Write Message.
When the Write Message button is pressed, ClientDlgProc() first checks the state of the radio buttons. The radio buttons control which mailslot(s) the message is written to. In the first case, the message is sent to the mailslot on the local computer. The syntax for the mailslot name in this case, is \\.\mailslot\<mailslot_name>. To send the message to a mailslot on a specific computer, the syntax would be \\<computername>\mailslot\<mailslot_name>. To broadcast a message to the mailslot of all computers of a specific domain, the mailslot name syntax would be \\<domainname>\mailslot\<mailslot_name>. Finally, to send the message to the mailslot of every computer in the primary domain, you would use \\*\mailslot\<mailslot_name>. Of course, for the message to reach each computer, in a broadcast, each computer will need to have a server application create the mailslot and read messages from it.
The mailslot name is read from the msname.h (listing 4). Once I have a fully qualified mailslot name, the client simply calls CreateFile(). You do need to use the parameters specified in the source code example for the CreateFile() call to successfully open a handle to the existing mailslot.
Now that I have an open handle to the desired mailslot, I use the WriteFile() file I/O routine to write the message to the mailslot. Notice that the mailslot clients only use standard file I/O routines (see Table 1). Messages will be read from the server in the order they are written by the client.
Maximum Message Size
The MSDN documentation refers to a message boundary size at 425 bytes. In theory, messages less than 425 bytes are sent using datagrams, but messages larger than 426 bytes are sent using a connection-oriented transfer over an SMB session. When using the connection-oriented transfer, you are supposedly limited to one-to-one connections, so you lose the ability to broadcast messages. This also means that message of exactly 425 or 426 bytes are not supported. This alone might make mailslots impractical to use (who wants to be that careful about the size of each message). However, the problem with 425 and 426 byte messages doesnt appear to exist on the Windows NT platforms (NT, 2000 and XP). It may exist on the Windows 9x platforms. I couldnt round up a Windows 9x platform to test this on; Id be interested to hear from any readers who have used mailslots on these operating systems.
Global Mailslot Registry Setting
The Windows NT platforms support a global registry setting that controls how many buffers are used to process mailslots messages. If your application sends lots of messages, you can up the default number (which is five) to avoid losing any messages (which could happen if the server doesnt read them fast enough).
HKEY_LOCAL_MACHINE\ System\ CurrentControlSet\ Services\ LanmanWorkstation\ Parameters MailslotBuffers:REG_DWORD
Summary
If youve never heard of or used mailslots before, its good to know that you have an additional option for interprocess communication. In general, if I didnt need to broadcast messages to multiple computers or I required sending large messages, I would stick with named pipes. If you do need to broadcast short messages or require only one-way communication, mailslots are a very easy-to-use option.
Paula Tomlinson has been developing Windows, Windows CE, and Windows NT based applications and device drivers for 13 years. In her spare time, Paula enjoys flying N422HJ, a 1951 Ryan Navion. The opinions expressed here are hers alone. Paula can be reached at [email protected].