Free VC++ Tutorial

Web based School

Previous Page Main Page Next Page


35 — Writing Messaging Applications with MAPI

Writing messaging-enabled applications is no longer the task of a few corporate programmers working on enterprise-wide system integration projects. Microsoft Exchange and MAPI services are now available on every Windows 95 desktop; and with the recent phenomenal growth of the Internet, users in increasing numbers demand messaging features in end-user applications. Solutions that were developed for corporate networks yesterday are used on home computers today; if this sounds like an outrageous claim, consider the fact that I am submitting the very pages of this manuscript by dragging the files into Microsoft Exchange and letting them go.

Microsoft recognized this fact when it decided to add the requirement for some level of MAPI support to its Windows 95 Logo Program. For applications to qualify under this program, it is now necessary for them to support, at the very minimum, a Send command that enables them to send a document to a MAPI recipient. (Obviously, if your application is conceptually different, such as a game program, MAPI support is not required.)

The MAPI acronym stands for Messaging Applications Programming Interface. But what exactly is MAPI? How is MAPI implemented? And, most importantly, in what way can applications utilize MAPI services most efficiently? These are the questions that I attempt to answer in the present chapter.

Be aware that the purpose of this chapter is not to provide an introduction to MAPI at the level required to develop MAPI providers. Such discussion would itself warrant a guide. Instead, I am trying to present an overview of MAPI as an application interface, with special emphasis on MAPI usage from within MFC framework applications.


NOTE: Throughout this chapter, the MAPI architecture I describe corresponds to MAPI in Windows 95 or in upcoming versions of Windows NT. Earlier versions of Microsoft Mail, although they provide limited support for Simple MAPI and CMC, do not provide full Extended MAPI support, nor are they compatible with the architecture described in this chapter.

The MAPI Architecture

What exactly is MAPI? Is it the Microsoft Exchange Client that is supplied with Windows 95? Is it the much anticipated Exchange Server? Is it the MAPI spooler that is quietly running in the background whenever Exchange is started?

The answer is, none of the above. MAPI is not an application, a DLL, or a system service; rather, it is a series of specifications. Although Microsoft is the prime supplier of MAPI components, it is by no means necessary to have a single Microsoft component in order to use MAPI (nor is it necessary to use a Windows or Win32 platform, actually). You can have a MAPI-compliant system with third party message store, address guide, and transport providers on a non-Windows operating system. MAPI is part of what Microsoft calls WOSA, the Windows Open Services Architecture, that consists of a common set of APIs for distributed computing.

MAPI, in fact, can be viewed as two independent sets of APIs that link client applications on the one hand with service providers on the other (Figure 35.1).


Figure 35.1. The MAPI architecture.

Why several APIs? The reasons are partly historical. First, Microsoft released the specifications for Simple MAPI, which included about a dozen fundamental calls that enabled applications to use messaging. The Common Messaging Calls (CMC)API has been developed as a platform-independent replacement for Simple MAPI. It also contains about 10 fundamental calls that provide access to basic messaging services. In contrast, Extended MAPI is a large, complex, evolving specification that not only provides an application programming interface for client applications but for service providers as well. OLE Messaging, an API specifically developed for Visual Basic and Visual C++ applications, uses the OLE automation architecture.

Before we plunge into exploring the APIs, the next section gives us a closer look at the MAPI architecture itself.

Types of MAPI Support

There are three distinct levels of MAPI support that applications can provide.

The simplest MAPI applications are messaging-aware applications. These applications do not depend on the presence of MAPI to perform their functions; they merely provide some simple MAPI functionality. The Windows 95 WordPad, which provides a Send command in its File menu, is a good example for a messaging-aware application. In contrast, messaging-enabled applications require MAPI to be present in order to offer full functionality. While these applications may function when MAPI is not present, they cannot offer the full range of their services under these conditions. A perfect example for a messaging-enabled application is Microsoft Schedule+; while this program can be used as a stand-alone personal information manager, many of its capabilities do not make sense unless it is running on a system with MAPI installed.

At the top of the hierarchy are messaging-based applications. Running these applications requires that the full range of MAPI services (message store, address guide, transport) be present and available. These applications are also often referred to as workgroup applications. A good example for a workgroup application is the Microsoft Exchange client; I will spare you the explanation why this application cannot be run on a stand-alone system with no MAPI support.

The next section presents a brief tour of MAPI service providers; then we can examine how the various APIs are used in applications that provide these different levels of support

Service Providers

MAPI service providers are the components that collectively implement MAPI service on a system. There are three distinct types of service providers: message stores, address guides, and transports.

