Special Edition Using Visual C++ 5 - Chapter 18

## Chapter 18

## Sockets, MAPI, and the Internet

There are a number of ways for your applications to communicate with other applications through a network like the Internet. This chapter introduces you to the concepts involved with these programming techniques. Subsequent chapters will cover some of these concepts in more detail.

Before the Windows operating system even existed, the Internet existed. As it grew, it became the largest TCP/IP network in the world. The early sites were UNIX machines, and a set of conventions called Berkeley sockets became the standard for TCP/IP communication between UNIX machines on the Internet. Other operating systems implemented TCP/IP communications, too, which contributed immensely to the growth of the Internet. On those operating systems, things were starting to get messy, with a wide variety of proprietary implementations of TCP/IP, when a group of over 20 vendors banded together to create the Winsock specification.

- Using Windows Sockets (Winsock)

  Describes the role that Winsock.dll plays in developing communications applications.

- Messaging API (MAPI)

  The capability to send messages is a must to receive a Windows 95 stamp of approval from Microsoft. This section shows you how to use this powerful API.

- New Internet Classes in Visual C++ 4.2

  These powerful classes make Internet development fast and easy.

- Internet Server API (ISAPI) Classes

  An Application Programmer Interface is a collection of utility functions collected for a similar purpose. The Internet Server API puts your World Wide Web server under your control.

### Using Windows Sockets

The Winsock specification defines the interface to a DLL, typically called WINSOCK.DLL or WSOCK32.DLL. Vendors write the code for the functions themselves. Applications can call the functions, confident that the name, parameter meaning, and final behavior of the function is the same no matter which DLL is installed on the machine. For example, the DLLs included with Windows 95 and Windows NT are not the same at all, but a 32-bit Winsock application can run unchanged on a Windows 95 or Windows NT machine, calling the Winsock functions in the appropriate DLL.

> Winsock is not confined to TCP/IP communication. IPX/SPX support is the second protocol supported, and there will be others. For more information, check the Winsock specification itself. The Stardust Labs Winsock Resource Page at http://www.stardust.com/wsresource/ is a great starting point.

An important concept in sockets programming is a socket's port. Every site on the Internet has a numeric address called an IP address, typically written as four numbers separated by dots: 198.53.145.3, for example. Programs running on that machine are all willing to talk, using sockets, to other machines. If a request arrives at 198.53.145.3, which program should handle it?

Requests arrive at the machine carrying a port number, a number from 1,024 and up that indicates for which program the request is intended. Some port numbers are reserved for standard use; for example, port 80 is traditionally used by Web servers to listen for Web document requests from client programs like Netscape Navigator.

Most socket work is connection-based: the two programs form a connection with a socket at each end and then send and receive data along the connection. Some applications prefer to send the data without a connection, but there is no guarantee that this data arrives. The classic example is a time server that sends out the current time to every machine near it, regularly, without waiting until it is asked. The delay in establishing a connection might make the time sent through the connection outdated, so it makes sense in this case to use a connectionless approach.

Winsock in MFC

At first, sockets programming in Visual C++ meant making API calls into the DLL. Many developers built socket classes to encapsulate these calls. Visual C++ 2.1 introduced two new classes: CAsyncSocket and CSocket, which inherits from CAsyncSocket. These classes handle the API calls for you, including the startup and cleanup calls that would otherwise be easy to forget.

Windows programming is asynchronous: there are lots of different things going on at the same time. In older versions of Windows, if one part of an application got stuck in a loop or otherwise hung up, the entire application—and sometimes the entire operating system—would stick or hang with it. This was obviously something to be avoided at all costs. Yet a socket call, perhaps a call to read some information through a TCP/IP connection to another site on the Internet, might take a long time to complete. (A function that is waiting to send or receive information on a socket is said to be blocking.) There are three ways around this problem:

1. Put the function that might block in a thread of its own. The thread will block, but the rest of the application will carry on.

2. Have the function return immediately after making the request, and have another function check regularly (poll the socket) to see if the request has completed.

3. Have the function return immediately, and send a Windows message when the request has completed.