Address guides contain one or more lists of recipients. An address guide provider implements a specific set of interfaces through which messaging applications or other providers can gain access to address entries or lists of addresses.

Message stores are hierarchical depositories of MAPI messages. A message consists of a multitude of properties that include the sender of the message, the recipient, the date, subject, message body, and many other items. Message store providers implement some form of persistent storage for messages (for example, a local disk file) and provide a set of interfaces through which messaging applications and other providers can enumerate messages in the message store, retrieve specific message properties, or retrieve a set of messages.

Transport providers represent the link between the local system and remote systems. Transport providers take outgoing messages, establish connections to remote systems, and transmit messages in a format that the remote system can comprehend. Transport providers also accept incoming messages from the remote system, translate these into MAPI message objects as necessary, and place them into the local message store. A good example of a transport provider is the Microsoft Internet transport provider, which connects to remote systems using Windows Sockets and uses SMTP (Simple Mail Transfer Protocol) for outgoing and POP (Post Office Protocol) for incoming messages. Outgoing messages are translated into a readable ASCII form; incoming messages are translated from such form into MAPI message objects.

All providers are represented in the form of DLLs. The set of DLLs that are to be loaded for a MAPI session is determined by MAPI profiles.

MAPI Profiles

The "glue" that holds MAPI components together is the MAPI Spooler. The MAPI Spooler is a separate process that facilitates message receipt and delivery. It is typically the MAPI Spooler that passes submitted messages to transport providers and accepts incoming messages from them. The MAPI Spooler implements a store-and-forward architecture; that is, messages submitted are "spooled" by the spooler to the appropriate transport provider when it becomes available. This capability is vital on systems with large message volumes and many remote connections.

Actually, it is also the MAPI Spooler that is responsible for loading and initializing service providers. But how does the spooler know which service providers to load?

The answer is MAPI profiles. MAPI profiles are registry entries that specify the current MAPI configuration.

These registry entries can be found under the following registry key:

HKEY_CURRENT_USER\

    Software\

        Microsoft\

            Windows Messaging Subsystem\

                Profiles

Note that the MAPI profile registry entries are generally not readable by human beings and should not be edited manually.

There can be several profiles defined for a user. Each profile describes a series of service providers and their operating parameters. For example, a typical profile may include the Microsoft Personal Information Store (message store provider), the Microsoft Personal Address guide (address guide provider), Microsoft Fax (transport provider), and the Microsoft Network Online Service (address guide and transport). MAPI profiles can be edited using the Microsoft Exchange client; select the Services command from its Tools menu (Figure 35.2).


Figure 35.2. Editing a MAPI profile.

MAPI APIs

The different APIs serve different types of MAPI applications.

Messaging-aware and messaging-enabled applications can use both Simple MAPI and CMC. The main advantage of using CMC is complete platform independence. It is recommended that newer applications use CMC in place of Simple MAPI.

Messaging-based applications (not to mention service providers) require access to the full MAPI API set and thus should use Extended MAPI.

OLE Messaging is used by Visual Basic and Visual C++ applications. OLE Messaging provides a richer API than CMC or Simple MAPI but falls short of the functionality of the full Extended MAPI set.

Simple MAPI

Simple MAPI provides a series of functions that enable applications to establish a MAPI session, perform messaging functions, and shut down the session.

The simplest way to use Simple MAPI is via the MAPISendDocuments function. This function can be used to create a standard MAPI message with one or more file attachments. MAPISendDocuments always displays a dialog where the user can specify recipients, sending options, and the message text. This is demonstrated by the program in Listing 35.1. This program sends a message using MAPISendDocuments with the file c:\autoexec.bat embedded in it. You can compile this program from the command line by typing cl sendmsg.c user32.lib.

    Listing 35.1. Using MAPISendDocuments.
#include <windows.h>

#include <mapi.h>

LPMAPISENDDOCUMENTS lpfnMAPISendDocuments;

void SendMsg(HWND hwnd)

{

    (*lpfnMAPISendDocuments)((ULONG)hwnd, ";", "C:\\AUTOEXEC.BAT",

                             "AUTOEXEC.BAT", 0);

    MessageBox(hwnd, "Message sent", "", MB_OK);

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg,

                         WPARAM wParam, LPARAM lParam)

{

    switch(uMsg)

    {

        case WM_LBUTTONDOWN:

            SendMsg(hwnd);

            break;

        case WM_DESTROY:

            PostQuitMessage(0);

            break;

        default:

            return DefWindowProc(hwnd, uMsg, wParam, lParam);

    }

    return 0;

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

                                        LPSTR d3, int nCmdShow)