Option 1 was not available until recently, and Option 2 is inefficient under Windows. So most Winsock programming adopts Option 3. The class CAsyncSocket implements this approach. For example, to send a string across a connected socket to another site on the Internet, you call that socket's Send() function. Send() doesn't necessarily send any data at all; it tries to, but if the socket isn't ready and waiting, Send() just returns. When the socket is ready, a message is sent to the socket window, which catches it and sends the data across. This is called asynchronous Winsock programming.

> Winsock programming is not a simple topic; entire books have been written on it. One you might like to look at is Que's Developing Internet Applications in Visual C++ ISBN 0-7897-0213-4. If you decide that this low-level sockets programming is the way to go, building standard programs is a good way to learn the process.

CAsyncSocket

The CAsyncSocket class is a wrapper class for the asynchronous Winsock calls. It has a number of useful functions, which facilitate using the Winsock API. Table 18.1 lists the CAsyncSocket member funtions and responsibilities.

Table 18.1—CAsyncSocket Member Functions

Method Name | Description
Accept | handles an incoming connection on a listening socket, filling a new socket with the address information.

    AsyncSelect

Requests that a Windows message be sent when a socket is ready.

    Attach

Attaches a socket handle to a CAsyncSocket instance, so that it can form a connection to another machine.

    Bind

Associates an address with a socket.

    Close

Closes the socket.

    Connect

Connects the socket to a remote address and port.

    Create

Completes the initialization process begun by the constructor.

    Detach

Detaches a previously attached socket handle.

    FromHandle

Returns a pointer to the CAsyncSocket attached to the handle it was passed.

    GetLastError

Returns the error code of the socket. Call GetLastError after an operation fails, to find out why.

    GetPeerName

Finds the IP address and port number of the remote socket that the calling object socket is connected to, or fills a socket address structure with that information.

    GetSockName

Returns the IP address and port number of this socket, or fills a socket address structure with that information.

    GetSockOpt

Returns the socket options that are currently set.

    IOCtl

Sets the mode of the socket; most commonly, to blocking or non-blocking.

    Listen

Instructs a socket to watch for incoming connections.

    OnAccept

Handles the Windows message generated when a socket has an incoming connection to accept. Often overridden by derived classes.

    OnClose

Handles the Windows message generated when a socket closes. Often overridden by derived classes.

    OnConnect

Handles the Windows message generated when a socket becomes connected or a connection attempt ends in failure. Often overridden by derived classes.

    OnOutOfBandData

Handles the Windows message generated when a socket has urgent, out-of-band data ready to read.

    OnReceive

Handles the Windows message generated when a socket has data that could be read with Receive().Often overridden by derived classes.

    OnSend

Handles the Windows message generated when a socket is ready to accept data that could be sent with Send(). Often overridden by derived classes.

    Receive

Reads data from the remote socket to which this socket is connected.

    ReceiveFrom

Reads a datagram from a connectionless remote socket.

    Send

Sends data to the remote socket to which this socket is connected.

    SendTo

Sends a datagram without a connection.

    SetSockOpt

Sets socket options.

ShutDown | Keeps the socket open but prevents any further Send() or Receive() calls.

If you use the CAsyncSocket class, you will have to fill the socket address structures yourself, and many developers would rather delegate a lot of this work. In that case, CSocket is a better socket class.

CSocket

CSocket inherits from CAsyncSocket and so has all the functions listed for CAsyncSocket. Table 13.2 describes the new methods added and the virtual methods that are overridden in the derived CSocket class.

Table 18.2—CSocket Methods

Method Name | Description

    Attach

Attaches a socket handle to a CAsyncSocket instance, so that it can form a connection to another machine.

    Create

Completes the initialization after the constructor constructs a blank socket.

    FromHandle

Returns a pointer to the CSocket attached to the handle it was passed.

    IsBlocking

Returns TRUE if the socket is blocking at the moment, waiting for something to happen.

    CancelBlockingCall

Cancels whatever request had left the socket blocking.

    OnMessagePending

Handles the Windows messages generated for other parts of your application while the socket is blocking. Often overridden by derived classes.

In many cases, socket programming is no longer necessary because the WinInet classes, ISAPI programming, and ActiveX controls for Web pages are bringing more and more power to Internet programmers. If you would like to explore a sample socket program, try Chatter and ChatSrvr, provided with Visual C++. Search on either name in the online help, or open the files, located on the CD in the \DevStudio\VC\Samples\MFC\Advanced\Chatter and \DevStudio\VC\Samples\MFC\Advanced\Chatsrvr folders.

Each session of Chatter emulates a user server. The ChatSrvr program is the server, acting as traffic manager among several clients. Each Chatter can send messages to the ChatSrvr—by typing in some text—and the ChatSrvr sends the message to everyone logged into the session. Several channels of traffic are managed at once.

If you’ve worked with sockets before, this short overview may be all you need to get started. If not, you may not need to learn them. If you plan to write a client/server application that runs over the Internet and does not use the existing standard applications like mail or the Web, then learning sockets is probably in your future. But, if you want to use e-mail, the Web, ftp, and other popular Internet information sources, you don’t have to do it by writing socket programs at all. You may be able to use MAPI, the WinInet classes, or ISAPI to achieve the results you are looking for.

### Messaging API (MAPI)

The most popular networking feature in most offices is electronic mail. You could add code to your application to generate the right commands over a socket to transmit a mail message, but it's simpler to build on the work of others.

What Is MAPI?

MAPI is a way of pulling together applications that need to send and receive messages (messaging applications) with applications that know how to send and receive messages (messaging services and service providers,) in order to lower the work load of all the developers involved. Figure 18.1 shows the scope of MAPI. Note that the word messaging actually covers far more than just electronic mail: a MAPI service could send a fax or voice-mail message rather than an electronic mail message. If your application uses MAPI, the messaging services such as e-mail clients that the user has installed will carry out the work of sending the messages that your application generates.

FIG. 18.1

The Messaging API covers applications that need messaging and those that provide it.

The extent to which an application uses messaging varies widely:

- Some applications can send a message, but sending messages is not really what the application is about. For example, a word processor is fundamentally about entering and formatting text and then printing or saving that text. If the word processor can also send the text in a message, fine, but that's incidental. Applications like this are said to be messaging aware and typically use just the tip of the MAPI functionality.
- Some applications are useful without being able to send messages, but they are far more useful in an environment where messages can be sent. For example, a personal scheduler program can manage one person's To Do list whether messaging is enabled or not, but if it is enabled, a number of workgroup and client-contact features—such as sending e-mail to confirm an appointment—become available. Applications like this are said to be messaging enabled and use some, but not all, of the MAPI features.
- Finally, some applications are all about messaging. Without messaging, these applications are useless. They are said to be messaging based, and they use all of MAPI's functionality.

Win95 Logo Requirements

The number-one reason for a developer to make an application messaging aware is to meet the requirements of the Windows 95 Logo program. To qualify for the logo, an application must have a Send item on the File menu that uses MAPI to send the document. (Exceptions are granted to applications without documents.)

To add this feature to your applications, it's best to think of it before you create the empty shell with AppWizard. If you are planning ahead, here is a list of all the work you have to do to meet this part of the logo requirement:

1. In Step 4 of AppWizard, select the MAPI (Messaging API) check box.

That's it! The menu item is added, and message maps and functions are generated to catch the menu item and call functions that use your Serialize() function to send the document through MAPI. Figure 18.2 shows an application called MAPIDemo, included on the book's CD-ROM, that is just an AppWizard empty shell.

FIG. 18.2

AppWizard adds the Send item to the File menu, as well as the code that handles the item.

No additional code was added, beyond the code generated by the AppWizard, to this application, and the Send item is on the File menu, as you can see. If you choose this menu item, your MAPI mail client is launched to send the message. Figures 18.2 and 18.3 were captured on a machine with Microsoft Exchange installed as an Internet mail client, and so it is Microsoft Exchange that is launched, as shown in Figure 18.3. The message contains the current document, and it is up to you to fill in the recipient, the subject, and any text you wish to send with the document.

FIG. 18.3