{

    MSG msg;

    HWND hwnd;

    WNDCLASS wndClass;

    HANDLE hMAPILib;

    hMAPILib = LoadLibrary("MAPI32.DLL");

    lpfnMAPISendDocuments = (LPMAPISENDDOCUMENTS)GetProcAddress(

                                  hMAPILib, "MAPISendDocuments");

    if (hPrevInstance == NULL)

    {

        memset(&wndClass, 0, sizeof(wndClass));

        wndClass.style = CS_HREDRAW | CS_VREDRAW;

        wndClass.lpfnWndProc = WndProc;

        wndClass.hInstance = hInstance;

        wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);

        wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

        wndClass.lpszClassName = "HELLO";

        if (!RegisterClass(&wndClass)) return FALSE;

    }

    hwnd = CreateWindow("HELLO", "HELLO",

                        WS_OVERLAPPEDWINDOW,

                        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,

                        NULL, NULL, hInstance, NULL);

    ShowWindow(hwnd, nCmdShow);

    UpdateWindow(hwnd);

    while (GetMessage(&msg, NULL, 0, 0))

        DispatchMessage(&msg);

    FreeLibrary(hMAPILib);

    return msg.wParam;

}

A much more flexible way of sending messages is through MAPISendMail. Through a series of structures, you can specify the recipient and contents of the message. MAPISendMail makes it possible to send mail without presenting a user interface whatsoever. Thus, MAPISendMail can also be used, for example, from command-line applications.