Microsoft Mail is launched so the user can fill in the rest of the e-mail message around the document that is being sent.

> If the Send item does not appear on your menu, make sure that you have a MAPI client installed. Microsoft Exchange is an easy-to-get MAPI client. The OnUpdateFileSendMail() function removes the menu item Send from the menu if no MAPI client is registered on your computer.

If you didn’t request MAPI support from AppWizard when you built your application, here are the steps to follow which will manually add the Send item:

1. Add the Send item to the File menu. Use a resource ID of ID_FILE_SEND_MAIL. The prompt will be supplied for you.

2. Add these two lines to the document's message map, outside the //AFX comments:

       ON_COMMAND(ID_FILE_SEND_MAIL, OnFileSendMail)

       ON_UPDATE_COMMAND_UI(ID_FILE_SEND_MAIL, OnUpdateFileSendMail)

Adding the mail support to your application manually is not much harder than asking AppWizard to do it.

Advanced Use of MAPI

If you want more from MAPI than just meeting the logo requirements, things do get harder. There are actually four kinds of MAPI client interfaces:

- Simple MAPI, an older API not recommended for use in new applications
- Common Messaging Calls (CMC), a simple API for messaging-aware and messaging-enabled applications
- Extended MAPI, a full-featured API for messaging-based applications
- OLE Messaging, an API with somewhat fewer features than Extended MAPI but ideal for use with Visual C++

Common Messaging Calls

There are only ten functions in the CMC API. That makes it easy to learn, yet packs enough punch to get the job done. They are the following:

- cmc_logon() connects to a mail server and identifies the user.
- cmc_logoff() disconnects from a mail server.
- cmc_send() sends a message.
- cmc_send_documents() sends one or more files.
- cmc_list() lists the messages in the user's mailbox.
- cmc_read() reads a message from the user's mailbox.
- cmc_act_on() saves or deletes a message.
- cmc_look_up() resolves names and addresses.
- cmc_query_configuration() reports what mail server is being used.
- cmc_free() frees any memory allocated by other functions.

The header file XCMC.H declares a number of structures used to hold the information that is passed to these functions. For example, recipient information is kept in this structure:

    /*RECIPIENT*/

    typedef struct {

        CMC_string              name;

        CMC_enum                name_type;

        CMC_string              address;

        CMC_enum                role;

        CMC_flags               recip_flags;

        CMC_extension FAR       *recip_extensions;

    } CMC_recipient;

You could fill this structure with the name and address of the recipient of a mail message by using a standard dialog box or by hard-coding the entries, like this:

    CMC_recipient recipient = {

        "Kate Gregory",

        CMC_TYPE_INDIVIDUAL,

        "SMTP:kate@gregcons.com",

        CMC_ROLE_TO,

        CMC_RECIP_LAST_ELEMENT,

        NULL };

The type, role, and flags use one of these predefined values:

Listing 18.1 (excerpt from \MSDev\Include\XCMC.H) Command definitions./* NAME TYPES */

#define CMC_TYPE_UNKNOWN ((CMC_enum) 0)

#define CMC_TYPE_INDIVIDUAL ((CMC_enum) 1)

#define CMC_TYPE_GROUP ((CMC_enum) 2)

/* ROLES */

#define CMC_ROLE_TO ((CMC_enum) 0)

#define CMC_ROLE_CC ((CMC_enum) 1)

#define CMC_ROLE_BCC ((CMC_enum) 2)

#define CMC_ROLE_ORIGINATOR ((CMC_enum) 3)

#define CMC_ROLE_AUTHORIZING_USER ((CMC_enum) 4)

/* RECIPIENT FLAGS */

#define CMC_RECIP_IGNORE ((CMC_flags) 1)

#define CMC_RECIP_LIST_TRUNCATED ((CMC_flags) 2)

    #define CMC_RECIP_LAST_ELEMENT              ((CMC_flags) 0x80000000)

There is a message structure you could fill in the same way, or by presenting the user with a dialog box to enter the message details. This structure includes a pointer to the recipient structure you have already filled. Your program then calls cmc_logon(), cmc_send(), and cmc_logoff() to complete the process.

Extended MAPI

Extended MAPI is based on COM, the OLE Component Object Model. Messages, recipients, and many other entities are defined as objects rather than as C structures. There are far more object types in Extended MAPI than there are structure types in CMC. Access to these objects is through OLE (ActiveX) interfaces. The objects expose properties, methods, and events. These concepts are discussed in Part IV, Chapter 14, "ActiveX Concepts."

OLE Messaging

If you understand Automation (described in Chapter 16, "Building an Automation Server"), then you will easily understand OLE Messaging. Your application must be an Automation client, however, and building such a client is beyond the scope of this chapter. Some ways to use OLE Messaging are in Visual Basic programming and VBA scripts for programs like Excel. Your program would set up objects and then set their exposed properties (for example, the subject line of a message object) and invoke their exposed methods (for example, the Send() method of a message object).

The objects used in OLE Messaging include the following:

- Session
- Message
- Recipient
- Attachment

A detailed reference of these objects, as well as their properties and methods, can be found in Visual C++ Books Online (the help files) from within Developer Studio. Follow the Books Online hierarchy: SDKs, Win32 SDK, Win32 Messaging (MAPI), OLE Messaging Library.

### Using New Internet Classes in Visual C++ 4.2

MFC 4.2 introduced a number of new classes that eliminated the need to learn socket programming when your applications need to access standard Internet client services. Figure 18.4 shows the way these classes relate to each other. Collectively known as the WinInet classes, they are the following:

FIG. 18.4

The WinInet classes make writing Internet client programs easier.

- CInternetSession
- CInternetConnection
- CInternetFile
- HttpConnection
- CHttpFile
- CGopherFile
- CFtpConnection
- CGopherConnection
- CFileFind
- CFtpFileFind
- CGopherFileFind
- CGopherLocator
- CInternetException

> These classes help you write Internet client applications, with which users interact directly. If you want to write server applications, which interact with client applications, you'll be interested in ISAPI, discussed in the next section.

First, your program establishes a session by creating a CInternetSession. Then, if you have a Uniform Resource Locator (URL) to a Gopher, FTP, or Web (HTTP) resource, you can call that session's OpenURL() function to retrieve the resource as a read-only CInternetFile. Your application can read the file using CStdioFile functions and manipulate that data in whatever way you need.

If you do not have a URL or do not want to retrieve a read-only file, you proceed differently after establishing the session. You make a connection with a specific protocol by calling the session's GetFtpConnection(), GetGopherConnection(), or GetHttpConnection() functions, which return the appropriate connection object. You then call the connection's OpenFile() function. CFtpConnection::OpenFile() returns a CInternetFile; CGopherConnection::OpenFile() returns a CGopherFile; and CHttpConnection::OpenFile() returns a CHttpFile. The CFileFind class and its derived classes help you find the file you want to open.

Chapter 19, "Internet Programming with the WinInet Classes," works through an example client program using WinInet classes to establish an Internet session and retrieve information.

> Though e-mail is a standard Internet application, you'll notice that the WinInet classes do not have any e-mail functionality. That's because e-mail is handled by MAPI. There is no support for Usenet news either, in the WinInet classes or elsewhere.

### Using Internet Server API (ISAPI) Classes

ISAPI is used to enhance and extend the capabilities of your HTTP (World Wide Web) server. ISAPI developers produce extensions and filters. Extensions are DLLs that are invoked by a user from a Web page in much the same way as CGI applications are invoked from a Web page. Filters are DLLs that run with the server and look at or change the data going to and from the server. For example, a filter might redirect requests for one file to a new location.

> In order for the ISAPI extensions and filters that you write to be useful, your Web pages must be kept on a server that is running as ISAPI-compliant server like the Microsoft IIS Server. You must have permission to install DLLs onto the server, and for an ISAPI filter, you must be able to change the Registry on the server. If your Web pages are kept on a machine administered by your Internet Service Provider (ISP), you will probably not be able to use ISAPI to bring more power to your Web pages. You may choose to move your pages to a dedicated server (a powerful Intel machine running Windows NT Server 4.0 and Microsoft IIS is a good combination) so that you can use ISAPI, but this will involve considerable expense. Make sure that you understand the constraints of your current Web server before embarking on a project with ISAPI.