MAPISendMail is typically used within a MAPI session that is started by a call to MAPILogon and terminated by calling MAPILogoff. This usage of MAPISendMail is demonstrated by the program in Listing 35.2, which sends a simple text message to president@whitehouse.gov without displaying a user interface. (For the sake of the sanity of Mr. Clinton's staff, do change the mail address before you start experimenting with this program!)

    Listing 35.2. Using Simple MAPI in a console application.
#include <windows.h>

#include <stdio.h>

#include <mapi.h>

LPMAPILOGON lpfnMAPILogon;

LPMAPISENDMAIL lpfnMAPISendMail;

LPMAPILOGOFF lpfnMAPILogoff;

MapiRecipDesc recipient =

{

    0, MAPI_TO,

    "Bill Clinton", "SMTP:president@whitehouse.gov",

    0, NULL

};

MapiMessage message =

{

    0, "Greetings",

    "Hello, Mr. President!\n",

    NULL, NULL, NULL, 0, NULL, 1, &recipient, 0, NULL

};

void main(void)

{

    LHANDLE lhSession;

    HANDLE hMAPILib;

    hMAPILib = LoadLibrary("MAPI32.DLL");

    lpfnMAPILogon =

        (LPMAPILOGON)GetProcAddress(hMAPILib, "MAPILogon");

    lpfnMAPISendMail =

        (LPMAPISENDMAIL)GetProcAddress(hMAPILib, "MAPISendMail");

    lpfnMAPILogoff =

        (LPMAPILOGOFF)GetProcAddress(hMAPILib, "MAPILogoff");

    (*lpfnMAPILogon)(0, NULL, NULL, MAPI_ALLOW_OTHERS, 0,

                     &lhSession);

    (*lpfnMAPISendMail)(lhSession, 0, &message, 0, 0);

    (*lpfnMAPILogoff)(lhSession, 0, 0, 0);

    printf("Message to the White House sent.\n");

    FreeLibrary(hMAPILib);

}

Simple MAPI can also be used to process incoming messages. Calls like MAPIFindNext and MAPIReadMail can be used, for example, to examine new messages in the user's Inbox.

Simple MAPI also offers a user interface for entering addresses. Instead of using MAPISendDocuments, you can utilize the MAPIAddress call to enable the user to select and enter addresses.

Common Messaging Calls

Common Messaging Calls is an implementation of the X.400 API Association's Common Messaging Call API. It provides a series of high-level messaging functions that can be used in a fashion similar to Simple MAPI.

Table 35.1 compares CMC functions with Simple MAPI functions.

    Table 35.1. CMC and Simple MAPI.
CMC


Simple MAPI


Description


cmc_logon

MAPILogon

Log on to the service

cmc_logoff

MAPILogoff

Log off from the service

cmc_free

MAPIFreeBuffer

Free allocated memory

cmc_send

MAPISendMail

Send a message

cmc_send_documents

MAPISendDocuments

Send files in a message

cmc_list

MAPIFindNext

Find messages

cmc_read

MAPIReadMail

Retrieve messages

cmc_act_on

MAPISaveMail

MAPIDeleteMail

Save or delete messages

cmc_look_up

MAPIAddress

MAPIDetails

MAPIResolveName

Addressing

cmc_query_configuration

N/A

CMC configuration data

The program in Listing 35.3 demonstrates the use of CMC calls from within a console application. You can compile and run this program from the command line. To compile, use cl cmcmsg.c.

    Listing 35.3. CMC in a console application.
#include <windows.h>

#include <xcmc.h>

typedef CMC_return_code (FAR PASCAL *LPFNCMCLOGON)(CMC_string,

    CMC_string, CMC_string, CMC_enum, CMC_ui_id, CMC_uint16,

    CMC_flags, CMC_session_id FAR *,CMC_extension FAR *);

typedef CMC_return_code (FAR PASCAL *LPFNCMCSEND)(CMC_session_id,

    CMC_message FAR *, CMC_flags, CMC_ui_id,CMC_extension FAR *);

typedef CMC_return_code (FAR PASCAL *LPFNCMCLOGOFF)(CMC_session_id,

    CMC_ui_id, CMC_flags, CMC_extension FAR *);

LPFNCMCLOGON lpfnCMCLogon;

LPFNCMCSEND lpfnCMCSend;

LPFNCMCLOGOFF lpfnCMCLogoff;

CMC_recipient recipient =

{

    "Bill Clinton", CMC_TYPE_INDIVIDUAL,

    "SMTP:president@whitehouse.gov", CMC_ROLE_TO,

    CMC_RECIP_LAST_ELEMENT, NULL

};

CMC_message message =

{

    NULL, "CMC: IPM", "Greetings", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

    "Hello, Mr. President!\n", &recipient, NULL,

    CMC_MSG_LAST_ELEMENT, NULL

};

void main(void)

{

    char msg[1000];

    CMC_session_id session;

    CMC_return_code retcode;

    HANDLE hMAPILib;

    hMAPILib = LoadLibrary("MAPI32.DLL");

    lpfnCMCLogon =

        (LPFNCMCLOGON)GetProcAddress(hMAPILib, "cmc_logon");

    lpfnCMCSend =

        (LPFNCMCSEND)GetProcAddress(hMAPILib, "cmc_send");

    lpfnCMCLogoff =

        (LPFNCMCLOGOFF)GetProcAddress(hMAPILib, "cmc_logoff");

    (*lpfnCMCLogon)(NULL, NULL, NULL, (CMC_enum)0, 0, 100,

      CMC_ERROR_UI_ALLOWED | CMC_LOGON_UI_ALLOWED, &session, NULL);

    (*lpfnCMCSend)(session, &message, 0, 0, NULL);

    (*lpfnCMCLogoff)(session, 0,

               CMC_ERROR_UI_ALLOWED | CMC_LOGOFF_UI_ALLOWED, NULL);

    printf("Message to the White House sent.\n");

    FreeLibrary(hMAPILib);

}

Extended MAPI

Extended MAPI is a large, complex object-oriented programming interface to all aspects of MAPI. Its programming model is based on OLE COM, the OLE Component Object Model.

Extended MAPI defines a series of object types, including messages, message stores, folders, attachments, mail users, address guides, providers, sessions, and many more supplementary objects. MAPI objects are characterized by a set of properties, themselves implemented as objects. MAPI objects are accessed through interfaces derived from the OLE IUnknown interface. For example, property objects implement the IMAPIProp interface, while message objects implement the IMessage interface.

Extended MAPI programming involves manipulating MAPI objects through their properties and methods and through event notifications. MAPI properties can be manipulated through property objects and the IMAPIProp interface, or through property tables. Methods are the IUnknown-derived interfaces that MAPI objects provide. Event notification is the mechanism of communication between MAPI objects.

Extended MAPI can be used to implement messaging-based applications that require finer control over messaging services than what is available through Simple MAPI or CMC. Extended MAPI can also be used to perform administrative functions, such as selecting and configuring services and creating user profiles.

Another use of Extended MAPI is to program with MAPI forms. MAPI forms represent special types of messages, implemented through a user interface and a form server, which manage the user's interaction with the forms message.

Extended MAPI can also be used to extend the Microsoft Exchange client. Customized versions of the Microsoft Exchange client can provide application-specific views on address guides, message stores, and message objects, and can add new searching, addressing, and workgroup features to that application.

Lastly, Extended MAPI also represents the programming interface for creating MAPI service providers. These include address guides, message stores, and transports.

OLE Messaging

OLE messaging exposes MAPI objects through the OLE automation interface. As such, it works best with OLE automation clients, such as Visual Basic applications or programs written in Visual Basic for Applications (that is, Microsoft Excel, Access, or Project programs).

Figure 35.3 illustrates the hierarchy of OLE automation objects exposed by OLE messaging.


Figure 35.3. OLE messaging objects.

Demonstrating the use of OLE messaging from within Visual C++ is difficult, as it requires constructing an OLE automation client application. In order to demonstrate a simple OLE messaging session, I decided to resort to Visual Basic. The example shown in Listing 35.4 shows how a Visual Basic application can send a simple message without displaying a user interface.

    Listing 35.4. OLE messaging example in Visual Basic.
Sub Command1_Click ()

    Dim objSession As Object

    Dim objMessage As Object

    Dim objRecip As Object

    Set objSession = CreateObject("MAPI.Session")

    objSession.Logon "", "", False, False

    Set objMessage = objSession.Outbox.Messages.Add

    objMessage.Subject = "Greetings"

    objMessage.Text = "Hello again, Mr. President!"

    Set objRecip = objMessage.Recipients.Add

    objRecip.Name = "Bill Clinton"

    objRecip.Address = "SMTP:president@whitehouse.gov"

    objRecip.Type = 1

    objRecip.Resolve (False)

    objMessage.Send True, False

    MsgBox "Message to the White House sent"

    objSession.Logoff

    Exit Sub

End Sub

To test this simple example, attach this code to a button in a Visual Basic form (you can also use disptest.exe, the OLE automation test version of Visual Basic that came as part of your Visual C++ installation), run the program, and click on the button. Oh, and don't forget to change the address before exercising this code!

Note that this test will only work if you have OLE messaging installed on your computer. OLE messaging components are only available at present as part of the MAPI SDK, distributed through the Microsoft Developer Network level 2 subscription.

MAPI Support in MFC

The Microsoft Foundation Classes Library provides MAPI support through a series of member functions in CDocument. This support, and how this support is incorporated into MFC framework applications, is the subject of the last part of this chapter.

MAPI Support in CDocument

The CDocument class supports MAPI through the OnFileSendMail member function.

CDocument::OnFileSendMail serializes the document into a temporary file, and then calls Simple MAPI functions to prepare and send a message with this file as an attachment.

A variant of CDocument::OnFileSendMail is COleDocument::OnFileSendMail; this version handles compound files correctly.

The CDocument::OnUpdateFileSendMail member function determines whether MAPI support is available on the system and updates command items accordingly through a CCmdUI object.

MAPI and AppWizard

The AppWizard can generate skeleton applications with minimal MAPI support. If requested, the AppWizard will add a Send menu item to the new application's File menu. This item will invoke the OnFileSendMail member function of the application's document class. AppWizard will also install a command update handler, referencing the OnUpdateFileSendMail member function.

In other words, if you only wish to make your application messaging-aware, you need not do anything other than enabling MAPI support when creating the application's skeleton with AppWizard. This is all you need to do in order to satisfy the new Windows 95 Logo requirements.

Summary

MAPI, the Messaging Application Programming Interface, represents a comprehensive set of specifications that link messaging applications on the one hand and messaging service providers on the other, forming a messaging architecture.

Messaging applications include messaging-aware, messaging-enabled, and messaging-based programs. Messaging-aware applications such as the Windows 95 WordPad, although they provide some level of MAPI functionality, do not depend on the presence of MAPI for their functionality. Messaging-enabled applications such as Microsoft Schedule+ require the presence of MAPI to perform many of their functions. Messaging-based applications such as the Microsoft Exchange client require MAPI in order to function.

On the service provider side, MAPI recognizes message stores, address guides, and transport providers. These providers, acting under the control of the MAPI Spooler, perform the services that together form the messaging system on your computer.

The MAPI configuration is stored in the form of MAPI profiles. MAPI profiles are registry entries that identify active MAPI services and their configuration. A user can have several MAPI profiles, with an active profile selected at the start of the MAPI session.

When developing MAPI applications, one can pick one of several APIs. Simple MAPI provides a set of functions essential for addressing sending simple messages and retrieving incoming messages. Similar functionality is offered by CMC, the Common Messaging Call API; however, CMC is completely platform-independent. CMC is an implementation of the X.400 API Association's Common Messaging Call API. Visual Basic and Visual C++ applications can also use OLE Messaging for an object-oriented interface to MAPI functions.

The full interface to MAPI, Extended MAPI, is used for developing messaging-based applications, service providers, new message types (MAPI forms), administrative applications, and extensions to the Microsoft Exchange client application.

Previous Page Main Page Next Page