> One of the major advantages of ActiveX controls for the Internet (discussed in Chapter 21, "The Active Template Library,” is that you do not need access to the server in order to implement them.

The five MFC ISAPI classes form a wrapper for the API to make it easier to use. They are:

- CHttpServer
- CHttpFilter
- CHttpServerContext
- CHttpFilterContext
- CHtmlStream

Your application will have a server or a filter class (or both) that inherit from CHttpServer or CHttpFilter. These are rather like the classes in a normal application that inherit from CWinApp. There is only one instance of the class in each DLL, and each interaction of the server with a client is done through its own instance of the appropriate context class. (A DLL may contain both a server and a filter, but at most one of each.) CHtmlStream is a helper class that describes a stream of HTML to be sent by a server to a client.

The ISAPI Extension Wizard is an AppWizard that simplifies creating extensions and filters. To use this wizard, choose File, New, as always, and then the Project tab. Scroll down the list on the left and select ISAPI Extension Wizard (as shown in Figure 18.5) and then fill in the project name and folder, and click OK.

FIG. 18.5

The ISAPI Extension Wizard is another kind of AppWizard.

Creating a server extension is a one-step process. That step, which is also the first step for a filter, is shown in Figure 18.6. The names and descriptions for the filter and extension are based on the project name that you chose.

FIG. 18.6

The first step in the ISAPI Extension Wizard process is to name the components of the DLL that you are creating.

If you choose to create a filter, the Next button is enabled and you can move to the second step for filters, shown in Figure 18.7. This list of parameters gives you an idea of the power of an ISAPI filter. You can monitor all incoming and outgoing requests and raw data, authenticate users, log traffic, and more.

FIG. 18.7

The second step in the ISAPI Extension Wizard process is to set filter parameters.

AppWizard shows you a final confirmation screen before creating the files. When you create a server and a filter at the same time, 11 files are created for you, including source and headers for the class that inherits from CHttpServer and the class that inherits from CHttpFilter.

Writing a filter from this shell is quite simple. You have been provided with a stub function to react to each event for which notification was requested. For example, the filter class has a function called OnEndOfNetSession(), which is called when a client's session with this server is ending. You add code to this function to log, monitor, or otherwise react to this event. When the filter is complete, you edit the Registry by hand so that the server will run your DLL.

To write an extension, add one or more functions to your DLL. Each function will be passed a CHttpContext pointer, which can be used to gather information such as the user's IP address. If the function is invoked from an HTML form, additional parameters such as values of other fields on the form will also be passed to the function.

The details of what the function does depend on your application. If you are implementing an online ordering system, the functions involved will be lengthy and complex. Other extensions will be simpler.

When the function is complete, you place the DLL in the executable folder for the server—usually the folder where CGI programs are kept—and adjust your Web pages so that they include links to your DLL, like this:

    Now you can <A HREF=http://www.company.com/exec/orders.dll>

    place an order</A>
    online!

For more information on ISAPI programming, be sure to read Que’s Special Edition Using ISAPI, included in its entirety on this book’s CD. You will learn how ISAPI applications can make your Web site dynamic and interactive, learn how to write filters and extensions, and cover advanced topics including debugging ISAPI applications and writing multi-threaded applications.

### From Here...

Adding the Internet to your applications is an exciting trend. It's going to make lots of work for programmers and create some powerful products that simplify the working life of anyone with an Internet connection. Just a year ago, writing Internet applications meant getting your fingernails dirty with sockets programming, memorizing TCP/IP ports, and reading RFCs. The new WinInet and ISAPI classes, as well as improvements to the old MAPI support, mean that today you can add amazing power to your application with just a few lines of code or by selecting a box on an AppWizard dialog box.

To learn more about using the APIs introduced in this chapter and building other specific kinds of applications refer to:

- Chapter 22, "Database Access," covers the basics of database manipulation.
- Chapter 19, "Internet Programming with the WinInet Classes" lets you work through an example program built with the WinInet classes.

© 1997, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.