MAPI, SAPI, and TAPI Developer's Guide
MAPI, SAPI, and TAPI Developer's Guide
SAPI, and
TAPI Developer's Guide
by Michael C. Amundsen
C O N T E N T S
● What Is WOSA?
● The WOSA Model
❍ The Client API Makes Requests
● WOSA Services
❍ Common Application Services
❍ Communication Services
● Benefits of WOSA
❍Isolated Development
❍ Multivendor Support
❍ Upgrade Protection
● Summary
❍ Consistency
❍ Portability
● Messages
❍ Text Messages
❍ Control Messages
● MAPI Applications
❍ Electronic Mail Clients
❍ Message-Aware Applications
❍ Message-Enabled Applications
● Summary
❍ Storage Folders
❍ Addresses
❍ Message Stores
❍ Address Books
● Introduction
● What Is the Microsoft Exchange Forms Designer?
❍ EFD Design Wizards
● Summary
● Summary
❍ Additional Features
● Summary
● Introduction
● The Session Object
❍ The Session Object Methods
● Summary
Chapter 9 Creating a MAPI Mailing List Manager with the OLE Messaging
Library
● Introduction
❍ Laying Out the MLM Form
❍ Dropping Subscribers
❍ Listing Archives
● Summary
● Summary
❍ Property Extensions
❍ Registering Extensions
● Summary
● Speech Recognition
❍ Word Separation
❍ Speaker Dependence
❍ Word Matching
❍ Vocabulary
❍ Text-to-Speech
❍ Voice Quality
❍ Phonemes
❍ TTS Synthesis
● Grammar Rules
❍ Context-Free Grammars
❍ Dictation Grammars
● Summary
● Introduction
● High-Level SAPI
❍ Voice Command
❍ Voice Text
● Low-Level SAPI
❍ Speech Recognition
❍ Text-to-Speech
● Summary
● SAPI Hardware
❍ General Hardware Requirements
● Technology Issues
❍ SR Techniques
❍ SR Limits
❍ TTS Techniques
❍ TTS Limits
❍ Using the Enable Property to Start and Stop the TTS Engine
● Summary
● Control Tags
❍ The Voice Character Control Tags
● Grammar Rules
❍ General Rules for the SAPI Context-Free Grammar
❍ Phones
❍ pc-Based Configurations
❍ Multiline Configurations
❍ Digital T1 Lines
● Summary
● Summary
● Summary
❍ Testing TAPIANS
● Summary
● Summary
● Testing TAPIFONE
● Summary
● Microsoft Phone
❍ Adding Announcement, Message, and AutoFax Mailboxes
● Summary
● Introduction
● General Considerations
❍ Rules of Complexity
● Introduction
● Project Resources
❍ The VBVoice Controls
● Project Resources
● Coding the Library Modules
❍ The AssistedTAPI Module
● Design Considerations
❍ Project Forms and Resources
❍ Coding tmView
❍ Coding tmNew
❍ Coding tmRead
● Design Issues
● The FaxBack Application
● The Voice Phone Application
● The Talk Mail Project
● Some Final Remarks
● Books
● Web Links
● Other Online Resources
● Books
● Web Links
● Other Online Resources
● Software and Hardware Resources
● Books
● Web Links
● Other Online Resources
● Software and Hardware Resources
This book is dedicated to Joe and Ida LaSala in thanks for their love, support, and
generosity over the last twenty years.
FIRST EDITION
All rights reserved. No part of this book shall be reproduced, stored in a retrieval system, or transmitted by any means,
electronic, mechanical, photocopying, recording, or otherwise, without written permission from the publisher. No patent
liability is assumed with respect to the use of the information contained herein. Although every precaution has been
taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions. Neither
is any liability assumed for damages resulting from the use of the information contained herein. For information, address
Sams Publishing, 201 W. 103rd St., Indianapolis, IN 46290.
HTML conversion by :
M/s. LeafWriters (India) Pvt. Ltd.
Website : http://leaf.stpn.soft.net
e-mail : [email protected]
Trademarks
All terms mentioned in this book that are known to be trademarks or service marks have been appropriately capitalized.
Sams Publishing cannot attest to the accuracy of this information. Use of a term in this book should not be regarded as
affecting the validity of any trademark or service mark.
Acknowledgments
Putting this book together took lots of help from many talented people. Although I can't list them all, I want to take a
moment to single out a few of the individuals who made this work possible.
First, I want to thank Jefferson Schuler and Bill Zembrodt of Pioneer Solutions. They accepted my challenge to build a
simple TAPI OCX tool that would allow Visual Basic programmers virtually the same access to Microsoft's Telephony
API services as C++ programmers. The result is the TAPILINE.OCX that is included on the CD-ROM that
accompanies this book. They spent several long days and late nights developing this handy tool and I thank them for all
their work and assistance.
Next, I must thank all those in cyberspace who answered my queries about telephony, speech systems, and electronic
mail. Many of the concepts that appear in this book were hashed out in extensive messages over the Internet, and I thank
all those who assisted me in my efforts. I could name many who helped, but I will refrain from doing so lest they be
blamed for any of my mistakes within these pages.
I also want to thank the people at Sams Publishing. It takes a great number of talented individuals to get a book from the
idea stage to the store shelves, and I consider it a privilege to be able to work with the folks at Sams. Completing this
book took more time and effort than any of us originally suspected and more than once it seemed like the book would
never be done. I am especially indebted to Sharon Cox for her continued help and support. I doubt this book would be in
your hands today were it not for her assistance.
Finally, I need to acknowledge the special contributions made by my family. Without their support, patience, and
understanding, I could not have completed this book. (And now that I have completed it, I have a long list of promises
that I must live up to!)
About the Author
Mike Amundsen works as an IS consulting and training specialist for Design-Synergy Corporation, a consulting and
project management firm specializing in information technology services. He has earned Microsoft certifications for
Windows operating systems, Visual Basic, SQL Server, and Microsoft Exchange Server. Mike's work takes him to
various locations in the U.S. and Europe where he teaches Windows programming and helps companies develop and
manage Windows-based client/server solutions.
He is co-author of Teach Yourself Database Programming with Visual Basic 4 in 21 Days, published by Sams, and was a
contributing author for Visual Basic 4 Unleashed and Visual Basic 4 Developer's Guide from Sams Publishing. Mike is
the contributing editor for Cobb's "Inside Visual Basic for Windows" newsletter, and his work has been published in
"Visual Basic Programmer's Journal" magazine, "VB Tech" magazine, and "Access Developer's Journal."
When he's not busy writing or traveling to client sites, Mike spends time with his family at his home in Kentucky. You
may write to Mike at his CompuServe address 102461,1267, at [email protected] on the Internet, or you
can visit his Web site at www.iac.net/~mamund/.
As a reader, you are the most important critic and commentator of our books. We value your opinion and want to know
what we're doing right, what we could do better, what areas you'd like to see us publish in, and any other words of
wisdom you're willing to pass our way. You can help us make strong books that meet your needs and give you the
computer guidance you require.
Do you have access to CompuServe or the World Wide Web? Then check out our CompuServe forum by typing GO
SAMS at any prompt. If you prefer the World Wide Web, check out our site at http://www.mcp.com.
Note
If you have a technical question about this book, call the technical support
line at (800) 571-5840, ext. 3668.
As the team leader of the group that created this book, I welcome your comments. You can fax, e-mail, or write me
directly to let me know what you did or didn't like about this book-as well as what we can do to make our books
stronger. Here's the information:
FAX: 317/581-4669
E-mail: [email protected]
Mail: Greg Wiegand
Comments Department
Sams Publishing
201 W. 103rd Street
Indianapolis, IN 46290
Introduction to MAPI, SAPI, and TAPI Developer's Guide
This book covers the three most exciting programming services available on the Microsoft Windows platform-messaging
(MAPI), speech (SAPI), and telephony (TAPI). Each of these APIs provides a specialized set of services that expand the
reach of the Windows operating system in a way that makes it easier to write programs that work without having to deal
with the differences between hardware provided from third parties.
The addition of these services as part of the basic operating system not only is a boon to programmers-it is of great
interest to users, too. Computers that can handle messages and telephones, and that can generate and understand simple
speech, are computers that, ultimately, are easier to use. Learning how you add these vital features to your applications
will give your software a greater reach and appeal that can make a real difference to your target audience.
● Part I-Introduction covers some preliminary issues regarding the Windows Open Services Architecture
(WOSA) upon which all three of the API sets are based.
● Part II-The Messaging API (MAPI) contains chapters that describe the MAPI service model, review existing
client and server software that implements the MAPI model, and show you how to use common developer tools
for building MAPI-compliant applications. There are also several chapters devoted to creating commonly used
MAPI-based programs, including e-mail clients, a broadcast mailing list manager, an e-mail-based discussion
forum tool, and an e-mail agent. You'll also learn how to use the Microsoft Exchange Forms designer and
discover how you can use C++ to create built-in extensions to the Windows Messaging client interface.
● Part III-The Speech API (SAPI) covers the Microsoft Voice product available for Windows 95. You'll learn
the details of the API model and how you can use it to create applications that use Text-to-Speech (TTS) and
Speech Recognition (SR) engines to add a voice to your pc applications. You'll use both C++ and Visual Basic
to build programs that respond to voice commands and read printed text back to users.
● Part IV-The Telephony API (TAPI) outlines the API set that allows Windows programmers to add inbound
and outbound telephony features to their applications. You'll learn about the telephony object model, and how
to build simple dialing applications and basic inbound call handlers. Along the way you'll learn how to select
telephony hardware and third-party TAPI development tools that will make it easier to build and maintain TAPI-
compliant applications.
● Part V-Creating Integrated Applications covers design issues you need to keep in mind when designing
Windows applications that combine messaging, telephony, and speech services. You'll learn how to build a
FaxBack service using MAPI and TAPI; an integrated voice response system that uses TAPI to allow users to
call in and request data from the computer and have the results spoken over the phone; and an application that
combines all three extension services to create an integrated voice and telephony application that uses voice
commands to place outbound telephone calls.
● Part VI-appendixes contains lists of third-party vendors for each of the three API sets and pointers to printed
and online documentation sources, along with a handful of e-mail and Web addresses that you can use to keep
current on these three technologies.
I encourage you to contact me via the Internet or through my Web site. I hope you enjoy this book, and I look forward to
hearing from you soon.
Mike Amundsen
[email protected]
www.iac.net/~mamund/
Chapter 1
CONTENTS
This developer's guide is designed to show you how to design, develop, and deploy applications that use messaging,
telephony, and speech services available within the Windows 95 operating system. The primary focus is on developing
client-side applications. Several chapters in this book cover the server-side aspects of these APIs, too. However, the
emphasis is on the client or desktop.
Note
The primary focus of this book is Windows 95, and all examples are
therefore in 32 bits. The same examples will work for Windows NT. The
ideas can be applied to 16-bit Win31, but no 16-bit examples are given in
this book.
One book cannot begin to cover all the possible development tools and API sets that provide message, telephony, and
speech services for desktop pcs. The approach taken here is to concentrate on the Microsoft API sets. This offers several
advantages: First, by using all Microsoft API models, the programmer gets to work with a consistent set of interfaces
that work well together. Second, there is no denying that Microsoft's presence in the marketplace adds strength to any
service model they develop. The time you invest in learning a set of API calls to provide advanced Windows services is
usually time well spent. Using Microsoft API models assures you that your knowledge will not be useless in a year or so
when some other API model is abandoned due to lack of use. And third, the Microsoft approach to service models is
designed to allow third-party vendors to contribute to the growth and development of the service model. This open
approach means you're really learning how to create programs that work with a variety of hardware/software
combinations and not tying your efforts to a single hardware or software system.
The messaging system explored in this book is the Microsoft Messaging API (MAPI). The MAPI system is one of the
most widely used message models available for the pc environment. While there are other message models in use today,
they are not covered here just because one book can't cover everything. If you are familiar with other message models,
your knowledge will help you gain a greater understanding of the MAPI system.
The telephony model covered here is the Microsoft Telephony API (TAPI). Just as with message services, there are
competing telephony service models, too. The primary advantage of TAPI to the programmer is that Microsoft has
committed to providing the TAPI model as part of the basic operating system for all future versions of Windows. For
example, TAPI is shipped as part of every Windows 95 operating system. Version 4.0 of Windows NT is also designed
to contain TAPI services as a fundamental part of the operating system.
Another major advantage of the TAPI model is that it is designed to work with multiple hardware products.
Programmers who use TAPI can be assured that their programs will work the same from one installation to the next as
long as TAPI-compliant hardware is used at all locations.
The speech service discussed here is Microsoft's Speech API (SAPI). There are several vendor-specific speech APIs. As
in the TAPI model, the real advantage of Microsoft's SAPI is that it is designed to support multiple third-party vendor
products. By writing to the SAPI model, you can potentially increase the reach of your speech-enabled software to all
SAPI-compliant hardware.
Some of the examples in this book also use the Microsoft Multimedia Communications Interface (MCI) to add audio and
video services. This is a well-established interface that is supported by almost all existing audio and video hardware.
The programming examples in this book move from simple, high-level examples and progress to more complex, full-
featured applications. Each section of the book has four basic parts:
● General theory
● Creating simple service-aware applications
● Building full-featured service implementation examples
● Designing applications that use the service in unique ways
Each section starts with the general theory of the API service. This includes coverage of the general design of the service
model and its objects, methods, and properties. You'll also get information about the various developer tools available
for building programs that use the target service.
You'll then learn how to create service-aware applications. This usually involves adding the target service to existing
applications, such as adding Send, Dial, or Speak buttons to a form. Service-aware applications use the target service
as an added feature instead of as a basic part of the program. You'll see how you can add service features using high-
level code routines.
The next level of programming examples shows you how to build applications that take advantage of the target service
as a basic part of the program design. Examples would be an e-mail message reader, an online address book that can dial
the selected address at the push of a button, or a program that allows users to drag and drop text documents onto a palette
and then reads a selected document aloud.
Lastly, you'll learn how to create applications that use the service in unique ways. For example, you could use the
message service to send data between two programs running on different machines on the same network, or use TAPI
services to create an answering machine application.
The final section of the book contains examples of applications that provide integrated services: using MAPI and TAPI
to build a dial-up FAX-back application; building a program that allows users to dial in, request information from a
database, and hear the results spoken to them over the phone; and creating a single application that combines messaging,
telephony, and speech into a single voice-mail system.
While the examples in this book don't cover every possible use of the target APIs, you'll find enough examples here to
give you the techniques and skills you'll need to build your own Windows applications to exploit the features of the
MAPI, TAPI, and SAPI services.
Development Tools
In the past, if you wanted to access advanced Windows services like MAPI, SAPI, and TAPI, you had to use C or C++
developer tools. But now, with the introduction of OLE libraries and the Microsoft OCX add-in control specification,
Microsoft has made it possible to access these advanced services from high-level developer tools like Visual Basic 4.0
and Microsoft FoxPro. You can even complete a number of the programming examples included in this book using the
VBA-compatible Microsoft Office tools like Excel, Access, Word, and others.
Most of the programming examples presented in this book are done in the 32-bit version of Microsoft Visual Basic 4.0
Professional Edition. Several examples are done using Microsoft's Excel 95 and Microsoft Access 95. However, a few of
the services are only available via C++ programming. You'll therefore see some short programming examples here using
Microsoft's Visual C++ 4.0. If you do not own a copy of Visual C++, you can still get a lot out of the C++ examples
simply by reading them to get the general concepts. None of the major projects in this book require coding in C++. In the
cases where C++ code is needed to gain access to a specific feature in the Windows service, you'll find compiled OLE
libraries and/or OCX tools included on the accompanying CD-ROM. You can use these compiled tools as part of your
high-level language projects.
All of the programming concepts described here are applicable to non-Microsoft programming environments, too. If you
are using products such as Borland's Delphi, dBASE, Borland C++, and so on, you can still get a lot out of this book.
You'll need to re-create the detail of the code examples in code usable in your programming environment, but the
Windows API calls will be exactly the same.
The programming examples in this book cover a wide range of hardware and software requirements, and it's no small
matter to equip your workstation with all the tools necessary to access all the Windows services described within these
pages. The following list summarizes the tools used in developing the programs presented here:
● Windows 95 operating system-Most of the examples require Windows 95. Some of the examples will run under
Windows 3.1 and most will run without problems under Windows NT (WinNT). However, all of the
programming examples in this book were developed under Windows 95. You'll avoid lots of difficulty by
sticking with Windows 95.
● Messaging API tools-MAPI services are accessed via the MAPI OCX controls, the OLE Message Library, and
the MAPI 1.0 API set. The MAPI OCXs ship with the Professional Edition of Visual Basic 4.0. The OLE
Message Library and the MAPI 1.0 API developer tools can be found on the Microsoft Developer's Network
(MSDN) Level II CD-ROMs. You'll need access to MSDN CD-ROMs to complete the advanced examples in
this book.
● Telephony API tools-The examples in this book were written using TAPI v1.4 for Windows 95. The v1.4 run-
time files are shipped as part of the Windows 95 operating system. TAPI services are accessed via a custom
OCX that comes on the CD-ROM shipped with this book and via calls directly through the API set. TAPI
developer tools are found on the MSDN Professional Level CD-ROMs, too. It is important to note that all the
examples in this book were developed as 32-bit applications for Windows 95. There is a 16-bit version of TAPI
(v1.3), and a new version of TAPI (v2.0) for WinNT will be released with NT v4.0. To keep frustration to a
minimum, stick with Win95 and TAPI 1.4.
● Speech API tools-The release version of SAPI developer tools and run-time modules are available from
Microsoft and are included on the CD-ROM that ships with this book. However, a major piece of the SAPI kit
is not included automatically as part of the SAPI developer kit. You'll need a text-to-speech engine supplied by
a third-party vendor in order to run the SAPI examples in this book. Check the accompanying CD-ROM for
demo versions of Text-to-Speech (TTS) engines. You'll also find a list of vendors of SAPI tools in appendix B,
"SAPI Resources."
● Microsoft Exchange E-Mail-Almost all the examples in this book that involve e-mail clients were created using
the Microsoft Exchange client for Windows 95. Some were created using the Microsoft Exchange Server or
Microsoft Mail Server clients. MAPI services are pretty much the same regardless of the client installed on your
workstation. Where the differences are important, they are noted in the text of the book.
● Sound cards, speakers, and microphones-Some of the examples here require the use of a pc audio system. Just
about any WAV-compatible audio card will work fine. Some examples use voice input and playback. You can
accomplish this with an attached microphone and speakers. In some cases, you can even use an attached
telephone handset, too.
● Data modems-You'll need at least a basic data/fax modem to run the examples in this book. Both the TAPI and
the MAPI examples require a data modem. For some of the TAPI examples, you can perform all the functions
using a simple data modem. For others, you'll need a data modem that supports the Unimodem/V
communications driver. Not all modems support Unimodem/V even though they offer voice-mail or telephony
features. Consult the appendix at the back of the book and the accompanying CD-ROM for a list of vendors
who offer data modems that support TAPI and the Unimodem/V standard.
● Telephony cards-While you can get through almost all the TAPI examples in this book without a telephony card
in your workstation, you'll get a lot more out of the TAPI section if you have access to one. Telephony cards
provide a much more advanced set of telephony features than do TAPI-compliant data modems. The CD-ROM
that comes with this book contains some demo tools that can be used to mimic the presence of a telephony card.
These demo tools can be used during development and testing, but they will not work in a production setting.
Consult appendix C, "TAPI Resources," and the CD-ROM for information on third-party developers who offer
full-featured TAPI-compliant telephony hardware. When shopping for telephony cards, be sure to confirm that
they are TAPI-compliant and that there are TAPI drivers (service providers) available for your telephony card.
● Access to live phone service-You'll need access to a live phone line to run most of the programs in this book.
All the examples will work with a simple analog phone line like the line available to most U.S. households. The
nature of the TAPI services makes it very easy to use digital lines such as T1 and ISDN to run these examples,
too. However, if you use digital lines, be sure your hardware (data modem and/or telephony card) is compatible
with the type of phone service you're using.
Even though this book covers a lot of territory, it leaves a lot out, too. The main focus of this book is the client desktop.
However, there's another set of APIs designed for building server-side applications for Windows. Microsoft provides
developer kits for the creation of MAPI message servers like transport providers, address books, and message storage
systems. Every TAPI client depends on a server-side interface that talks directly to the vendor hardware to translate the
requests from the client into something the hardware understands. Microsoft publishes the Telephony Service Provider
Interface (TSPI) as a set of API calls for handling the server-side aspects of Windows telephony. Finally, the Speech API
is designed to allow third-party vendors to create separate text-to-speech and speech recognition engines that work
within the SAPI system.
Covering the details of each of these server-side models could fill an entire book. For our purposes, you'll learn the
general facts about how the clients and servers relate to each other, but you'll need to look elsewhere if you want to learn
how to build server-side components.
It is also important to keep in mind that all the material here was built for the Windows 95 platform. Even though many
of the examples will run on other Windows platforms, not much will be said about Windows 3.1 or even Windows NT.
This is mainly to keep the book clear of confusing exceptions and special notations for cases where the platforms behave
in different ways. If you're unlucky enough to have the responsibility of deploying advanced Windows services on
multiple platforms, you'll need to supplement this text with copious experimenting and tweaking.
Since this book is divided into very clear sections, you can use it in a number of ways:
● Start from the beginning-The chapters of the book are arranged to start with relatively simple issues and
progress through more complex topics toward the end of the book. If you're new to programming with WOSA
and APIs, you'll get the most out of the book by following along in chapter order.
● Focus on a target service-If you have a good understanding of WOSA and the use of Windows services, you
can jump right into the API sections that interest you most. The three service sections (MAPI, SAPI, and TAPI)
are each self-contained. You can read these sections in any order without missing any vital material.
● Focus on integrating services-If you already know one or more of the APIs and are mainly interested in
building advanced integration applications, you can skip the API sections you have had previous experience
with and move directly to the section on building integrated applications. If you take this approach, you may
run into areas of the book that refer to previous programming examples or concepts discussed in previous
sections of the book. Be prepared to do a bit of skipping around at times to follow some of these threads back to
their source. In this way, you can use this book as more of a reference guide than a tutorial.
No matter how you use this book, by the time you complete the examples and absorb the basic concepts explained here,
you'll have a solid understanding of some of the most advanced Windows extension services available.
CONTENTS
● What Is WOSA?
● The WOSA Model
❍ The Client API Makes Requests
● WOSA Services
❍ Common Application Services
❍ Communication Services
● Benefits of WOSA
❍ Isolated Development
❍ Multivendor Support
❍ Upgrade Protection
● Summary
Before we jump into the details of the three API sets covered in this book, it is a good idea to spend some time reviewing
the overall architecture upon which these APIs are built. Although these API sets are only slightly related in their
function, they are all closely related in their construction and implementation. It is the construction and implementation
of the APIs that is the topic of this chapter.
All of the API sets covered in this book are part of the Windows Open Services Architecture (WOSA). This chapter
offers a brief overview of the WOSA model and describes how it works and the benefits of the WOSA model for
developers. Once you understand the general notions behind the creation and deployment of API services via the WOSA
model, you will also have a good understanding of how to build well-designed end-user applications that use WOSA-
based API services. The WOSA model APIs offer clear benefits to developers who understand the model. Those who
fail to grasp the basic theories behind WOSA may end up using the APIs incorrectly, thus ruining their chances of taking
advantage of the real benefits of the WOSA model.
What Is WOSA?
The Windows Open Services Architecture was developed by Microsoft to "...provide a single, open-ended interface to
enterprise computing environments." The concept of WOSA is to design a way to access extended services from the
Windows operating system that require having only a minimum amount of information about the services. For example,
the MAPI (Message API) model is designed to allow programmers to develop applications that use the message services
without having to understand the complexities of the hardware and software routines that implement messaging on
various Windows platforms. The same is true for the Speech (SAPI) and Telephony (TAPI) services we will discuss in
this book.
The WOSA model goes beyond the idea of exposing services in a uniform way across Windows operating systems.
WOSA is also designed to work in a mixed operating system environment. For example, the Microsoft Rpc (Remote
Procedure Call) interface is a WOSA service that is designed to work with the Open Software Foundation's DCE
(Distributed Computing Environment) Rpc model. The design of Microsoft Rpc allows programmers to design software
that will safely interface with any product that uses the DCE model, regardless of the operating system with which the
software must interact.
In order to attain this flexibility, the WOSA model defines two distinct interfaces-the Client API and the Server SPI.
These interfaces are linked by a single interface module that can talk to both API and SPI applications. As a result, all
client applications need to do is conform to the API rules and then to the universal interface. All server applications need
to do is conform to the SPI rules and then to the universal interface. No matter what changes are made to the client or
server applications, both software modules (client and server) will be compatible as long as they both continue to
conform to the API/SPI model and use the universal interface.
The next two sections of this chapter outline the WOSA model in detail and give several examples of WOSA services
currently available.
The WOSA model consists of three distinct pieces. Each of these pieces plays an important, and independent, role in
providing programming services to your applications. The three WOSA components are
● The Client API-the application programming interface used by the program requesting the service.
● The Server SPI-the service provider interface used by the program that provides the extended service (for
example, e-mail, telephony, speech services, and so on).
● The API/SPI Interface-the single module that links the API and SPI calls. This is usually implemented as a
separate DLL in the Windows environment.
Figure 2.1 shows the relationship between the three WOSA components.
Each of the components has an important job to do. Even though they perform their tasks independently, the components
work together to complete the service interface. This is the key to the success of the WOSA model-distinct, independent
roles that together provide the whole interface.
The Client API is the interface for the application requesting the service. API sets are usually implemented at the
Windows desktop. The Message API (MAPI) is a good example of a WOSA client API. Each client API defines a stable
set of routines for accessing services from the back-end service provider. For example, the operations of logging into an
e-mail server, creating an e-mail message, addressing it, and sending it to another e-mail client are all defined in the
MAPI set. These services are requested by the client. The actual services are provided by the server-side application.
The key point is that the client application interface allows programs to request services from the server-side service
provider but does not allow the client software to access the underlying services directly. In fact, the request is not even
sent directly to the server-side application. It is sent to the DLL interface that sits between the API and SPI (see Figure
2.2).
The Server SPI (Service Provider Interface) accepts requests for services and acts upon those requests. The SPI is not
designed to interface directly with a client application. Most SPI programs are implemented on network servers or as
independent services running on desktop pcs. Users rarely interact with these service providers, except through the client
API requests.
A good example of an SPI implementation is the Open Database Connectivity (ODBC) interface. Even though
programmers use API calls (or some other method of requesting ODBC services) in their programs, these calls merely
request services from an external program. ODBC calls to Microsoft's SQL Server, for example, are simply requests to
SQL Server to perform certain database operations and to return the results to the client application. When making an
ODBC request to SQL Server, the client actually performs very few (if any) database operations. It is SQL Server that
performs the real database work.
As mentioned earlier, service providers rarely display interfaces directly to client applications. Their job is to respond to
requests. These requests do not even come directly from the client program. In the WOSA model, all requests come
directly from the interface DLL. The SPI talks only to the interface DLL. Any information that the SPI needs to supply
as a part of the response to the request is sent directly to the interface DLL. It is the DLL's job to send the information on
to the client that made the initial request.
Another important point should be highlighted here. The service provider portion of the WOSA model allows for
multiple clients to request services (see Figure 2.3).
The DLL interface tells the SPI which client is making the request. It is the SPI's responsibility to keep the various
clients straight. SPIs must have the ability to handle multiple requests from the same client and from multiple clients.
Since a key design aspect of WOSA is the isolation of the client API and the server SPI, a single interface between the
two components is required. This single interface is usually implemented as a Windows dynamic link library (DLL) that
allows programs to link to existing services at run-time instead of at compile time. The advantage of using DLLs is that
programs need not know everything about an interface at compile time. Thus, programmers can upgrade DLL modules
without having to recompile the applications that access the interface.
The primary role of the DLL is to broker the requests of the client API and the responses of the server SPI. The DLL
does not actually perform any real services for the client and makes no requests to the SPI.
Note
Actually, the interface DLL may request basic information from the SPI at
startup about the underlying SPI services, their availability, and other
information that may be needed to support requests from clients.
The interface DLL is the only application in the Windows environment that actually "speaks" both API and SPI. It is the
DLL's job to act as translator between the client and server applications.
In the past (before WOSA), these DLLs were written as translators from the client API directly to a specific back-end
product. In other words, each DLL interface understood how to talk to only one back-end version of the service. For
example, early implementations of the MAPI interface involved different DLLs for each type of MAPI service provider.
If a program needed to talk to a Microsoft MAPI service provider, the MAPI.DLL was used as an interface between the
client and server. If, however, the program needed to talk to another message server [such as Lotus Vendor Independent
Messaging (VIM) or the universal Common Message Calls (CMC) service provider], another DLL had to be used to link
the client request with the back-end provider.
In the WOSA world, interface DLLs can speak to any service provider that understands the SPI call set. This is an
important concept. Now, a single interface DLL can be used for each distinct service. This single DLL is capable of
linking the client application with any vendor's version of the service provider. This is possible because the service
provider speaks SPI rather than some proprietary interface language (see Figure 2.4).
WOSA Services
Microsoft has been championing the WOSA model for several years and promotes three types of WOSA services:
Each type has its own purpose and its own core of services. The following sections describe the WOSA service types
and give examples of services currently available for each.
Common Application Services allow applications to access services provided by more than one vendor. This
implementation of WOSA focuses on providing a uniform interface for all Windows applications while allowing
programmers and/or users to select the vendor that provides the best service option for the requirement. In this way,
Microsoft can encourage multiple (even competing) vendors to provide their own versions of key service components for
the Windows operating system.
By defining a single set of APIs to access the service, all third-party vendors are assured equal access to the Windows
operating environments. Since the interface is stable, vendors can concentrate on building service providers that expose
the services that customers request most often. These vendors can also be confident that, as Windows operating systems
change and evolve, the basic model for service access (the WOSA model) will not change.
The list of Common Application Services available for Windows operating systems is constantly growing and changing.
Here is a list of some of the services provided under the WOSA model:
● License Service Application Program Interface (LSAPI) provides access to software license management
services.
● Messaging Application Program Interface (MAPI) provides access to e-mail and other message services.
● Open Database Connectivity (ODBC) provides access to database services.
● Speech Application Program Interface (SAPI) provides access to speech and speech recognition services.
● Telephony Application Program Interface (TAPI) provides access to telephone services.
Communication Services
Communication Services provide access to network services. This set of WOSA services focuses on gaining uniform
access to the underlying network on which the Windows pc is running. The Communications Services also provide
uniform access to all the network resources exposed by the underlying network. By defining a universal interface
between the pc and the network, Windows applications are able to interact with any network operating system that
conforms to the WOSA model.
The following list shows some examples of WOSA implementations of Communication Services:
● Windows SNA Application Program Interface provides access to IBM SNA services.
● Windows Sockets provide access to network services across multiple protocols, including TCP/IP, IPX/SPX,
and AppleTalk.
● Microsoft Rpc provides access to a common set of remote procedure call services. The Microsoft Rpc set is
compatible with the Open Software Foundation Distributed Computing Environment (DCE) model.
The last category of WOSA services defined by Microsoft is Vertical Market Services. These are sets of API/SPI calls
that define an interface for commonly used resources in a particular vertical market. By defining the interfaces in this
way, Microsoft is able to work with selected vertical markets (banking, health care, and so on) to develop a standard
method for providing the services and functions most commonly used by a market segment. In effect, this allows users
and programmers to invent Windows-based solutions for an entire market segment without having to know the particular
requirements of back-end service provider applications.
As of this writing, Microsoft has defined two Vertical Market Services under the WOSA umbrella:
● WOSA Extensions for Financial Services provide access to common services used in the banking industry.
● WOSA Extensions for Real-Time Market Data provide access to live stock, bond, and commodity tracking data
for Windows applications.
Benefits of WOSA
There are several benefits for both users and programmers in the WOSA model. The three key benefits worth
mentioning here are
● Isolated development
● Multivendor support
● Upgrade protection
The next three sections describe the details of the benefits of the WOSA model as it relates to both client and server
programmers and application users.
Isolated Development
In one way or another, all WOSA benefits are a direct result of the model's ability to separate the details of service
providers from the application running on users' desktops. By keeping the details of hardware and software interface
locked away in the SPI-side, programmers can concentrate on providing a consistent interface to the services, rather than
concerning themselves with the low-level coding needed to supply the actual services.
The isolation of services from user applications has several other benefits. With WOSA services, developers can limit
their investment in understanding the details of a service technology, where appropriate. Those focused on developing
client-side applications can leave the details of server-side development to others. They can concentrate their efforts on
developing quality client-side software knowing that, as long as the service providers maintain WOSA compatibility, the
client software will be able to take advantage of new services as they become available.
Of course, this works the same for developers of server-side software. They can concentrate their efforts on providing
the most efficient and effective means for exposing and supporting requested services and leave the client interface
details to others. Service provider developers are assured equal access to all Windows clients because the WOSA model
ensures that all links to the services are the same, regardless of the client software used.
Multivendor Support
In addition to allowing programmers to focus on the client-side of the equation instead of the server-side, WOSA
implementations provide benefits to application programmers. With a common interface for the service, application
programmers can build software solutions that are independent of vendor-specific implementations. The WOSA model
allows programmers to build programs that interact with any vendor's service implementation as long as that vendor
adheres to the WOSA model.
This is a key benefit for both client-side and provider-side developers. Now service provider vendors can be assured that,
as client-side applications change, the interface to their services will remain the same. At the same time, client-side
developers can be assured that as service providers upgrade their software, client applications need not be rewritten
except to take advantage of new services. This feature allows client-side and service-side development to go forward
independently. The result is greater freedom to advance the technology on both sides of the interface.
Upgrade Protection
Another benefit of WOSA-compliant systems is the protection it provides during service or application upgrades or
platform migrations. Users can more easily plan and implement software and hardware upgrades when the service access
to uniform calls is isolated to a single DLL. Since the WOSA model ensures that service provision and access is
standardized across vendors and platforms, changing software and hardware has a minimal effect on users who access
services from WOSA-compliant applications.
Thus, when users decide to move their primary database services from an IBM VSAM system to a DB2 or SQL Server
environment, the client applications see minimal change as long as the WOSA model was implemented for database
access. This protects users' software investment and allows greater flexibility when selecting client and server software.
At the same time, this approach provides protection for commercial software providers because a single application can
be designed to work with multiple service providers. Developers can focus on creating full-featured applications without
tying their software to a single service provider. As the market grows and changes, and service providers come and go,
client-side applications can remain the same when the WOSA model is used as the route for service access.
Now that you understand the concepts behind the WOSA model, you can use this information in your own development
efforts. For example, when accessing WOSA services from your client applications, isolate those calls in your code. This
will make it easier to modify and enhance your application's WOSA interface in the future. As the services available
change and grow, you'll need only to make changes in a limited set of your code.
Also, when designing your application, plan for the future from the start. Assume that the various program services will
be provided via WOSA-compliant tools-even if they are not currently available as true WOSA components. This
approach will make it much easier to add true WOSA components to your client application once they become available
and will increase the life and flexibility of your software.
The same holds true for back-end service provider developers. If there is a WOSA SPI defined for the services you are
providing, use it. This will make your software client-ready for virtually all Windows desktops. If no WOSA interface is
yet defined for your service, code as if there is one. Limit the code that talks directly to hardware to a single area in your
program. If you are using vendor-specific calls, isolate these, too. This way, when a WOSA model is defined for your
service, you'll have an easier time converting your software to comply with the WOSA model.
As you work through the book, you learn about the specific API calls that are used to access extension services. You'll
see a consistent pattern throughout all three extensions. Each of the extension services is divided into layers. The first
layer provides a simple interface-sometimes as simple as a single function call-to the target service. The second level
provides a more extensive access to a complete feature set. Finally, you'll find a third level of service that allows
sophisticated programmers access to all the nifty little details of the extension service. When you're coding your own
applications, it is a good idea to use this same approach. Where possible, give users a single function or subroutine that
provides access to the extension service. For more advanced applications, create a function library or class object that
encapsulates all the extension service calls. By doing this, you'll make it easier to make modifications to your program
logic without touching the extension routines. It will also be easier to update the extension routines in the future without
damaging your local program logic.
Summary
In this chapter, you learned that the WOSA model was developed by Microsoft to "... provide a single, open-ended
interface to enterprise computing environments." You learned that the WOSA model has three key components:
● The Client API usually resides on the desktop workstation and makes service requests.
● The Server SPI usually resides on a network server and receives and responds to service requests made by
clients.
● The interface DLL acts as a broker between the client API and the server SPI. The API and SPI never talk
directly to each other. They both talk only to the interface DLL.
You learned that there are three types of WOSA implementations. Each of these implementations focuses on a different
aspect of service implementation. The three WOSA types are
● Common Application Services provide common access to system-level services, independent of vendor
implementations. Examples of WOSA Common Application Services are ODBC, MAPI, SAPI, TAPI, and
LSAPI.
● Communication Services provide standard access to network services, independent of the underlying network
available to the workstation. Examples of Communication Services are Windows SNA API, Windows Sockets
API, and the Microsoft Rpc interface.
● Vertical Market Services provide access to common services used in a particular vertical market, such as
banking, health care, and so on. Examples of this type of WOSA service are the WOSA Extensions for
Financial Services and the WOSA Extensions for Real-Time Market Data.
We also covered some of the key benefits of using WOSA-defined services in developing Windows applications. The
benefits mentioned are
● Isolated development-Using WOSA-compliant services isolates access to external services. As these services
change, the impact on your application is limited.
● Multivendor support-WOSA-compliant services are vendor neutral. If your application uses WOSA-defined
service calls, they can be provided by any vendor's service provider if it is also WOSA-compliant.
● Upgrade protection-When you use WOSA components, you can easily plan and implement software and
hardware upgrades because the WOSA model is consistent across platforms and operating systems.
Finally, you learned how you will use the concepts behind the WOSA model in your own software development to
improve compatibility and ensure easy future upgrades.
Chapter 3
What is MAPI
CONTENTS
❍ Consistency
❍ Portability
● Messages
❍ Text Messages
❍ Control Messages
● MAPI Applications
❍ Electronic Mail Clients
❍ Message-Aware Applications
❍ Message-Enabled Applications
● Summary
Before getting into the details of how the Messaging Application Programming Interface (MAPI) works and how to
write MAPI applications, we'll take a moment to review the general architecture of Microsoft's messaging API and how
this set of message services fits into the overall Windows operating system. As you will see a bit later in this chapter,
MAPI is more than a handful of e-mail APIs-it is a defined set of message services available to all programs that run in
the Windows operating environment.
We'll also discuss the various kinds of applications and message types commonly used under MAPI services. In this
chapter, you'll learn about the three general types of MAPI messages: text messages, formatted documents and binary
files, and control messages. Each of these message types has a distinct set of properties and uses within the MAPI
framework. This chapter describes each of the message types and shows how you can use them within the MAPI
architecture.
There are also three common types of MAPI applications: electronic mail clients, message-aware applications, and
message-enabled applications. Each of these application types is defined and illustrated in this chapter. You'll also learn
the relative strengths of each type of MAPI application.
The MAPI service set is more than a set of API commands and functions that you can use to send e-mail from point to
point. The MAPI interface is actually a carefully defined set of messaging services available to all Windows programs.
This pre-defined set has three key attributes:
● Flexibility
● Consistency
● Portability
Because the MAPI service set contains these three characteristics, it has become the de facto messaging interface
standard for Windows applications.
Access to MAPI services is the same for all versions of the Windows operating system. But even though your Windows
programs use the same methods for accessing MAPI services, MAPI services can vary from system to system. Also,
MAPI architecture allows software designers to create their own service providers (SPs) to support the MAPI service set.
These services are also available within all existing flavors of the Windows operating system. Even more important, the
methods of access to these message services is the same, regardless of the version of Windows you are working with.
This means that programs using MAPI services that were written under Windows 3.1 will still be able to access those
same MAPI services under Windows 95.
Flexibility
Probably the most important aspect of the MAPI service architecture is its flexibility. Microsoft has implemented MAPI
within the Windows Open Systems Architecture (WOSA). This architecture is designed to allow customization at both
the client (user) side and the server (provider) side. In other words, you can use MAPI not only to create your own end-
user software to read, write, create, and send messages, but also to construct custom server-side software to store and
transport those same messages. As part of the WOSA model, MAPI services are implemented in a tiered format (see
Figure 3.1).
The first layer is the client layer. This is what the end-user most often sees. At this level a set of well-defined services are
available. These services are accessed when the client layer makes a service request to the second layer-the MAPI DLL.
The MAPI DLL takes the service request from the client and forwards it on to the third layer in the tier-the service
provider. The service provider is responsible for fulfilling the client request and sending the results of that request back
to the DLL where it is then forwarded to the client that made the initial request. Throughout the process, the DLL layer
acts as a broker between the client side and the server side.
The primary advantage of this layered implementation is the ease with which users can interchange client and server
components. Since the only constant required in the mix is the DLL layer, any client can be matched with any server
component to provide a working message service. It is very common to switch client-side components in a messaging
service. Each e-mail reader is a MAPI client application. Any application that sports a send button is actually a MAPI
client. Any specialized program written to manipulate messages at the end-user level is a MAPI client.
While interchanging MAPI clients is rather commonplace, interchanging MAPI service providers is not. In a network
environment, a single service provider will usually be designated as the default provider of MAPI services. It is no
longer rare to have several MAPI service providers available at the same time, however. In fact, the Microsoft Mail
Exchange client that ships with Windows 95 is specifically designed to be able to access more than one service provider.
It is possible to use the Windows Exchange client to access messages via Microsoft Mail Server, Microsoft FAX, or
through the Microsoft Network (MSN). You can even install third-party service providers into the Exchange client (such
as the one provided by CompuServe) to access messages stored in other mail systems (see Figure 3.2).
Consistency
The MAPI service set contains a set of services that encompasses all the basic messaging tasks:
● Message service logon and logoff
● Reading, creating, and deleting text messages
● Adding and deleting message binary file attachments
● Addressing and transporting the completed messages
The exact behavior and properties of each of these services are defined as part of MAPI. All vendors who supply a
MAPI-compliant set of tools provide these services in the exact same manner. This way, any program that uses MAPI
services can be assured that there are no special API variations to deal with when moving from one vendor's MAPI
product to another. This means the programs you write today using your current implementation of MAPI services will
function under other implementations of the MAPI service set (see Figure 3.3).
Portability
This leads to the second strength of Microsoft's MAPI service set-portability. Microsoft supports MAPI services on all
versions of its Windows operating systems. If you write a program for the Windows 3.1 version of MAPI services, that
same program can still access the MAPI services under any other version of Windows that supports your executable
program. This is a key issue when you consider how many versions of Windows are currently in use and how quickly
new versions of the operating system are developed and deployed.
Not only will you be able to move your MAPI-related programs to various Windows platforms, you can also allow
programs to access MAPI services from more than one platform at once. In other words, users of more than one version
of Windows can all be accessing MAPI services from a central location at the same time (see Figure 3.4).
Microsoft has announced plans to move several of its service sets (MAPI included) beyond the Windows operating
environment, too. As this happens, Microsoft has pledged that the same set of functions and routines used under the
Windows environment will be available in other operating systems.
Messages
The primary role of the MAPI service is to transport and store messages. This section identifies three common message
types supported by MAPI services:
● Text messages
● Formatted documents or binary files
● Control messages
The most basic message form is the text message, commonly thought of as e-mail. Most electronic message systems also
support the second type of message-formatted documents or binary files. These are usually included as attachments to a
text message.
The third message type is a control message. Control messages are usually used by the operating system to pass vital
information such as system faults, potential failure conditions, or some other type of status information. Control
messages can also be passed between programs in order to implement a level of distributed processing in a computer
network.
The text message is the most common MAPI message. In fact, all MAPI messages have a default text message
component. A text message contains the letters and words composed by users to communicate with other message
system users.
All MAPI service providers must supply a simple text message editor as part of their MAPI implementation. All MAPI
message providers support plain ASCII text characters as a message body. Many also support rich-text messages that
contain formatting characters such as font and color. The Microsoft Mail client supplied for Windows 3.11 and Windows
for Workgroups supports plain ASCII text. The Microsoft Mail Exchange client supplied for Windows 95 supports rich-
text formatting.
The second MAPI message type is the formatted document or binary file, which is usually a file containing non-printable
characters such as a spreadsheet, a word-processing file, graphics, or even an executable program. Binary files are
supported by MAPI services as attachments to text messages. The MAPI service set allows multiple attachments to a
single text message. This means you can send several binary files to the same e-mail address using a single message
body.
All MAPI service providers support the use of binary attachments to a message body. However, the transport of binary
attachments across multiple message servers may not be supported. For example, if you compose a message that
contains attached binary files, address it to an associate at a distant location, and attempt to send the message using a
service provider that supports only Simple Mail Transfer Protocol (SMTP) format, your attached binary files will not be
successfully transported to the recipient.
Control Messages
The third type of MAPI message is the control message. Control messages are usually used by the operating system to
deliver system status information, such as a component failure or other system-related problem. These messages are
usually addressed directly to the system administrator.
Control messages can also be used to pass data or other control information between programs. Control messages of this
type can contain requests for information that is to be collected by one program and returned to another for further
processing. Or the control message can contain actual data to be manipulated by another program. Since MAPI services
can stretch across the LAN or across the globe, control messages can be passed to systems halfway around the globe as
easily as to systems across the room.
It is possible to designate one or more workstations on a network as batch job computers. These machines wait for
control messages that direct them to perform time-consuming tasks, such as extended database searches or generating
long reports, thus freeing up users' workstations for more immediate business. Once the task is complete, the batch job
machine can send a completion notice via e-mail to the user who sent the original request. While it is true that OLE
Automation servers are beginning to replace batch job computers that are controlled by MAPI messages, MAPI services
are still a very powerful alternative.
MAPI Applications
Just as there are three types of MAPI messages, there are three general types of MAPI applications:
Electronic mail (e-mail) clients are the most common form of MAPI application. An e-mail client allows end-users direct
access to the MAPI services supported by the back-end service provider. Figure 3.5 shows the Microsoft Exchange
electronic mail client.
Electronic mail clients can also provide additional services to make it easy to manipulate, store, and retrieve text
messages and binary file attachments. Electronic mail clients may also have additional features for addressing and
transporting messages, including the use of defined mailing lists and the capability to address messages as cc (courtesy
copies) or Bcc (blind courtesy copies).
Message-Aware Applications
Message-aware applications are non-MAPI programs that allow users access to MAPI services. Typically, this access is
implemented through the addition of a send option in a menu or button bar. Figure 3.6 shows the Microsoft Word 95
main menu with the Send menu item highlighted.
Message-aware applications usually treat e-mail services just like any other storage or output location, such as disk
drives, printers, or modems. In these cases, the ability to send the standard output as an electronic mail message is an
added feature for the application. As MAPI services become a standard part of the Windows operating system, message-
aware applications will become the norm instead of the exception.
Message-Enabled Applications
The last category of MAPI applications is message-enabled applications. Message-enabled applications are programs
that offer message services as a fundamental feature. While message-aware applications provide message services as an
additional feature and can operate well without them, message-enabled applications are specifically designed to use
message services and most will not run properly unless message services are available on the workstation.
● Computerized service dispatch-Customer calls are handled by representatives at pc workstations where they fill
out data entry forms outlining the repair needs and the location of the service call. When the data entry is
complete, the program analyzes the information and, based on the parts needed and the service location, routes
an instant electronic message containing the service request and a list of needed parts to the repair office nearest
to the customer.
● Online software registration-When a user installs a new software package, part of the installation process
includes an online registration form that already contains the unique software registration code along with a
data entry form for the user to complete. Once the form is completed, the results are placed in the user's e-mail
outbox to be sent directly to the software company to confirm the user's software registration.
● End-user support services-When network end-users have a question about a software package or need to report
a problem with their workstation or the network, they call up a data entry form prompting them to state the
nature of the problem. This program will also automatically load the user's system control files and add them as
attachments to the incident report. Once the form is complete, it is sent (along with the attachments) to the
appropriate network administrator for prompt action.
It is important to note that, in some cases, users of message-enabled applications may not even be aware that they are
using the e-mail system as part of their application. MAPI services define properties and methods for logging users in
and out of the message server without using on-screen prompts. MAPI also provides options for addressing and sending
messages without the use of on-screen prompts or user confirmation. By using these features of MAPI services, you can
design a program that starts a message session, reads mail, composes replies, addresses the new mail, and sends it to the
addressee without ever asking the user for input.
There are two more types of message-enabled applications that deserve comment here. These two application types are
Electronic forms applications display a data entry screen that contains one or more data fields for the user to complete.
These data fields act as full-fledged windows controls and can support all the events normally supported by Windows
data entry forms. Once the form is completed, the data, along with additional control information, is sent to the addressee
through MAPI services. When the addressee opens the new mail, the same formatted data entry form appears with the
fields filled in (see Figure 3.7).
The message-driven application looks for data contained in a message and acts based on the data it finds. Message-
driven applications can use any aspect of the message as control information for taking action. Message-driven
applications can inspect the message body or subject line for important words or phrases, check the sender's name or the
date and time the message was sent, or even scan attachments for important data. These applications can then use the
data to forward messages to another person automatically, to set alerts to notify the user of important messages, or to
start other programs or processes at the workstation.
● Message filtering agent-Users can enter a list of important keywords into a list box. This list is used to scan all
incoming text messages automatically. If the message contains one or more of the keywords, the user is notified
immediately that an important message has arrived. Users could also set values to scan for the message sender's
name. For example, if the message came from the user's boss, an alert could sound to warn the user that an
urgent message has arrived. The same technique can be used to automatically forward specific messages when
the user is away on a trip.
● File transfer database update application-This program could be used by outlying sales offices to update a
central database automatically. Each day the remote offices would enter sales figures in a database, then attach
the binary database file to an e-mail message, and send the message to the corporate headquarters. There, a
special workstation (logged in as the addressee for all sales database updates) would receive the message and
automatically run a program that takes the binary database file and merges it into the central database. This
same program could then provide summary data back to the remote offices to keep them up to date on their
progress.
● Electronic database search tool-Many companies have large libraries of information on clients, products,
company regulations, policies and procedures, and so on. Often users would like to run a search of the
information but don't have time to physically visit the library and pour through thousands of pages in search of
related items. If the information is kept in online databases, users at any location around the world could
formulate a set of search criteria to apply against the databases and then submit these queries, via MAPI
messages, to one or more workstations dedicated to performing searches. After the search is completed, the
resulting data set could be returned to the user who requested the data.
Filtering agents, remote update routines, and long-distance search tools are all examples of how MAPI services can be
used to extend the reach of the local workstation to resources at far-away locations. The Windows MAPI services
provide excellent tools for building programs that enable users to collect and/or disseminate data over long distances or
to multiple locations. The next several chapters will explore the details of MAPI architecture, teach you how to
incorporate MAPI services into your programs, and show you examples of real-life programs that take advantage of
Windows MAPI services.
Summary
In this chapter, you learned that the Messaging Application Programming Interface (MAPI) is a part of the Windows
Open Systems Architecture (WOSA) model. MAPI is designed to offer three key benefits over other messaging services:
● Flexibility-Since MAPI is implemented within the WOSA model, there are three distinct layers:
● The client layer (the end-user software)
● The MAPI DLL layer (the MAPI service broker)
● The service layer (the actual message service provider)
● Because the MAPI DLL layer acts as the service request broker between the MAPI client and the MAPI server,
you can interchange servers and clients without having to modify your MAPI software modules.
● Consistency-MAPI services and the methods for accessing them are the same no matter what vendor you are
using to provide the message services.
● Portability-MAPI services are available on all supported versions of Windows (Win3.11, WFW, WinNT, and
Win95). As Microsoft moves WOSA services to non-Windows platforms, MAPI services will be available
within those operating systems, too.
● Text messages-These are the standard plain ASCII text messages commonly known as e-mail. Some MAPI
service providers support the use of rich-text formatted messages (for example, the Microsoft Exchange Mail
client).
● Formatted documents and binary files-These are word-processing documents, graphics files, databases, and so
on. MAPI enables you to send these binary files as attachments to the body of a text message.
● Control messages-These are used by operating systems and specialized batch programs to send information
about the operating system, or send commands to tell remote machines how to process attached data or run
special jobs.
Finally, you learned about the various types of MAPI applications. These application types are
● Electronic mail clients-The sole purpose of these programs is to give users direct access to the available MAPI
services (for example, the Microsoft Mail Exchange client that ships with Windows 95).
● Message-aware applications-These are programs that provide MAPI services as an added feature. These
programs usually offer users a send button or menu option. The standard output of the program can then be
routed to another location through MAPI. The Send menu option of Microsoft Word 95 is an example of a
message-aware application.
● Message-enabled applications-These programs offer MAPI services as a basic part of their functionality.
Usually, message-enabled applications will not operate properly unless MAPI services are available to the
workstation. Examples of message-enabled applications include data entry forms that collect data and
automatically route the information to the appropriate e-mail address, sometimes without asking the user for
MAPI logons or addresses.
Now that you know the common types of MAPI messages and applications, it's time to review the details of MAPI
architecture. That is the subject of the next chapter.
Chapter 4
MAPI Architecture
CONTENTS
❍ Storage Folders
❍ Addresses
❍ Message Stores
❍ Address Books
In Chapter 3, "What Is MAPI?," you learned the general outline of the messaging API and how MAPI fits into
Microsoft's Windows Open Systems Architecture (WOSA) scheme. You also learned about the three most common
types of MAPI messages (ASCII text, formatted documents or binary files, and control messages). Lastly, Chapter 3
described the three major categories of MAPI applications (e-mail, message-aware, and message-enabled).
In this chapter, you'll learn about the basic conceptual components of MAPI-the MAPI
Client and the MAPI Server. These two components work together to create, transport, and store messages within the
MAPI system.
Each of these objects is represented slightly differently in the various versions of MAPI implementations you'll learn
about in this book. For example, the MAPI OCX tools that ship with Visual Basic allow only limited access to folders
and address information. The Messaging OLE layer (provided through the MAPI 1.0 SDK) provides increased access to
folders and addresses, but only the full MAPI 1.0 functions allow programmers to add, edit, and delete folders and
addresses at the client level. This chapter will cover all three objects in a general sense. Later chapters will provide
detailed programming examples.
● Message transport
● Message stores
● Addresses books
As you can see, the server side of MAPI is quite similar to the client side (see Figure 4.1).
Where the client is concerned with creating and manipulating messages, the server component is concerned with the
transporting of those same messages. Where the client side is accessing storage folders, the server side is dealing with
message storage, and both client and server must deal with message addresses. However, the MAPI server has the
responsibility of managing the transport, storage, and addressing of messages from any number of client applications.
In addition to maintaining the message base for all local clients, MAPI servers also have the task of moving messages to
and from remote servers and clients. The final section of this chapter talks briefly about a special MAPI component that
handles this task-the MAPI Spooler.
When you complete this chapter, you'll understand the fundamental tasks that must be performed by all MAPI clients
and MAPI servers and the basic objects maintained and manipulated by both client and server applications. Once you
have a grasp of the general operations of a MAPI system, you'll be ready to explore MAPI functions from a Windows
programming perspective in the coming chapters.
The MAPI Client is the application that runs on the user's workstation. This is the application that requests services from
the MAPI Server. As mentioned in the preceding chapter, client applications can be generic e-mail tools such as
Microsoft's Microsoft Mail or Exchange Mail Client for Windows 95. Client applications can also be message-aware
applications like the Microsoft Office Suite of applications. Each of these applications provides access to the message
server via a send menu option or command button. Lastly, message-enabled applications, ones that use MAPI services as
a primary part of their functionality, can be built to meet a specific need. These programs usually hide the MAPI services
behind data entry screens that request message-related information and then format and send messages using the
available message server.
All MAPI clients must, at some level, deal with three basic objects:
Depending on the type of client application, one or more of these MAPI objects may be hidden from the client interface.
However, even though they may not be visible to the application user, all three objects are present as part of the MAPI
architecture. The next three sections describe each of the MAPI client objects and their functions in the MAPI model.
The MAPI system exists in order to move messages from one location to another. Therefore, the heart of the system is
the MAPI message object. All message objects must have two components-a message header and a message body. The
message header contains information used by MAPI to route and track the movement of the message object. The
message body contains the actual text message portion of the message object. Even though every message object must
have a message body, the body can be left blank. In addition to the two required components, message objects can also
have one or more attachments. Attachments can be any valid operating system file such as an ASCII text file, a binary
image, or an executable program.
Note
The item names given in Table 4.1 do not necessarily correspond to a valid
property or variable name in programming code. The actual property names
for each item can vary from one code set to another. Also, the order in
which these properties appear differs greatly for each MAPI
implementation. The chapters following this one focus on different code
sets (CMC API, MAPI Controls, OLE Messaging) and detail the exact
keywords and property names used to access the items described here.
Along with this basic set, additional data items may appear or be available to the programmer. These additional items
add functionality to the MAPI interface, but because they are not part of the core set, you cannot expect them to be
available to you when you write your programs. Table 4.2 contains a list of additional header data items.
Table 4.2. Optional items that may be found in the message header.
Property Name Type Description
Flag that indicates the sender asked for a return
receipt message upon either delivery of the message
DeliveryReceipt Boolean
to the recipient or the reading of the message by the
recipient.
A value that indicates the relative importance of the
Importance Long message. Currently, Microsoft Mail clients recognize
three priorities: High, Medium, and Low.
Flag that indicates the item has been sent to the
Submitted Boolean
recipient.
Sent Boolean Read/write.
Signed Boolean Read/write.
Value that identifies this message as one of a class of
messages. Currently, Microsoft Mail systems
recognize the IPM (Interpersonal Message) type for
Type String sending messages read by persons. Microsoft has
defined the Ipc (Interprocess Communication) type
for use between program processes. Other types can
be defined and used by other programs.
Flag that indicates whether the message has been
Unread Boolean
received and/or read by the recipient.
The message body contains the text data sent to the recipient from the sender. For most systems, this is a pure ASCII text
message. However, some service providers can handle rich-text format message bodies, which allows for additional
information such as font, color, and format codes to be included in the message body (see Figure 4.2).
The availability and support of rich-text message bodies vary between service providers. Some service providers allow
you to create rich-text message bodies but translate the information into simple ASCII upon delivery. For example,
Microsoft Exchange allows users to build rich-text message bodies but translates that message into simple ASCII text
when using the SMTP service provider. All messages received by the Microsoft Mail system are converted into simple
text as well. This behavior ensures that the message will be delivered but may result in surprise or even unreadable
material at the recipient's end (see Figure 4.3).
Figure 4.3 : Receiving a rich-text message that has been changed to simple ASCII.
Other transport providers may transmit the rich-text and allow the receiving message provider to handle the translation to
simple ASCII, if needed. This option allows for the most flexibility but can result in undeliverable messages. For
example, Microsoft Exchange users have the option of sending rich-text messages through the CompuServe message
transport. The CompuServe transport supports rich-text messages. Rich-text messages sent from one Windows
Messaging Client to another by way of the CompuServe transport retain their original layout and look. However,
recipients using something other than Microsoft Exchange may see something different. For example, the WinCIM
client provided by CompuServe treats rich-text messages as binary attachments to a simple ASCII text message.
WinCIM clients would receive the message shown in Figure 4.2 as an attachment to view with Microsoft Word or some
other viewer.
If, however, the CompuServe recipient is defined as an Internet user through the CompuServe address (for example,
[email protected]), the CompuServe message transport reports the message as undeliverable when it is
discovered that the message body contains anything other than simple ASCII text (see Figure 4.4).
Message Attachments
Message attachments are supported by all forms of Microsoft MAPI. A MAPI attachment can be any data file, of any
type (text, binary programs, graphics, and so on). These attachments are sent to the recipient along with the message
header and body. Upon receipt of the message, the recipient can, depending on the features of the message client
software, view, manipulate, and store the attachments on the local workstation. The MAPI system keeps track of
attachments with a set of properties. Table 4.3 lists an example set of attachment properties. The actual properties and
their names can differ between program code sets.
Table 4.3. Example MAPI attachment properties.
Property Name Type Description
Each message object can contain more than one
Index Long
attachment. Attachments are numbered starting with 0.
The name to display in a list box or in the client message
Name String
area (for example, "June Sales Report").
A value that indicates where in the message body the
attachment is to be displayed. Microsoft Mail and
Windows Messaging clients display an icon representing
Position Long
the attachment within the message body. Other clients
may ignore this information, show an icon, or show ASCII
text that represents the attachment.
The exact filename used by the operating system to locate
Source String and identify the attachment (for example, "\\Server1\Data
\Accounting\JuneSales.xls").
A value that indicates the type of attachment. Microsoft
defines three attachment types:
Type Long Data-A direct file attachment
Embedded OLE-An embedded OLE object
Static OLE-A static OLE object
Attachments can be handled differently by the message transport provider. Microsoft Mail and Windows Messaging
clients display attachments within the message body and transport the attachments as part of the message body, too.
Microsoft Mail and Microsoft Exchange recipients see the attachment within the message body and can use the mouse to
select, view, and save the attachment when desired. Other transports may handle the attachment differently.
SMTP transports will report a message that contains attachments as undeliverable unless the transport supports MIME or
some other binary transfer protocol. The Internet transport that ships with the Windows Messaging Client does support
MIME protocol.
The CompuServe service provider for Microsoft Exchange will transport the attachments as additional messages
addressed to the same recipient. For example, a single ASCII text message with one attachment would be received as
two messages when sent via the CompuServe transport.
Note
The CompuServe message transport for Microsoft Exchange supports only
attach-ments for native, or CompuServe, addresses. You cannot use the
CompuServe transport to send attachments to an SMTP-defined Internet
account (such as [email protected]).
Storage Folders
MAPI messages can be saved in storage folders. The MAPI model defines several storage folders. Figure 4.5 shows a set
of folders as viewed from the Windows Messaging Client.
Figure 4.5 : Viewing the folders from the Windows Messaging Client.
Not all implementations of MAPI support all of the folders listed above. For example, the Simple MAPI interface allows
access to the Inbox (by way of the .Fetch method of the MAPISession Control) and the Outbox (by way of the .
Send method of the MAPISession Control). Simple MAPI allows no other folder access. Programmers cannot inspect
the contents of the Sent folder or move messages from the Inbox to other user-defined storage folders.
The OLE Messaging library offers a more complete access to the MAPI storage system. The Inbox and Outbox
folders are accessible by name (that is, Session.Inbox and Session.OutBox). The Sent and Deleted folders
are available. The OLE MAPI implementation allows access to all folders through the InfoStore object. An
Infostore object contains all folder and message objects. All MAPI service providers can implement their own
message stores, and a single client can have access to more than one message store at the same time. Therefore, a single
MAPI session can involve attaching to several message stores and presenting their contents to the user for handling.
Note
The OLE Messaging library does not allow programmers to create or delete
folders from the InfoStore collection. Only the MAPI 1.0 API set
available from C++ allows programmers to create and delete folders from
the storage set.
The MAPI storage folders are defined as a hierarchy (as seen in Figure 4.5). The MAPI model allows for the creation of
multiple levels of the hierarchy at any time. The MAPI model allows for the creation of subfolders at any level and on
any folder. For example, the Inbox folder can have several subfolders such as UnRead, Read, Urgent, and Unknown.
The addition of subfolders allows users to organize message stores based on use and preference.
The MAPI model defines a handful of properties for storage folders. These properties are available through the OLE
Messaging library and C++. Table 4.4 lists some of the more commonly used properties of the storage folder.
Physical organization of the storage folders can differ greatly depending on the service provider. For example, the
Microsoft Mail Server storage arrangement involves a single directory on the disk that identifies the post office and
subsequent directories underneath that correspond to an individual user's InfoStores (and subfolders within the
storage). However, the physical organization of storage folders for the Windows Messaging Client that ships with
Windows 95 involves a single data file (usually found in \Exchange\mailbox.pst). This single file is used to store
all the personal messages maintained on the user's workstation. It is up to the service provider to establish the storage
details and to support access to the physical storage using the pre-defined InfoStore, Folder, and Message
objects.
Addresses
Addresses are the last class of objects dealt with at the client level. Every electronic message has at least two address
objects: the sender object and the recipient object. MAPI allows you to add several recipient address objects to the same
message. Each address object has several properties. Table 4.5 shows a set of sample properties for the MAPI Address
object.
MAPI address objects are a part of every MAPI message and are stored in the MAPI address book. You'll learn more
about the address book in the following section on MAPI Server objects.
The MAPI Server
The MAPI Server handles all the message traffic generated by MAPI clients. The MAPI Server usually runs on a
standalone workstation connected to the network, but this is not a requirement. There are versions of user-level MAPI
servers that can be used to handle message services.
The Microsoft Mail Server runs standalone on both Intel pcs or Apple workstations. It provides direct MAPI services for
all connected MAPI users and also provides gateway MAPI services for remote users. The Microsoft Mail Server has,
until recently, been Microsoft's primary electronic mail server. Even though Microsoft is stressing the early adoption of
the new Microsoft Exchange Server for NT, the Microsoft Mail Server will continue to be the primary mail server for
thousands of users. All MAPI Clients can share information with connected Microsoft Mail Servers regardless of the
client platform (Win31, WinNT, or Win95).
The Microsoft Exchange Server runs as a service on an NT Server workstation. It provides MAPI services to all MAPI
users. Unlike the Microsoft Mail Server, which distinguishes between local and remote users, the Microsoft Exchange
Server treats all MAPI users as remote users. This simplifies several aspects of MAPI administration. Unlike the
Microsoft Mail Server, which only supports Microsoft Mail format messages, the Microsoft Exchange Server supports
multiple message formats and services, including Microsoft Mail. This also means that the administration of gateways
and remote transports is quite different for Microsoft Exchange.
Microsoft also supports two peer-to-peer message servers. These servers run on the user's workstation, usually as a part
of the MAPI client software. The two client-level MAPI servers provided by Microsoft are
The WorkGroup Post Office runs as a limited version of the Microsoft Mail Server. Clients that use Microsoft's peer-to-
peer networking are able to establish a post office on a single workstation and then share the post office directories with
other peers on the network. The design and operation are very much like the Microsoft Mail Server system, but it runs on
an individual pc. The primary advantage of the peer-to-peer version is that a single user can set up a WorkGroup Post
Office and use that as a base for adding remote mail connections and fax support. The main disadvantage of the peer-to-
peer client is that users were not able to attach to both the WorkGroup Post Office and an existing Microsoft Mail Server
post office.
With the introduction of Windows 95, Microsoft introduced a client version of Microsoft Exchange that provides the
same features as the Microsoft Exchange Server version. Users are able to install and share a WorkGroup Post Office
and are also able to attach to existing Microsoft Mail post offices. In addition, users can connect using other mail
transports as they become available.
Regardless of the actual server application used, the same basic processes must occur for all MAPI server systems. The
three main tasks of all MAPI servers are
Message Transport
Message Transport is the process of moving messages from one place to another. Under the MAPI model, message
transport is a distinct, and often separate, process. MAPI 1.0 allows for the use of external message transports. In other
words, programmers can write software that knows how to handle a particular type or types of message formats and
register this transport mechanism as part of the MAPI system. This allows third-party vendors to create format-specific
transports that can be seamlessly integrated into the MAPI system.
It is the message transport that knows just how to format and, if necessary, pre-process messages for a particular
messaging format. The message transport knows exactly what information must be supplied as part of the message
header and how it needs to be arranged. The message transport also knows what types of message bodies are supported.
For example, SMTP format allows only text message bodies. However, the Microsoft Network message format allows
rich-text message bodies. It is the job of the message transport to keep track of these differences, modify the message
where appropriate, or reject the message if modification or pre-processing is not possible.
One of the key features of the MAPI model is the provision for multiple message transports within the MAPI system.
Once message transports are installed (or registered) with a MAPI client application, they are called into action
whenever the pre-defined message type is received by the MAPI client software. Since MAPI is designed to accept the
registration of multiple transports, the MAPI Client is potentially capable of handling an unlimited number of vendor-
specific message formats.
Note
Message types are stored as part of the address. These types were discussed
earlier in this chapter in the "Addresses" section.
Figure 4.6 shows how the multiple message transports are used when messages are received by the MAPI Client.
Under the MAPI system, message transports provide another vital service. It is the responsibility of the message
transport to enforce any security features required by the message format. For example, the MSN mail transport is
responsible for prompting the user for a username and password before attempting to link with the MSN mail system.
It is important to note that the message transport is not responsible for storing the messages that have been received. The
transport is only in charge of moving messages from one location to another. Message storage is discussed in the next
section.
Message Stores
Message stores are responsible for providing the filing system for the messages received via the message transport. The
MAPI model dictates that the message store must be in a hierarchical format that allows multilevel storage. In other
words, the system must allow users to create folders to hold messages, and these folders must also be able to hold other
folders that hold messages. Under the MAPI model, there is no limit to the number of folder levels that can be defined
for a message store (see Figure 4.7).
Under the MAPI model, storage folders can have properties that control how they are used and how they behave. For
example, storage folders can be public or private. Folders can have properties that make the contained messages read-
only to prevent modification. The options available depend on the implementation of the message store. In other words,
the programmer who designs the message store can establish the scope of storage options and the MAPI Client will
comply with those rules.
As in the case with message transports, MAPI clients can access more than one message store. Figure 4.8 shows the
Windows Messaging Client that is currently accessing two different message stores. You can see that each store has its
own set of folders and its own set of messages.
The Windows Messaging Client that ships with Microsoft Exchange Server also allows you to create folder column,
grouping, sort, and filter rules for personal and public folders. By doing this, you can create storage views that reflect the
course of an ongoing discussion and allow for easy search and retrieval of data kept in the message store (see Figure
4.9).
Address Books
The last of the main MAPI server objects is the address book. The MAPI address book contains all the directory
information about a particular addressee. The book can contain data for individual users or groups of users (a distribution
list). The minimum data stored in the address book is the user's display name, the transport type, and the user's e-mail
address.
Additional information such as mailing address, telephone number, and other data may be available depending on the
design of the address book.
Address books, like the other objects described in this chapter, work independently under the MAPI model. Also, the
MAPI client can access more than one address book at a time. This means that several address books of various formats
can all be viewed (and used) at the same time when composing messages (see Figure 4.10).
Along with storing addresses, the address book interface also acts to resolve display names used in the MAPI interface
with the actual e-mail addresses and transport types for those display names. To do this, MAPI offers a ResolveName
service that performs lookups upon request. The ResolveName service is able to look at all address books (regardless of
their storage format) in order to locate the proper e-mail address.
Users are also able to designate one of the address books as the default or personal address book. This is the first address
book in which new addresses are stored and the first address book that is checked when resolving a display name. The
Windows Messaging Client and the Microsoft Mail client both ship with default personal address books. The Windows
Messaging Client allows users to add new address books and designate their own personal address book container.
The MAPI Spooler is a special process that interacts with both message stores and message transports. It is the spooler's
job to route messages from the client to the proper transport and from the transport to the client. The spooler is the direct
link between the client and the transport. All messages go through the MAPI Spooler.
Note
Actually there are some cases in which a message moves directly from the
message store to the message transport. This occurs when service providers
offer both message store and message transport. E-mail service providers
that offer these features are known as tightly coupled service providers.
Figure 4.11 illustrates the different paths messages can take when the MAPI Spooler is used.
Figure 4.11 : The MAPI Spooler passes messages between the message store and the message transport.
As each message is moved from the message store (the "outbox") to the transport, the MAPI Spooler checks the address
type to see which transport should be used. Once this is determined, the spooler notifies the transport and attempts to
pass the message from the message store to the message transport. If the transport is not currently available, the MAPI
Spooler holds onto the message until the transport is free to accept messages. This allows transport providers to act as
remote connections without any additional programming or addressing on the client side.
Note
In fact, the implementation used in the Microsoft Exchange version of
MAPI treats all connections as if they were remote-even when the message
is moved from one user's Microsoft Exchange outbox to another Microsoft
Exchange user's inbox on the same network.
In the case of messages that move along a constantly connected transport (that is, between two addresses on the same
Microsoft Exchange Server), the spooler notifies the transport (Microsoft Exchange) and the transport accepts the
message almost immediately. Often the user is not aware of any delay in the handling of the message.
In the case of messages that move from the Windows Messaging Client by way of an SMTP transport through a dial-up
connection to the Internet, the MAPI Spooler holds onto the message until the user connects to the Internet account
through Win95 Dial-Up Networking. Once the connection is made, the MAPI Spooler sends all local messages on to the
Internet mail server, retrieves any waiting mail from the mail server, and passes these new messages to the appropriate
message store.
The MAPI Spooler is also able to move a single message to several recipients when some of those recipients are not
using the same message transport. For example, users can build distribution lists that contain names of users on the local
Microsoft Exchange Server, users who have addresses on a local Microsoft Mail Server, and users who can only be
contacted through a fax address. When the message is sent, it moves from the message store to the spooler, which then
sorts out all the transports needed and passes the messages on to the correct transports at the first available moment.
The MAPI Spooler is also responsible for marking messages as read or unread, notifying the sender when a message has
been successfully passed to the transport, and, when requested, notifying the sender when the recipient has received (or
read) the message. The MAPI Spooler also reports when messages cannot be sent due to unavailable transports or other
problems.
Summary
In this chapter, you learned about the general architecture of the MAPI system. You learned that there are two main
components to the system:
You learned that the MAPI Client resides on the user's desktop and handles three main MAPI objects:
This chapter also reviewed the basic properties and features of MAPI messages, including message headers, folders, and
address objects.
You learned that the MAPI Server usually resides on a standalone workstation connected to the network (although not
always). Like the MAPI Client, the MAPI Server handles three main objects:
● Message transports
● Message stores
● Address books
You learned that the MAPI model allows users to use multiple versions of message transports (such as Microsoft
Exchange Server messages and SMTP Internet messages), message storage, and address books. You also learned about
the MAPI Spooler. The MAPI Spooler is the process that moves items from the message store to the appropriate
provider.
Now that you know the basic architecture of the MAPI system, it's time to build some applications that use the system.
In the next chapter, you'll learn how to use the Microsoft Exchange Forms Designer to build MAPI-enabled applications
that work within the Microsoft Exchange interface.
Chapter 8
CONTENTS
● Introduction
● The Session Object
❍ The Session Object Methods
● Summary
Introduction
One of the new features of Microsoft Exchange is the creation of the OLE Messaging library. This set of OLE objects,
properties, and methods allows any VBA-compliant development tool to gain access to MAPI services and incorporate
them into desktop applications. This chapter shows you how the OLE Messaging library works and how you can use the
OLE objects to create MAPI-enabled programs.
This chapter provides an overview of all the OLE Messaging library objects and gives examples of their use. You'll learn
about the following objects:
You'll also learn how these objects interact with each other and how to use them to perform several advanced MAPI
tasks, including:
When you complete this chapter, you'll understand the OLE Messaging library objects and how to use them to build
MAPI-compliant e-mail applications with any VBA-compatible development tool.
The Session object of the OLE Messaging library is the top-most object in the hierarchy. You must create an instance
of a MAPI Session object before you can gain access to any other aspects of the MAPI system. The Session object
has several properties (including subordinate objects) and a handful of methods that you can invoke.
Table 8.1 shows the Session Object Methods along with a list of parameters and short descriptions.
The most used of these methods are the Logon and Logoff methods. You use these to start and end MAPI sessions.
You will also use the AddressBook and GetInfoStore methods frequently in your programs.
If you have not done so yet, load Visual Basic 4.0 and start a new project. Place a single button on the form. Set its index
property to 0 and its caption to MAPI &Start. Copy and paste a second command button onto the form and set its
caption property to MAPI &End. Now add the code in Listing 8.1 to the Command1_Click event of the buttons.
The code in Listing 8.1 calls two subroutines-MAPIStart and MAPIEnd. They each use a form-level variable called
objSession. Add this variable to the general declarations section of the form.
Option Explicit
'
Dim objSession As Object ' for mapi session
Now create a new subroutine called MAPIStart and add the code shown in Listing 8.2. This routine initializes the
session object and calls the MAPI logon dialog box.
It is important that you formally end each MAPI session you begin. This will ensure that you do not have any stray
sessions running in the background.
Warning
By default, the MAPI Logon method will attempt to connect you to the
first available active session currently running on your workstation. For
example, if you have started a MAPI session with your e-mail client and
you then run this sample code, MAPI will attach this program to the same
MAPI session started by the MAPI client. This could give you unexpected
results. That is another reason why you should always close your MAPI
sessions when you are exiting your programs.
Now add a new subroutine to the project called MAPIEnd and add the code shown in Listing 8.3. Notice that this routine
sets the objSession variable to Nothing. This is done to clear Visual Basic's memory storage and conserve RAM
space.
Save the form as OML.FRM and the project as OML.VBP. You can now run the project and log into and out of a MAPI
session. You won't see much, but it works!
Add another command button to the array (Edit | Copy, Edit | Paste) and modify the Command1_Click event
to match the code in Listing 8.4. This will call up the MAPI address book.
Listing 8.4. Modifying the Command1_Click event to call the address book.
Now add the MAPIAddrBook routine to the form and enter the code in Listing 8.5.
Save and run the project. After clicking the MAPI Start button, press the Address Book button. Your screen
should look like the one in Figure 8.1.
You can set several parameters when you call the Address Book method. For example, you can set the title of the
address book using the Title property. You can also control the number and caption of the recipient selection buttons
that appear on the address book. You can even set the address book dialog so that the user can review the addresses but
cannot select one.
Listing 8.6 shows you how to modify the code in the MAPIAddrBook routine to set the title and remove all recipient
selection buttons.
When you run the project, your address book will look something like the one in Figure 8.2.
You can also control the Logon method behavior by passing selected parameters. The most common use for this is
automatically logging a user into MAPI without the use of the Logon dialog box. To do this you need to pass the user
profile and password and set the ShowDialog flag to false.
Listing 8.7 shows you how to modify the MAPIStart routine to perform an automatic logon. You should change the
ProfileName parameter to match your personal Microsoft Exchange logon.
Now let's look at some of the Session object properties. After reviewing the properties, you can add another button to
the form to display the properties of your MAPI session. Table 8.2 has a list of the Session object properties, their
type, and a short description.
The Session object has several properties, many of them objects themselves. Using these object properties allows you
to gain access to more complex data than standard strings or numbers. You'll inspect the object properties later in the
chapter.
Now add another button to the control array (use Edit | Copy, Edit | Paste), set its Caption to "MapiProps" and
modify the code in the Command1_Click event to look like the code in Listing 8.9.
Now create a new subroutine called SessionProps and enter the code that appears in Listing 8.10. This routine
creates a message box that displays several of the Session object's properties.
Save the project again and run it. After clicking on the MAPI Start button, click on the MapiProps button. Your
screen should look like the one in Figure 8.3.
Figure 8.3 : Displaying the Session properties.
Now it's time to start inspecting the subordinate objects in the OLE Messaging library.
The first-level subordinate object of the Session object is the InfoStore object. Each InfoStore object
represents a separate message store. The MAPI model allows clients to access more than one message storage system at
the same time. For example, the Microsoft Exchange shared folders are a separate message store (represented by a
separate InfoStore object). The Microsoft Exchange Personal Folders are another separate message store. Users can
have any number of message stores connected to their MAPI client.
The InfoStores collection object is an OLE Messaging library object that allows you to view all the connected
message stores for the logged-in user. You can use the InfoStores object to locate a particular message store and
then access that message store using the InfoStore object.
Note
Be sure not to confuse the InfoStore object with the InfoStores
object. The InfoStore object is the OLE Messaging library object that
you use to gain access to the contents of a single message store. The
InfoStores object is the OLE Messaging library object you use to gain
access to the collection of message stores. In Microsoft OLE naming rules,
collection objects are plural (InfoStores) and single objects are not
(InfoStore).
The InfoStores collection has only a few properties and no methods at all. You cannot add, modify, or delete
InfoStore objects using the OLE Messaging library interface. Table 8.3 shows the InfoStores properties with
their type and a short description.
To test the InfoStores object, add another button to the control array on the form with the caption of
InfoStoreColl and modify the Command1_Click event as shown in Listing 8.11.
Listing 8.11. Updated Command1_Click event.
Next you'll need to add two new form-level variables to the general declaration section of the form. Your general
declaration section should now look like this:
Option Explicit
'
Dim objSession As Object ' for mapi session
Dim objInfoStoreColl As Object ' collection of stores
Dim objInfoStore As Object ' single info store
Now add the SessionInfoStoreColl routine shown in Listing 8.12. This routine gets the InfoStores
properties and displays the names of all the message stores in the collection.
Warning
The OLE Messaging library does not require message stores to have unique
names. If you are using the InfoStores collection object to locate a
particular message store, you must be sure that there is not more than one
store with that name in the collection! InfoStore objects are assigned a
unique unchanging ID value. Once you know the ID value of an
InfoStore object, you can locate it using the GetInfoStore method
of the Session object.
Save and run this project. After logging in, press the InfoStoreColl button. Your screen should look similar to the
one in Figure 8.4.
Now that you know how to review the InfoStore collection, it's time to learn more about the individual InfoStore
objects.
The InfoStore object contains all the folders and messages defined for a single message store. InfoStore objects
have several properties and no methods. You cannot use the OLE Messaging library to add, modify, or delete
InfoStore objects. Table 8.4 shows the important InfoStore object properties, their types, and their descriptions.
Now add some code to view the properties of an InfoStore object. First, add another command button to the control
array and set its caption to InfoStore. Then modify the Command1_Click routine so that it matches the one in
Listing 8.13.
Now add the InfoStoreProps subroutine and enter the code shown in Listing 8.14.
Note that the InfoStore object is part of what is called a small collection. OLE object collections that are considered
to have a limited number of members are called small collections. All small collection objects have an Index property
and a Count property. Most of them also have an Item property. Small collection objects support the use of the For
Each...Next programming construct.
Save and run the project. After clicking the InfoStore button, you should see a series of dialog boxes showing the
properties of each message store available to your client (see Figure 8.5).
The next object to review is the Folder object and the Folders collection object.
One of the first level objects below the InfoStore object is the Folder object. The Folder object can hold
messages and other folders. Each InfoStore object also has a Folders collection object that contains a list of all the
Folder objects in the message store.
There is no limit to the number of messages or folders a Folder object can have. For this reason it is called a large
collection object. large collection objects do not have an Index property or a Count property. The only
way you can locate all the folders in a message store is to "walk through" the store using a set of methods to get each
item. All large collection objects support the use of the GetFirst, GetNext, GetPrevious, and
GetLast methods to provide a way to navigate through the collection. You'll use these methods in the next few
examples.
The Folders collection object has only a few properties and methods. Table 8.5 shows the important Folders
collection object properties and Table 8.6 shows the Folders collection object methods.
To test the Folders object, add two new variables to the general declaration area of the form. Your form-level variable
list should now look like this:
Option Explicit
'
Dim objSession As Object ' for mapi session
Dim objInfoStoreColl As Object ' collection of stores
Dim objInfoStore As Object ' single info store
Dim objFolderColl As Object ' collection of folders
Dim objFolder As Object ' single folder
Now add another command button to the control array and set its Caption property to FolderColl. Then modify the
Command1_Click event so that it matches the code in Listing 8.15.
Now add the new subroutine called FoldersColl and enter the code from Listing 8.16.
The FoldersColl routine shows the application and class property of the object and then lists all the folder names in
the collection. Note that you cannot determine the folder hierarchy from the list returned by the Get methods. The Get
methods traverse the folder collection in the order the folders were created, not in the order they are displayed or
arranged within the MAPI client.
Save and run the program. Clicking the FoldersColl button should give you a display similar to the one in Figure
8.6.
The Folder object has several properties and one method. The OLE Messaging library allows you to modify the Name
property of a Folder object, but you cannot add or delete a Folder object from the message store. Table 8.7 contains
the list of important Folder object properties.
Add a new button to the command array and set its Caption property to Fo&lder Object. Then modify the
Command1_Click event to match the one in Listing 8.17.
Save and run the project. Then click the Folder Object button and compare your results with those shown in Figure
8.7.
The only method available for Folder objects is the Update method. You can use this method to save changes made
to the Folder object properties. The only property you can modify is the Name property. If you wish to change the
name of an existing folder you can use the following line of code:
Note
The MAPI system will not let you modify the name of the Inbox,
Outbox, Sent Items, or Deleted Items folders. Attempting to do
this will cause MAPI to return an error to your program.
There are two folders that are used for almost every MAPI message transaction:
Note
The InfoStore object was discussed in the earlier section of this chapter
titled "The InfoStore Objects and Collections."
You can modify the FolderProp routine to access the properties of the Inbox by changing the line that sets the
objFolder object.
'
'Set objFolder = objSession.InfoStores.Item(1).RootFolder
Set objFolder = objSession.Inbox
'
Now when you click the Folder Object button, you'll get data on the Inbox folder in message store #1. This works
the same way for the Outbox.
The Message object and Messages collection object are the heart of the OLE Messaging library. These objects hold
the actual messages composed and received by the MAPI client. You will use the Message objects to read, modify,
create, and delete messages from the message store.
The Messages collection object has very few properties and a number of methods. Because the Message collection is
a large collection (that is, it has an unlimited number of members), you must use the GetFirst, GetNext,
GetPrevious, and GetLast methods to retrieve messages from the collection. You can also add and delete
messages within the collection.
Table 8.8 shows the properties for the Messages collection object.
Table 8.9 shows the list of methods for the Messages collection object.
To test the Messages collection object, you first need to add two new variables to the general declaration area of the
form. Make sure your variables match the ones in Listing 8.19.
Option Explicit
'
Dim objSession As Object ' for mapi session
Dim objInfoStoreColl As Object ' collection of stores
Dim objInfoStore As Object ' single info store
Dim objFolderColl As Object ' collection of folders
Dim objFolder As Object ' single folder
Dim objMessageColl As Object ' messages collection
Dim objMessage As Object ' single message
Next add a new button to the control array and set its caption to M&essageColl. Then modify the
Command1_Click event to match the code shown in Listing 8.20.
Then add the new MessagesColl subroutine to the project and enter the code from Listing 8.22.
Save and run the project. Your screen should look similar to the one in Figure 8.8.
You can sort the messages in the collection using the Sort method. Setting the sort order affects how the Get methods
access the messages in the collection. The sort order is based on the TimeReceived property of the messages. The sort
method can be set for None(0), Ascending(1), or Descending(2). The default SortOrder is None(0). If
there is no sort order specified, the Get methods access the messages in the order in which they were added to the
message collection.
Tip
Because the sort order affects the way in which the Get methods access the
file, setting the SortOrder to Ascending(1) and performing the
GetFirst method on the messages collection will return the same
message as setting the SortOrder to Descending(2) and performing
the GetLast method on the messages collection.
Modify the MessageColl routine to ask you for a sort order. Add the lines of code to the routine as indicated in
Listing 8.23.
Now when you press the MessageColl button you'll be asked to supply a sort order and then be presented with a
different view of the message collection list.
You can delete all the messages in a message collection by invoking the Delete method followed by the Update
method on the parent object to save the change. The code below shows how this is done.
Set objMessageColl = objSession.Inbox.Messages ' get inbox
messages
objMessageColl.Delete ' dump all messages in the inbox
objSession.Inbox.Update ' make the modification permanent
You'll learn about the Add method in the section on the Message object.
The Message object is the richest object in the OLE Messaging library system. It has only a few methods, but they are
all quite powerful. They allow you to delete the message from the collection (Delete), display a message option dialog
box (Options), display a send dialog box (Send), and save the modified message properties (Update). These
properties range from handling attachments to flagging a message as read or unread. Table 8.10 shows the Message
object methods with their parameters and a short description.
The Message object properties are extensive and powerful. The properties range from simple Boolean flags to indicate
the importance of a message, to the actual text body of the message, to the list of binary attachments to the message.
Table 8.11 shows the important Message object properties, their type, and a short description.
IPM-Interpersonal messages.
These are recognized by the
MAPI client and displayed in
Type String
the Inbox when received.
Ipc-Interprocess
communications. These are
not recognized by the MAPI
client, but can be processed
behind the scenes.
Flag indicating whether the
Unread Boolean
message has been read.
Now add another button to the control array and set its caption to MessageProps. Then modify the
Command1_Click event as shown in Listing 8.24.
Next add a new subroutine called MessageProps to the form and enter the code from Listing 8.25.
The MessageProps routine first selects the session's Inbox message collection and then selects the first message in
the collection.
Warning
This routine crashes with an error if no message is present in the Inbox. If
you do not currently have at least one message in the Inbox, fire up an e-
mail client and place one there before running this routine. In production
applications, you should make sure you trap for such an error to prevent
needless (and annoying) crashes.
Notice the addition of the On Error Resume Next just before the series of statements that retrieve the message
properties. This is done in case one or more properties are missing in the selected message. Since MAPI supports
messages from several different providers, it is quite likely that some of the properties will contain garbage or nothing at
all. You should keep this in mind when writing routines that read Message object properties.
Save and run the project. After starting MAPI and pressing the MessageProps button, you'll see something like the
data shown in Figure 8.9. Of course, the actual values of the properties will vary depending on the message you are
reading.
It's easy to add new messages to the message collection. The simplest method is to use the Send method of the
Message object to invoke the MAPI Send dialog box. From this dialog box, the user can compose, address, and send
the message without any additional coding.
Add a new button to the control array and set its caption property to MessageAdd. Then update the
Command1_Click event so that it matches the one in Listing 8.26.
Listing 8.26. Updating the Command1_Click event.
Now add the MessageAdd subroutine and enter the code from Listing 8.27. This will create a new Message object in
the message collection and then bring up the MAPI Send dialog box.
After adding this routine, add a new button to the array and set its caption property to MessageMake. Also add another
line to the Select Case structure to handle the button selection (see Listing 8.29).
You can also set several message options by calling the Options method to bring up the Options dialog box. Modify
the code in the MessageMake routine to call the Options method before the Send method. Insert the line shown
below into the code just before the objMessage.Send line.
When you save and run the project, press the MessageMake button. You'll see the Options dialog box before you see
the Send dialog box. The exact layout and contents of the Options dialog box depend on the type of message you are
working with and the available message transports at your workstation (see Figure 8.10).
You can also compose a complete message, address it, and send it without the use of dialog boxes. However, to do that
you need to create at least one recipient object. You learn how to do that in the next section.
The OLE Messaging library defines two address objects-the Recipient object and the AddressEntry object. The
two objects are related, but serve different purposes. The purpose of the Recipient object is to provide valid
addressing information for the message. The purpose of the AddressEntry object is to gain access to individual
records in the MAPI address book.
The next several sections outline the properties and methods of both the Recipient and AddressEntry objects.
The Recipients collection object holds a list of all recipients for a message. Every message has a recipients
collection-even if the message has only one recipient in the collection. There are three methods for the collection and a
handful of properties. Because the Recipients collection is a small collection, it has Count and Item properties.
This also means that the Recipient object supports an Index property.
Table 8.12 shows the Recipients object methods and Table 8.13 shows the object's properties.
To test the properties of the Recipients collection object, add a new button to the control array and set its caption to
RecipColl. Then add a new line in the Command1_Click event to match the code in Listing 8.30.
Before coding the collection routine, you must first add three new variables to the general declaration area of the form.
Modify the declaration list to match the code in Listing 8.31.
Option Explicit
'
Dim objSession As Object ' for mapi session
Dim objInfoStoreColl As Object ' collection of stores
Dim objInfoStore As Object ' single info store
Dim objFolderColl As Object ' collection of folders
Dim objFolder As Object ' single folder
Dim objMessageColl As Object ' messages collection
Dim objMessage As Object ' single message
Dim objRecipColl As Object ' recipient collection
Dim objRecipient As Object ' single recipient
Dim objAddrEntry As Object ' addressentry object
Next add the RecipColl subroutine to the project and enter the code in Listing 8.32.
The RecipColl routine locates the first message in the Inbox collection and then displays the Recipients
collection object properties. Notice that the routine calls the Name property of the Item object in the collection. The
Item(1) property points to the first recipient object in the collection.
In Figure 8.11 you can see the results of a message with three recipients. Your exact results will vary based on the
message you select.
Using the Delete method will remove all the Recipient objects from the collection. After calling the Delete
method, you must call the Update method on the Message object to make the changes permanent. Once the recipients
are deleted, they cannot be recovered. The following code sample illustrates how to remove all recipients from a
collection:
objMessage.Recipients.Delete
objMessage.Update
You can use the Add method to add a new recipient to a message, as explained in the next section.
The Recipient object holds all the information needed to address a message to its destination. Along with the usual
properties, the Recipient object has an AddressEntry property. This property points to a valid AddressEntry
object. You'll learn more about the AddressEntry object in the next section. The methods for the Recipient object
allow you to delete the recipient from the collection and validate the address before attempting to send the message.
Table 8.14 shows the Recipient object methods, and Table 8.15 shows the Recipient object properties.
TransportType:
EmailAddress. The
Address String TransportType is taken from
the Type property of the child
AddressEntry object. The
EmailAddress is taken from the
Address property of the
AddressEntry object.
The underlying object that contains
detailed information on the
AddressEntry AddressEntry object recipient, including the exact
address and message transport
type.
Name of the library. Always set to
Application String
OLE/Messaging.
Internal identifying code for all
Class Long MAPI objects. Always set to 4 for
Recipient objects.
A value that indicates the type of
recipient. This is used to control
how the message is displayed by
client applications. Valid display
types are
Local User
Distribution List
Shared Folder
Agent
DisplayType Long
Organization
Private Distribution
List
Remote User
To view the properties of a Recipient object, add another button to the control array and set its caption property to
RecipProps. Then modify the Command1_Click event as shown in Listing 8.33.
You can use the Add method of the Recipients collection object to add a valid recipient to a message. To do this you
must have a Message object, access the recipients collection for that message, execute the Add method, and then
populate the new Recipient object properties. Once that is done, you must execute the Update method of the
message to save all changes.
Add a new button to the control array and set its caption property to RecipAdd. Be sure to modify the
Command1_Click event to match the code in Listing 8.35.
Now add the RecipAdd subroutine to the form and enter the code from Listing 8.36.
The RecipAdd routine first creates a new message in the outbox and then adds a new recipient to the message. Finally,
after validating the Recipient object, the routine updates all the changes and calls the Send dialog box (see Figure
8.12).
This routine could easily be modified to complete the send operation without presenting any dialog boxes. If you
change the ShowDialog parameter to False, the OLE Messaging library will post the message without interfacing
with the user.
The AddressEntry object is a child object of the Recipient object. The AddressEntry object contains all the
valid addressing information for a message system. The AddressEntry object is also the object that represents an
entry in the MAPI address book. In this way, the AddressEntry object provides a link between the MAPI address
book and MAPI messages.
The OLE Messaging library interface allows you to modify or delete AddressEntry objects from the MAPI address
book. However, there is no Add method for the AddressEntry object. You cannot use the OLE Messaging library to
create new entries in the MAPI address book. Table 8.16 shows the AddressEntry object methods, their parameters,
and brief descriptions.
The AddressEntry object has a handful of properties. These properties identify the message transport used to send
messages to this location, the actual address, and other internal properties. Table 8.17 shows the properties of the
AddressEntry object.
Table 8.17. The AddressEntry object properties.
Property name Type Description
The electronic mail address of the
Address String
record.
Name of the library. Always set to
Application String
OLE/Messaging.
Internal identifying code for all
Class Long MAPI objects. Always set to 8 for
AddressEntry objects.
A value that indicates the type of
recipient. This is used to control
how the message is displayed by
client applications. Valid display
types are
Local User
Distribution List
Shared Folder
Agent
DisplayType Long
Organization
Private Distribution
List
Remote User
Add a new button to the control array and set its caption to AddrProps. Then modify the Command1_Click event to
match the code in Listing 8.37.
Listing 8.37. Modifying the Command1_Click event.
Now add the AddrProps subroutine and enter the code in Listing 8.38.
When you save and run the project, then click AddrProps, you'll see a set of property information for the message
recipient. Although the details will vary, your screen should look like the one in Figure 8.13.
You can use the Details method to invoke a Details dialog box for an AddressEntry object. This is handy for
looking up additional information on a known AddressEntry object. Add another button to the control array and set
its caption to AddrDetails. Modify the Command1_Click event as shown in Listing 8.39.
'
End Sub
Now add the AddrDetails subroutine and enter the code from Listing 8.40.
After accessing the first message in the inbox and getting the AddressEntry of the first Recipient object of the
message, this routine invokes the Details method to show a dialog box that allows users to modify the fields of the
address book entry (see Figure 8.14).
Figure 8.14 : Viewing the Details dialog box for the AddressEntry object.
You can modify AddressEntry properties without invoking the Details method. For example, you can change the
Name property of an existing AddressEntry object. The following code fragment shows how this is done:
You can also delete an entry from the MAPI address book by using the Delete method. The following code example
shows how this can be done:
Warning
Once a Delete/Update method pair is invoked on an AddressEntry
object, it is permanently removed from the address book and cannot be
recovered. Use this method sparingly. And when you do provide delete
services in your programs, be sure to add a confirmation option dialog box
before permanently deleting the object.
The Attachment objects contain non-text data that is to be sent along with a standard message. Often this is a binary
graphic or formatted document file that is shipped from one user to another. The Attachment object methods and
properties allow you to read and write attachments to your messages.
There can be multiple attachments for each message. For this reason, the message object has an Attachments
collection object associated with it. All attachment objects are part of the Attachments collection.
The Attachments collection object is a child of the Message object and holds all the associated attachments for that
message. The Attachments collection is a small collection, so it supports the Count and Item properties and the
Attachment object supports the Index property.
Table 8.18 shows the Attachments collection object methods, and Table 8.19 shows the Attachments collection
object properties.
To test the Attachments collection object, add a new command button to the control array and set its caption to
AttachColl. Then modify the Command1_Click event to match the code in Listing 8.41.
Next you need to add two new variables to the general declaration section of the form. Modify your declarations to
match the code in Listing 8.42.
Option Explicit
'
Dim objSession As Object ' for mapi session
Dim objInfoStoreColl As Object ' collection of stores
Dim objInfoStore As Object ' single info store
Dim objFolderColl As Object ' collection of folders
Dim objFolder As Object ' single folder
Dim objMessageColl As Object ' messages collection
Dim objMessage As Object ' single message
Dim objRecipColl As Object ' recipient collection
Dim objRecipient As Object ' single recipient
Dim objAddrEntry As Object ' addressentry object
Dim objAttachColl As Object ' attachment collection
Dim objAttachment As Object ' single attachment
Now add the AttachColl subroutine to the form and enter the code that appears in Listing 8.43.
Warning
The AttachColl routine will crash if there are no attachments on the first
message in the inbox. Be sure to add a single message in the inbox with at
least one attachment before you run this routine. You can use your MAPI
client to create a new message with attachments and send it to yourself.
The AttachColl routine accesses the attachments collection of the first message in the inbox and displays its
properties. Your output may be different, but it should look something like Figure 8.15.
You can delete all the attachments in the collection by invoking the Delete method on the Attachments collection
object. The delete is not complete until you invoke the Update method on the parent object. And once the delete is
complete, you cannot recover the data.
You'll learn about the Add method in the next section on Attachment objects.
To review the attachment properties, add a new button to the control array and set its caption to AttachProps. Then
modify the Command1_Click event to match the code in Listing 8.44.
Now add the AttachProps subroutine and enter the code from Listing 8.45.
Save and run this routine. When you click on the AttachProps button, you will see the properties of the attachment.
Refer to Figure 8.16 for an example of the output.
You can use Visual Basic code to add an attachment directly to a message. This involves setting three properties and
invoking the ReadFromFile method. First, add another button to the control array and set its caption to AttachAdd.
Then modify the Command1_Click event to match the code in Listing 8.46.
Next, add a new subroutine called AttachAdd and enter the code shown in Listing 8.47.
Warning
Be sure to address the message to a valid person in your MAPI address
book. It is a good idea to address this message to yourself since you will be
reading and saving an attachment in the next section.
The AttachAdd routine creates a new message, adds the WIN.INI file as an attachment (at the first position in the
file), and then addresses the message and sends it. Your screen should look something like the one in Figure 8.17.
Tip
You could easily send the message without ever seeing the dialog box by
just setting the ShowDialog parameter to False.
Now you can read the message you just sent yourself. Add one more button to the command array and set its caption to
AttachSave. Then modify the Command1_Click event to match the code in Listing 8.48.
Now add the AttachSave subroutine and enter the code from Listing 8.49.
The AttachSave routine reads the last message added to the inbox collection (the one you sent just a moment ago)
and retrieves the attachment from the message's attachment collection. The attachment is then saved in the local disk
folder as SAVED.TXT (see Figure 8.18).
In production applications, you should add code to the routine to prompt the user for a folder and filename for storing the
attachment.
Summary
In this chapter, you learned how to use the OLE Messaging library to access features of MAPI. You learned all the major
objects, their methods, and their properties.
You also wrote several code examples that inspected and modified objects and their properties. You learned to use the
OLE Messaging library to
The OLE Messaging library is a rich and powerful set of commands. In the next several chapters, you'll use the OLE
Messaging library to build powerful desktop applications that use the advanced features of MAPI 1.0.
Chapter 7
CONTENTS
❍ Additional Features
● Summary
In this chapter, you'll learn how to use the MAPI controls from Visual Basic to create a simple program that can read and
reply to all e-mail sent to the logon ID. You'll also learn how to write routines to access all the electronic mail services
available to a basic MAPI client application on a desktop workstation. This includes creating new e-mail messages,
checking the inbox for new mail, and accessing and updating the e-mail address book. When you complete this chapter,
you will have a fully functional e-mail client application.
You'll also learn the details of using the MAPISession and MAPIMessage controls with Visual Basic 4.0. The Visual
Basic MAPI controls offer a quick way to build Simple MAPI applications. The MAPI controls allow you full access to
the Inbox object, to the MAPI Compose, Fetch, Read, Delete, and Send services, and limited access to the
address book.
Note
Simple MAPI is sometimes called MAPI 0 to indicate that it precedes the
MAPI 1.0 release that matches Microsoft Exchange Server. Throughout this
book, you'll see Simple MAPI instead of MAPI 0.
When you complete the coding examples in this chapter, you will understand the basics of Simple MAPI, and you'll
know how to use Visual Basic and the MAPI controls to read, compose, address, send, and delete MAPI messages.
Visual Basic 4.0 Professional Edition ships with two OCX controls that provide access to all the MAPI services you'll
need to create fully functional electronic mail applications using Visual Basic. The MAPISession control provides
access to everything you'll need to sign on and sign off any MAPI-compliant server. The MAPIMessage control
provides access to the MAPI routines that allow you to read, compose, address, and send messages using the session
established with the MAPISession control. This section of the chapter will review the MAPI-related properties and
methods of each of these controls.
The MAPISession control is used to establish a link between your Visual Basic program (the mail client) and the
electronic mail server. The MAPI-compliant mail server must be installed and available to the Visual Basic client
program. If your program will run on a traditional network server, the mail server may be Microsoft Mail installed on a
network workstation. If you are running Windows for Workgroups or Windows 95, Microsoft Mail or Microsoft
Exchange can act as a mail server. There are other mail servers available for both file server and peer-to-peer networks.
There are two methods and seven properties for the MAPISession control that are directly MAPI related. The two
following sections identify these components of the MAPISession control, and describe their meaning and their use in
Visual Basic programs.
There are only two MAPISession methods: SignOn and SignOff. The SignOn method is used to begin a MAPI
session. By default, the SignOn method provides a logon dialog box that prompts the user for valid logon information.
The exact nature of the logon dialog box depends on the mail server. The Microsoft Mail logon dialog box prompts the
user for a valid username and password (see Figure 7.1).
The default logon dialog box for the Microsoft Exchange Mail product simply asks the user to select the desired mail
services profile (see Figure 7.2).
Figure 7.2 : Default logon dialog box for Microsoft Exchange Mail.
If a valid username and password are supplied by way of the SignOn method, the MAPISession control returns a
unique value in the SessionID property. This unique value is used in all message transactions to identify the link
between the client application and the mail server. We'll talk more about the SessionID property in the next section of
this chapter.
The SignOff method of the MAPISession control does just what you'd expect-it safely ends your link to the mail
server. There is no dialog box associated with the SignOff method.
In order to use the MAPISession control methods, you must first place the MAPISession control on a Visual Basic
form. The form is invisible at run-time and is only used to provide the methods and properties needed to establish a
MAPI session between your Visual Basic program and the mail server.
As an example of the MAPISession control, start a Visual Basic project. Use the Tools | Custom Controls
menu item to add the Microsoft MAPI controls to your project. Place a MAPISession control on the form and add the
three lines of code in Listing 7.1 to the Form_Load event.
Save the form as CDG0701.FRM and the project as CDG0701.VBP, and run the project. You'll see the default logon
dialog box provided by your mail server. Once you sign in, the Visual Basic program immediately signs you out and
ends. You'll add more features as we go along.
The MAPISession control has seven MAPI-related properties. These properties all deal with options that you can set
to control the behavior of the control at logon time.
The Action property can be used to invoke the sign-on or sign-off methods. This property was present in Visual Basic
3.0 and has been replaced by the SignOn and SignOff methods discussed earlier.
The DownloadMail property is used to control whether new messages are downloaded from the mail server at logon
time. By default, all new messages are forced into the user's mailbox at logon time. You can set this property to False
to prevent this from happening. In the code example in Listing 7.2, the DownloadMail property has be set to False
before invoking the SignOn method.
You can use the NewSession property to force the creation of a new MAPI session, even if a MAPI session already
exists for this workstation. By default, the SignOn method will attempt to locate any current MAPI interface sessions
before attempting to log on to the mail server. When you set the NewSession parameter to True, the SignOn
method will create a second MAPI session link with the mail server. The code in Listing 7.3 shows how this is done.
The Password and UserName properties should be set to valid values if you want to bypass the default logon screen.
If you supply a UserName but leave the Password property blank, the SignOn method will force the logon dialog
box to appear and prompt for the missing information. If, however, the LogonUI property is set to False, no dialog
box will appear, and an error will be returned.
If you are using the Microsoft Exchange Mail Client, you only need to provide a valid Profile Name. Microsoft
Exchange Mail will ignore any value in the Password property. If you are using the Microsoft Mail client (network or
workgroup version), you will need to supply both the UserName and the Password properties if you want to bypass
the default logon dialog box. Refer to Listing 7.4 for an example.
The SessionID property is a read-only property available only at run-time that contains the unique session ID number
of a completed link between your Visual Basic program and the mail server. This session ID value must be used in all
transactions to the mail server. Its value is used to set the SessionID of the MAPIMessage control before attempting
to access the message services provided by the mail server. The code in Listing 7.5 displays the value of the
SessionID after a successful logon of the user.
Modify the UserName and, if needed, the Password properties to contain valid logon data for your mail server. Then
save and run the project. You will see a message box that shows the unique session handle for the MAPI session (see
Figure 7.3).
The MAPIMessage control gives your Visual Basic program access to all the message services available from the mail
server with which your program has established a session. The MAPIMessage control provides services for reading,
composing, addressing, and sending mail messages. You can perform all major mail operations by requesting the service
from the server.
There are 11 methods and over 30 properties of the MAPIMessage control that are MAPI-related. We'll review these
methods and properties briefly. You can find additional documentation on each of the MAPIMessage properties in the
Visual Basic online help files.
Methods
● To create and send messages, the control uses the Compose, Copy, Forward, Reply, ReplyAll, and
Send methods.
● To read messages, the control uses the Fetch method.
● To manage old messages, the control uses the Save and Delete methods.
● To maintain the address list, the control uses the Show and ResolveName methods.
The message-creation methods account for six of the eleven methods. Of these six, you only need to know two before
you can create a functional e-mail application. The Compose method clears out the edit buffer area and prepares a clean
slate for the creation of a new message. The Send method attempts to send the new message to the address supplied. If
an address or message is not supplied, the Send method forces the mail server to present the default message compose
form to the user.
In other words, you can create a complete e-mail composer by adding only two lines to the code we started earlier in this
chapter. The code shown in the following listing is all you need to create a Visual Basic application that can compose
and send e-mail messages. Start a new Visual Basic project and add the MAPISession and the MAPIMessage
controls to the form. Then add the code shown in Listing 7.6 to the Form_Load event.
Now save the form as CDG0702.FRM and the project as CDG0702.VBP, and run the program. You'll be prompted for
a logon, and then you'll see the default compose form. Figure 7.4 shows what comes up if you are using Microsoft
Exchange Mail.
Notice that you have a highly functional e-mail program with very little coding. Use this form to send yourself a
message. We'll use other Visual Basic code to read the message later in this chapter.
You can use the other message creation methods (Copy, Forward, Reply, and ReplyAll) to load the compose
buffer with messages that have been sent to you by others. You can then use the default compose dialog box to edit the
old message and send it just as you would a new message you created from scratch. The Forward, Reply, and
ReplyAll methods also alter the subject line to reflect the action. For example, when you use the Forward method,
the mail server will add "FW:" to the beginning of the subject line. The Reply methods place "RE:" at the start of the
subject line.
The code example in Listing 7.7 takes the first message in the user's inbox and copies it to the compose buffer with
"FW:" on the subject line.
You can use the Fetch method to tell the mail server to send your Visual Basic program all the messages that are
currently on file in the inbox for the logged-on user. The code example shown in Listing 7.8 fetches all the messages for
the user and then uses the MsgCount property to find out how many messages are actually on file.
Finally, you can tell the mail server to show you a list of all the mail server addresses on file by invoking the Show
method. The Show method can also be used to display details of the current message recipient (if this is supported by the
MAPI mail server). The example code shown in Listing 7.10 will display the current mail server address list.
Properties
The MAPIMessage control has more than thirty MAPI-related properties. We will quickly review them here. You can
find more detailed information on each of the MAPIMessage control properties by consulting the topic
"MAPIMessage Control" in the Visual Basic online help file.
The MAPIMessage control properties can be divided into several groups. Each group contains a set of properties that
all deal with the same aspect of the message services provided by the mail server. Table 7.1 shows the MAPI-related
properties, divided by service group.
You can use these properties to modify the behavior of the MAPI dialog boxes supplied by the mail server. For example,
you can change the caption of the address list, change the number of buttons that appear on the list, even change the
caption of the To: button. You can also use these properties to add increased functionality to your Visual Basic mail
applications by honoring attached documents, allowing the use of blind courtesy copy recipients, and so on.
While there are a number of things you can do with the numerous properties of the MAPIMessage control, one of the
most useful is the ability to create e-mail attachments. That is the subject of the next section.
Creating e-mail attachments is very useful and very easy to do with the MAPIMessage control and Visual Basic.
Attachments can be simple text files, word processing documents, or even databases. For the next example, you'll attach
a system file from a user's workstation and prepare a message to send to the help desk at a large corporation.
There are four property values you need to set in order to successfully create an e-mail attachment:
● AttachmentPathName-This contains the complete filename as it is used by the operating system (for
example, c:\config.sys or \\server\directory1\file.ext).
● AttachmentName-This is a text string that appears underneath the attachment icon in the message.
● AttachmentType-This flag tells the server what type of attachment you are using. Visual Basic constants for
this property are mapData (a data file), mapEOLE (an embedded OLE object), and mapSOLE (a static OLE
object).
● AttachmentPosition-This is an integer value that contains the exact character position where the
attachment icon is to appear in the message text.
Note
If you plan on adding multiple attachments to the message, you'll also need
to use the AttachmentCount and AttachmentIndex properties to
fetch the attachments when you read the message.
You can add an attachment to any valid message in the compose buffer. The code example below creates a new message
and adds the workstation's CONFIG.SYS file as an attachment. Modify the Form_Load event of CDG0702.FRM to
match the code in Listing 7.11.
Now save and run the CDG0702.VBP project. After logging onto the mail server, you'll see a form appear with the C:
\CONFIG.SYS file already attached to the message (see Figure 7.5).
The rest of this chapter covers the creation of a complete e-mail client for Simple MAPI access. This example uses all of
the default MAPI services supplied by the installed MAPI service provider. The look and feel of the sign-in dialog box,
the compose form, and the address book are completely controlled by the underlying MAPI engine running on the
workstation. As you saw earlier in the chapter, each of these forms looks different depending on whether you are running
Microsoft Mail, Microsoft Exchange, or any other MAPI-compliant messaging provider (such as Perfect Office). By
using the services already available on the workstation, you can reduce your coding and maintain a familiar look and feel
for your users' e-mail applications.
You will notice that one of the services unavailable within this client is the ability to store and retrieve old messages
within the existing private and public mail folders. Simple MAPI services do not include access to the message store.
You can only read information from the inbox using Simple MAPI. The Send method automatically writes messages to
the outbox, but the Simple MAPI client cannot view messages in the outbox once they are placed there.
Note
The ability to access mail folders is available through MAPI OLE
Messaging. You'll learn how to use OLE Messaging in Chapter 8, "The
OLE Messaging Library."
The simple mail client project requires two forms. The first form (MAPIMAIN.FRM) is the main form in the application.
This form will consist of a single list box that shows all the messages in the user's e-mail inbox and a set of command
buttons that can be used to perform e-mail activities such as creating new messages, reading e-mail, deleting old
messages, saving messages to text files, and replying to existing messages. This form will also hold the MAPI controls
and a common dialog box control that will be used to save e-mail messages as text files. Refer to Figure 7.6 when laying
out the form.
Listing 7.12 shows the Visual Basic form code for MAPIMAIN.FRM. When you build the MAPIMAIN.FRM, be sure to
add the picture control first; then add a single command button to the form by selecting the command button from the
toolbox and drawing it onto the picture control rather than double-clicking the command button from the toolbox. By
drawing it on the picture control, you establish the command button as a child control of the picture box. Now, whenever
you move the picture box, the command button will move with it.
VERSION 4.00
Begin VB.Form MapiMain
Caption = "Form1"
ClientHeight = 1710
ClientLeft = 1875
ClientTop = 1725
ClientWidth = 6345
Height = 2115
Left = 1815
LinkTopic = "Form1"
ScaleHeight = 1710
ScaleWidth = 6345
Top = 1380
Width = 6465
Begin VB.ListBox List1
BeginProperty Font
name = "Courier"
charset = 0
weight = 400
size = 9.75
underline = 0 'False
italic = 0 'False
strikethrough = 0 'False
EndProperty
Height = 840
Left = 120
TabIndex = 1
Top = 540
Width = 4695
End
Begin VB.PictureBox Picture1
Align = 1 'Align Top
Height = 375
Left = 0
ScaleHeight = 315
ScaleWidth = 6285
TabIndex = 0
Top = 0
Width = 6345
Begin VB.CommandButton Command1
Caption = "Command1"
Height = 315
Index = 9
Left = 900
TabIndex = 11
Top = 0
Width = 375
End
Begin VB.CommandButton Command1
Caption = "Command1"
Height = 315
Index = 8
Left = 1380
TabIndex = 10
Top = 60
Width = 375
End
Begin VB.CommandButton Command1
Caption = "Command1"
Height = 315
Index = 7
Left = 1800
TabIndex = 9
Top = 60
Width = 375
End
Begin VB.CommandButton Command1
Caption = "Command1"
Height = 315
Index = 6
Left = 2280
TabIndex = 8
Top = 0
Width = 375
End
Begin VB.CommandButton Command1
Caption = "Command1"
Height = 315
Index = 5
Left = 2820
TabIndex = 7
Top = 0
Width = 375
End
Begin VB.CommandButton Command1
Caption = "Command1"
Height = 315
Index = 4
Left = 540
TabIndex = 6
Top = 0
Width = 375
End
Listing 7.12. continued
Begin VB.CommandButton Command1
Caption = "Command1"
Height = 315
Index = 3
Left = 3240
TabIndex = 5
Top = 0
Width = 375
End
Begin VB.CommandButton Command1
Caption = "Command1"
Height = 315
Index = 2
Left = 3720
TabIndex = 4
Top = 0
Width = 375
End
Begin VB.CommandButton Command1
Caption = "Command1"
Height = 315
Index = 1
Left = 4200
TabIndex = 3
Top = 0
Width = 375
End
Begin VB.CommandButton Command1
Caption = "Command1"
Height = 315
Index = 0
Left = 120
TabIndex = 2
Top = 0
Width = 375
End
End
Begin MSComDlg.CommonDialog CommonDialog1
Left = 5280
Top = 900
_Version = 65536
_ExtentX = 847
_ExtentY = 847
_StockProps = 0
End
Begin MSMAPI.MAPISession MAPISession1
Left = 5880
Top = 540
_Version = 65536
_ExtentX = 741
_ExtentY = 741
_StockProps = 0
End
Begin MSMAPI.MAPIMessages MAPIMessages1
Left = 5100
Top = 480
_Version = 65536
_ExtentX = 741
_ExtentY = 741
_StockProps = 0
End
End
Also, you'll notice that the command buttons are in the form of a control array. Control arrays are easier to work with
than a set of individually named controls. Control arrays also consume fewer Windows resources than a set of
individually named controls. You create the array by clicking on the first command button and setting its Index
property to 0. Then highlight the control and select Edit | Copy from the Visual Basic main menu. Select Edit |
Paste from the same menu. You'll see a dialog box asking you to confirm that you want to create a control array-click
Yes. Visual Basic will then place a copy of the control on the form. Continue cutting and pasting until you have ten
command buttons in the picture control.
The second form (MAPIREAD.FRM) will be used to display messages sent to you by other users. This form will have a
label control to display the e-mail header information, a text box control to display the actual body of the message, and a
single command button to close the form. Use the Visual Basic form code in Listing 7.13 and Figure 7.6 as a reference
when building the MAPIREAD.FRM.
There are four support routines that you need to add to the MAPIMAIN.FRM form. The first routine, AdjustForm (see
Listing 7.14), will do all the work to set the proper size and location for all the controls on the form, including the ten
command buttons.
This routine is called at the very start of the program and also each time the user resizes the form during run-time. When
you add this routine to the Form_Resize event, all controls will be adjusted automatically each time the user changes
the size of the form.
The next support routine you need to add is the MAPIStart routine (see Listing 7.15). This is the routine that attempts
to log the user onto the mail server. Calling the MAPISession1.Signon method forces the mail server to display the
default logon screen for the e-mail system.
Tip
Notice the use of the error-handling routine. You'll see these throughout the
application. Adding error handlers is always a good idea. Error handlers are
even more critical whenever your programs are calling for system services
like e-mail, since unexpected errors in the e-mail system can affect your
Visual Basic program, too.
Once your user has successfully logged onto the mail server, you need to check for any messages in the user's inbox. The
MAPIFetch routine (see Listing 7.16) does this. The MAPIMessages1.Fetch method brings all messages from the
inbox into the MAPI read buffer. You can then use a For...Next loop to "walk" through this buffer and read each
message. This program pulls the messages into the read buffer and then copies the message header information (message
subject, the sender's name, and the date and time the message was received) into a list box on the main form.
The last support routine you need to add to the MAPIMAIN.FRM form is MAPISave (see Listing 7.17). This routine is
used to save selected messages to your local workstation for later use. The common dialog box control is used to provide
the standard save file dialog box. Once a valid name is given for the file, the routine writes out the message header
information followed by the actual message text. This is saved as an ASCII file that can be loaded by Notepad or any
standard text editor.
Now that you have coded the support routines, you need to add code for four Visual Basic events on the MAPIMAIN.
FRM form.
Coding the MAPIMAIN.FRM Events
The MAPIMAIN.FRM form has only five events that require code. Four of them are described here. The last event is
described in the next section. The four events covered here are
● Form_Load
● Form_Unload
● Form_Resize
● List1_DblClick
The Form_Load event first sets the form size and location and then calls the support routines AdjustForm,
MAPIStart, and MAPIFetch. If any of these routines returns an error, the program is halted. The Form_Resize
event calls the AdjustForm routine. This automatically resizes all controls each time the user changes the size of the
form during run-time. The Form_Unload event invokes the MAPISession1.SignOff method to end the e-mail
session and log the user out of the message server. The List1_DblClick event gets the currently selected message
and calls the MAPIREAD.FRM form to display the e-mail note. You'll code the MAPIREAD.FRM form later on.
The last code routine needed for the MAPIMAIN.FRM form is the code used for the Command1_Click event (see
Listing 7.19). Since you built a command button array, all button clicks are sent to the same routine. The program will be
able to tell which button was pressed by checking the Index parameter passed to the Click routine.
Each time a user presses one of the command buttons, this routine will execute the desired function. For most routines,
the user must first select one of the messages in the inbox. If no message is selected, a dialog box pops up. Notice also
that the only function that will require much code is the message-reading routine. You need to provide your own MAPI
message reader (you'll use the MAPIREAD.FRM for that). All other e-mail services (New, Delete, Forward, Reply,
ReplyAll, and AddressBook) are all provided by the message server your user logged onto at the start of the
program.
Note
There is, of course, a downside to this "easy-code" access to MAPI services.
Simple MAPI does not allow you to read, write, or search the MAPI address
book via code. You can only gain access to the address book by starting the
address book dialog box with the MAPIMessages.Show method. Also,
you cannot see any existing MAPI storage folders except the inbox. This
means you cannot save messages to an existing folder, and you cannot read
old messages stored in other folders in the past. These limitations make the
Simple MAPI interface less than ideal for building robust MAPI clients.
However, Simple MAPI is very good for general access to MAPI messages
and for creating very simple e-mail interfaces.
You need to code the MAPIREAD.FRM form to complete the project. This form has two support routines and four events
that require code. The first support routine, AdjustReader, handles the resizing and locating of controls on the reader
form. The second support routine, LoadReader, loads the message from the read buffer onto the form for display. This
routine also creates a message header to display in the label control of the form. The code for these two support routines
is shown in Listing 7.20.
The Form_Load event contains code to set the form size and then call the AdjustReader and LoadReader
routines. The Form_Resize event calls the AdjustReader routine to resize the controls. The cmdClose_Click
event unloads the MAPIREAD.FRM form, and the Text1_KeyPress event contains a single line of code that tells
Visual Basic to ignore any key presses that occur within the text box control. This is a simple way to make a text box
control read-only. Each time a user presses a key, the KeyPress event will zero out the ASCII key value before it gets
typed to the screen. Listing 7.21 contains the code for the MAPIREAD.FRM form events.
After you add all the code, save the project (MAPICLN.VBP) and run it. When the program first starts, you'll see a
prompt to log onto your e-mail server. After you log on, you'll see the main form of the application (see Figure 7.7).
This form shows all the e-mail messages that are currently in your inbox. Notice that you can resize the form, and all the
controls will adjust to the new form dimensions. If you double-click an item in the list box or select an item with a single
click and press the Read button, you'll see the MAPIREAD.FRM form with the message header and selected e-mail
message (see Figure 7.8).
If you press the New button, you'll see the default message compose dialog box. This box will look different depending
on the e-mail system you are using. Figure 7.9 shows how the Microsoft Exchange compose dialog box looks in
Windows 95.
You can get direct access to the e-mail address book by clicking the Addr command button on the MAPIMAIN.FRM
form. Figure 7.10 shows what the Microsoft Exchange address book looks like in Windows 95.
You can test the application by sending yourself e-mail and then using the various command buttons to forward, reply,
save, and delete e-mail messages. You now have a completed e-mail client application!
Additional Features
Even though this project is fairly complete, there are a few features you might consider adding to improve the program.
Some possible enhancements are
● Adding a print button to print the selected message. This involves adding a print button to the control button
array and setting up the common dialog box properties to access the printer.
● Adding the ability to read and save e-mail attachments. This involves adding the ability to collect and list
attachments to the MAPIREAD.FRM form. The Visual Basic text box will not allow you to render an icon
within the message body as is done by the Microsoft Mail and Windows Messaging clients. However, VB4-
32bit does contain a rich-text edit box that will allow you to render icons. If you wish, you can collect the
attachment properties and add them to a list box at the end of the MAPIREAD form, or to a list on another form
launched from MAPIREAD.FRM. After viewing the attachment list, you'll need to offer the user the chance to
save the attachments via the file options of the Visual Basic common dialog box control.
● Replacing the command buttons with icon buttons using the Sheridan 3-D command button that ships with the
Professional Edition of Visual Basic. If you are working in the 32-bit version of Visual Basic, use the new
Toolbar control instead.
● Adding a set of menu items to the forms to match the functions of the command buttons.
Summary
You learned the properties and methods of the two Visual Basic MAPI controls. The MAPISession control is used to
gain access to MAPI service providers through the SignOn and SignOff methods. The MAPIMessages control is
used to read, create, delete, address, and send MAPI messages.
The Simple MAPI client detailed in this chapter showed you how to build a complete MAPI-enabled application with a
minimum of coding. This sample application shows how you can use the Visual Basic MAPI controls to create a fully
functional e-mail client that can read and delete incoming messages, compose new messages, address them, and send
them to their recipients.
You also learned that Simple MAPI services allow only limited access to the MAPI address book. You can search and
edit the address book only through the pre-defined MAPI.Show method. You cannot directly search for existing
addresses or add, edit, or delete addresses without using the address dialog box supplied by the MAPI service provider.
You also learned that Simple MAPI does not allow you to access any of the existing mail folders. You can only see the
inbox folder and its contents.
Now that you know how to use the Visual Basic MAPI controls to create a simple e-mail client, you're ready to tackle
OLE messaging. In the next chapter, you'll learn how to build a mailing list server application that is capable of
managing large mailing lists.
Chapter 6
CONTENTS
● Summary
The most basic MAPI service is the ability to provide a send feature to a program. Almost all Windows programs have a
print feature to send output to a print device. The send feature works basically the same way. It provides the user a way
to send output to some other e-mail address. Adding this most basic form of MAPI service to your Windows applications
makes it "MAPI-aware." MAPI-aware applications do not have e-mail services as a basic part of their functionality (that
is, an e-mail client) but provide it as an added feature. For example, most office suite applications (word processing,
spreadsheet, and so on) provide a send feature on the main menu of all their programs. Basically, whatever documents
you can create with the program can be sent to other locations using the mail services available on the network.
In this chapter, you'll learn how to make your programs MAPI-aware using the Simple MAPI API call set. This API set
provides very easy, very quick access to the most needed MAPI services. Another advantage of using the API set is that
it is available to any program that supports DLL calls. This means it is quite easy to add MAPI services to most any
Windows application.
In the first half of this chapter, you'll get a quick overview of the API calls themselves. You'll learn about the eleven API
calls and three user-defined types that comprise the Simple MAPI interface, and you'll build a set of examples that
illustrate the use of Simple MAPI services.
In the second half of the chapter, you'll create some real-world examples of Windows applications that have MAPI-
aware features. You'll create a quick spreadsheet routine that can send its results using MAPI. You'll also modify an
existing Visual Basic 4.0 program to add MAPI capabilities.
When you complete this chapter, you'll have a good understanding of the Microsoft MAPI API calls. You will also be
able to design and build applications that can use the MAPI interface to provide mail services from within your Visual
Basic programs.
The Simple MAPI (SMAPI) calls allow you to add MAPI services to virtually any Windows program. While these calls
offer only the smallest set of MAPI services, they are still quite useful. In the next few sections, you'll learn about the
three user-defined structures needed to provide MAPI via the API calls, and you'll experiment with each of the API calls
themselves.
Note
All the SMAPI services for Visual Basic and VBA applications are
provided through the dynamic link library (DLL) called VBAMAP32.DLL
(or VBAMAPI.DLL for 16-bit plat-forms). If you do not already have this
DLL on your system, you can find it on the CD-ROM that ships with this
book.
Before you begin this part of the chapter, start Visual Basic 4.0 and begin a new project. Locate the VBAMAP32.BAS
module in the Chap06 folder and add that module to your project. This has all the API calls and structures defined
along with several constants and a helper error function.
Note
Throughout this chapter, you'll use the 32-bit version of the SMAPI set. A
16-bit version of the SMAPI calls can also be used. You'll find the 16-bit
version of the API calls in the VBAMAP16.BAS module on the CD-ROM.
● MAPIMessage-Contains all the information about a message packet, including originator, subject, text,
recipients, and attachments.
● MAPIRecip-Contains all the information about a message recipient, including name, address type, full address,
and unique entry ID.
● MAPIFile-Contains all the information about an attached file, including display name, operating system name,
and position in the message packet.
MAPIMessage
The MAPIMessage structure is used to hold all the vital information about a message packet. You will use this
structure to pass message data from your programs to the DLL and back. Table 6.1 shows the structure of the
MAPIMessage along with short descriptions for each element.
Listing 6.1 shows how the MAPIMessage structure is built using Visual Basic 4.0.
Note
The user-defined types and API calls are all contained in the VBAMAP32.
BAS and VBAMAPI16.BAS modules on the CD-ROM. You do not have to
type these structures and API calls into your projects.
'***************************************************
' MAPI Message holds information about a message
'***************************************************
Type MapiMessage
Reserved As Long
Subject As String
NoteText As String
MessageType As String
DateReceived As String
ConversationID As String
Flags As Long
RecipCount As Long
FileCount As Long
End Type
MAPIRecip
The MAPIRecip structure holds all the important data related to a message recipient. Table 6.2 describes the structure,
and Listing 6.2 shows how it looks in VBA code.
'************************************************
' MAPIRecip holds information about a message
' originator or recipient
'************************************************
Type MapiRecip
Reserved As Long
RecipClass As Long
Name As String
Address As String
EIDSize As Long
EntryID As String
End Type
MAPIFile
The last structure used by SMAPI is the MAPIFile structure. This user-defined type holds all the information about a
message attachment. Table 6.3 describes the structure, and Listing 6.3 shows the UDT definition.
'******************************************************
' MapiFile holds information about file attachments
'******************************************************
Type MapiFile
Reserved As Long
Flags As Long
Position As Long
PathName As String
FileName As String
FileType As Long
End Type
These are the only three structures needed to establish MAPI services with the VBAMAPI DLLs. The next section
describes each of the API calls and constants and shows you examples of how to use them.
There are eleven SMAPI API calls. This set of calls provides access to the core MAPI services including
The next several sections describe each of the API calls and provide Visual Basic 4.0 examples of how to use them.
If you haven't already done so, start Visual Basic 4.0 and load the VBAMAP32.BAS module into your project. Listing
6.4 shows the complete set of API calls for SMAPI. You do not have to type this information into your project. You can
find this module in the Chap06 directory that was created when you installed the source code from the CD-ROM.
'***************************
' FUncTION Declarations
'***************************
There are also a number of CONSTANT declarations needed to make the API calls easier to work with. Listing 6.5 shows
the error constants and flag declarations used for SMAPI.
'**************************
' CONSTANT Declarations
'**************************
'
These are all the basic tools needed to begin to write MAPI applications. The next section reviews each API call in
greater depth, including at least one coding example for each call.
Warning
In order for the 32-bit API calls to work, you must have the VBAMAP32.
DLL in your WINDOWS\SYSTEM folder. If you are using Visual Basic 4.0
on a 16-bit platform, you can load the VBAMAPI.BAS module and make
sure that the VBAMAPI.DLL is in your WINDOWS\SYSTEM folder.
All SMAPI calls return a status code (either SUccESS or some error). You should always check this value before
continuing on with your program. In order to make it easier to work with the SMAPI calls, you can add a helper function
that returns meaningful error messages for the established MAPI errors. Add a BAS module to your Visual Basic project
called MAPIERR.BAS and enter the code in Listing 6.6.
Listing 6.6. Adding the MAPIErr function.
The MAPILogon and MAPILogOff functions are used to start and stop MAPI sessions.
Note
It is always a good idea to log off a session when you no longer need MAPI
services. Leaving an unused session open can slow your program and, if it's
left open after you exit, can lead to unexpected problems.
Table 6.4 shows the MAPILogon parameters along with their type and description.
Table 6.5 shows the MAPILogOff parameters along with their type and description.
Add a new command button to your Visual Basic form. Set its Caption property to LogOn. Use Edit|Copy, Edit|
Paste to add a second command button as part of a control array. Set the second command button's caption to
LogOff. Then add the code in Listing 6.7 to the Command1_Click event.
Next add the following form-level declarations to the general declaration area of your form. You'll use these throughout
the project.
Option Explicit
'
Dim lReturn As Long ' return flag
Dim lSession As Long ' session handle
Dim udtMessage As MapiMessage ' message object
Dim udtRecip As MapiRecip ' recipient object
Dim udtRecips() As MapiRecip ' recipient collection
Dim udtFile As MapiFile ' attachment object
Dim udtFiles() As MapiFile ' attachment collection
Now add a new subroutine called SMAPIStart to the project, and enter the code shown in Listing 6.8.
Finally, add the SMAPIEnd routine, and enter the code shown in Listing 6.9.
Now save the form as SMAPI.FRM and the project as SMAPI.VBP. When you run the project, click the LogOn button
to bring up the logon dialog box (see Figure 6.1).
MAPIAddress
The MAPIAddress call produces the address book dialog box and allows users to add, edit, and delete records from the
address book. There are several flags you can use to control the address book dialog box behavior. Table 6.6 shows the
MAPIAddress call parameters and their type and description.
Now add a new button to the control array and set its caption to AddressBook. Then modify the Command1_Click
event to match the code in Listing 6.10.
Next add the AddressBook subroutine and enter the code shown in Listing 6.11.
The AddressBook routine calls up the MAPI address book, passing a new dialog title, and enabling all possible
recipient class buttons (TO:, cc:, and Bcc:). The AddressBook function returns a collection of recipients.
Save and run the project. After clicking the AddressBook, you should see something like the screen in Figure 6.2.
MAPIResolveName
The MAPIResolveName function is used to look up and/or validate a recipient object. You can use this to retrieve the
complete e-mail address of a recipient and to present a dialog box to the user to resolve any unknown or ambiguous
names. The MAPIResolveName parameters are described in Table 6.7.
Table 6.7. The MAPIResolveName parameters.
To test MAPIResolve, add a new button to the control array and set its caption to ResolveName. Then modify the
Command1_Click event to match the one in Listing 6.12.
Now add the new ResolveName subroutine and enter the code in Listing 6.13.
Listing 6.13. Adding the ResolveName routine.
If you run this routine and supply an ambiguous name, MAPI returns a dialog box asking you to resolve the differences
(see Figure 6.3).
You can avoid viewing the dialog box (and just trap any error) by setting the Flag value to 0.
MAPIDetails
The MAPIDetails function returns a special dialog box that allows users to inspect and edit information about a single
recipient. You can use this in your programs to give users direct access to an address entry edit form. Table 6.8 shows
the MAPIDetails parameter list.
Add a new button to the control array and set its caption to MAPIDetails. Then modify the Command1_Click
event to match the code in Listing 6.14.
Now add the AddrDetails subroutine and fill it in with the code from Listing 6.15.
When you save and run the project, you will see an address entry dialog box appear when you press the AddrDetails
button (see Figure 6.4).
MAPISendDocuments
The MAPISendDocuments function is unique. You do not need to log in to MAPI before you call this function. As an
option, you can fill simple test strings with information for attachments and pass them in the call, too. When the call is
used, it brings up a full-featured compose dialog box that you can use to create and send an e-mail message. Table 6.9
shows the parameters for MAPISendDocuments.
Add another button to the control array and set its caption to SendDocs. Make sure your Command1_Click event
matches the one in Listing 6.16.
Now add the SendDocs subroutine and enter the code in Listing 6.17.
Note
The code in Listing 6.17 refers to documents in the C:\WINDOWS
directory. If your Windows directory is not found at C:\WINDOWS, make
the needed changes to the code example.
Save and run the project. Remember that you do not have to press LogOn before you press the SendDocs button. The
MAPISendDocuments API will log you in automatically. Your screen should look similar to the one in Figure 6.5.
MAPISendMail
The MAPISendMail function is similar to MAPISendDocuments. The difference is that MAPISendMail uses the
MAPIRecip and MAPIFile structures to pass data to MAPI. The MAPISendMail function also allows you to
compose, address, and send a message without the use of any dialog boxes. Table 6.10 shows the MAPISendMail
parameters.
Add another button to the control array and set its caption to SendDialog. Update the Command1_Click event to
match the code in Listing 6.18.
Now add the SendDialog subroutine and enter the code from Listing 6.19.
Save and run the project and press SendMail. You should see the Send Note dialog box on your screen, already filled
out and ready to go (see Figure 6.6).
You can use MAPISendMail to send a message without invoking the Send Note dialog box. To do this, modify the
MAPISendMail line by removing the MAPI_DIALOG constant and replacing it with 0.
The MAPIFindNext and MAPIReadMail functions are used to read messages that have been placed in the user's
InBox. The MAPIFindNext function is used to point to the next (or first) unread message in the InBox. The
MAPIReadMail function takes information received during the MAPIFindNext operation and retrieves the message
for viewing or other processing. Table 6.11 contains a list of MAPIFindNext parameters.
The MAPIReadMail function reads a message from the MAPI InBox and places it into the MAPIMessage structure.
You use MAPIReadMail to retrieve messages from the Inbox for review and subsequent action. Table 6.12 shows the
MAPIReadMail parameters.
Now add another button to the control array and set its caption to ReadMail. Update the Command1_click event to
match Listing 6.20.
Now add the ReadMail subroutine and enter the code from Listing 6.21.
Listing 6.21. Adding the ReadMail routine.
Save and run the project. After you press the ReadMail button, you'll see a message box that shows the subject and
sender name (see Figure 6.7).
Even though MAPI services provide a built-in compose form (see SendMail), there is no built-in read form. You must
provide that through Visual Basic code.
The most basic form of MAPI applications is the mail-aware application. This is a program that offers mail services as
an added feature. A good example of this is the send option in Word, Excel, Access, and the other Microsoft Office
programs.
Making your programs mail-aware is about the same as making them aware of a printer. Usually, you can add a send
option to the main menu and treat mail output the same way you treat printer output. It is possible that you may have to
create an interim ASCII text file that you can then import into the message text using the clipboard or a few lines of
Visual Basic code. All in all, it's quite easy.
In this section, you'll develop a send feature for an Excel spreadsheet and then modify a Visual Basic project to add
MAPI-aware features to its menu.
One of the quickest ways to add MAPI services to existing applications is through the use of the
MAPISendDocuments API call. This API requires no user-defined types and does not even require that you perform a
MAPI logon before attempting the send operation. All you need to do is add a MAPISendDocuments API declaration
and write a short routine to handle the selection of files for the send.
All the Microsoft Office applications allow you to build this kind of MAPI service into your spreadsheets, input forms,
and other projects. As an illustration, let's build a quick Excel spreadsheet that allows users to select from a friendly list
of accounting reports and then route those reports to someone else in the company.
Note
This example uses Excel 95 and requires the VBAMAP32.DLL be present in
the WINDOWS\SYSTEM folder. If you are running a 16-bit version of
Excel, you need to have the VBAMAPI.DLL installed in your WINDOWS
\SYSTEM folder, and you need to change the code referenced DLL to
match your version.
First, bring up Excel and start a new worksheet. Insert a code module (Insert | Macro | Module) and enter the
code shown in Listing 6.22.
'
' declare API call for MAPI service
Declare Function MAPISendDocuments Lib "VBAMAP32.DLL" Alias
"BMAPISendDocuments"
(ByVal UIParam&, ByVal DelimStr$, ByVal FilePaths$, ByVal FileNames
$, ByVal Reserved&) As Long
'
' send file in active cell
'
Sub MAPIAware()
'
' send the selected file as attachments
'
Dim x As Long ' for return
Dim cFile As String
Dim cName As String
'
If ActiveCell = "" Then
MsgBox "Select a Report to Send"
Exit Sub
End If
'
cName = ActiveCell & ";"
cFile = ActiveCell.Offset(0, 1) & ";"
'
x = MAPISendDocuments(0, ";", cFile, cName, 0)
'
If x <> 0 Then
MsgBox "SendDocuments Error [" & Str(x) & "]"
End If
'
End Sub
Now select a new worksheet page and, using Figure 6.8 as a guide, enter the columns of information shown in Table
6.13.
Add a button to the worksheet (selected from the Forms Toolbar) and connect the button to the MAPIAware routine you
built earlier. Set its caption to Send Report. Now hide column B so that users cannot see the exact operating system
filenames. To do this, click the column header, click the right mouse button, and select Hide. Finally, add a title to the
worksheet and save it as QIKSEND.XLS.
Now press Send Report. You'll be asked to log into the MAPI service; then MAPI will collect the file you selected
and present you with the Send Note dialog box with the attachment already in place (see Figure 6.9).
That's all there is to it! You can create much more sophisticated forms and options, though-including building the entire
message, attaching the selected file, even routing directly to the person who is authorized to see the report. And all this
can be done without ever asking the user to do more than select the report and click Send!
For this example, you'll borrow the code from a sample program that ships with Visual Basic 4.0 Standard Edition: the
MDI sample application. This can be found in the SAMPLES\MDI folder within the main Visual Basic folder. If you do
not have this application or if you want to leave your copy alone, you can find another copy of it on the CD-ROM
shipped with this book.
This MDI application is a simple project that creates a multidocument editor that can save documents as ASCII files. To
make this system mail-aware will require a few lines of code behind a Send... menu item in one form.
Note
This project uses the MAPI controls that ship with Visual Basic 4.0. You'll
cover the MAPI controls in detail in the next chapter. For now, just
remember that the MAPI controls offer the same level of access to MAPI
services that the SMAPI API offers.
Load the MDI project and open the NOTEPAD form. First, add the MAPI Session and MAPI Message controls to
the bottom of the form. Next, add a separator line and a Send... menu item just after the Save As... menu item
(see Figure 6.10).
Finally, add the code in Listing 6.23 to the mnuFileSend_Click event. This is all the code you need to make this
application mail-aware.
Now save and run the project. Begin to edit a new document (see Figure 6.11).
When you are done editing the text, select the Send... menu item to send the document out. You'll see the default
compose form appear with the text and subject already supplied (see Figure 6.12).
There is a way to "bury" the mail features even deeper into this application. You really only need a way to tack on an
address to this document. Listing 6.24 shows a modified routine that calls only the address dialog box and then sends the
document out.
Note
In Listing 6.24, it is possible for the user to call the address book and exit it
without selecting a valid address. This will be reported as an error when the
Send method is invoked. To prevent the error, you could check the
RecipAddress property before invoking the Send method.
Save and run this project. When you select the Send... menu option, you now will see only the address dialog box
before the program sends your document out to the server.
As you can see, it's not at all difficult to add mail features to your existing applications. This technique of adding a send
option to the menu will work with just about any Windows application.
Summary
In this chapter, you learned how to make your programs MAPI-aware using the Simple MAPI API call set. This API set
provides very easy, very quick access to the most-needed MAPI services.
You learned that there are three user-defined types required to provide full SMAPI services:
● MAPIMessage-Contains all the information about a message packet, including originator, subject, text,
recipients, and attachments.
● MAPIRecip-Contains all the information about a message recipient, including name, address type, full address,
and unique entry ID.
● MAPIFile-Contains all the information about an attached file, including display name, operating system name,
and position in the message packet.
You also learned that there are eleven API calls in the SMAPI set. This set of calls provides access to the core MAPI
services, including
You also discovered that the MAPISendDocuments API call is the only MAPI call that requires no use of user-
defined types to pass data via MAPI. This API call is very useful for adding quick MAPI support to existing
applications.
In the second half of the chapter, you used SMAPI to add send features to an Excel worksheet (using the
MAPISendDocuments API). You also modified an existing Visual Basic 4.0 project by adding a Send... menu
option to the form.
In the next chapter, you'll get an in-depth look at the Visual Basic MAPI controls, and in the process you'll build a fully
functional e-mail client application that you can use to read and write all your MAPI messages.
Chapter 5
CONTENTS
● Introduction
● What Is the Microsoft Exchange Forms Designer?
❍ EFD Design Wizards
● Summary
Introduction
One of the quickest ways to develop MAPI applications is to use the Microsoft Exchange Forms Designer kit. This tool
ships with the Microsoft Exchange Server and includes a GUI form designer tool, sample templates, design wizards, and
an installation wizard. The Microsoft Exchange Forms Designer (called the EFD) generates Visual Basic 4.0 code. Once
the forms are generated, you can also use Visual Basic 4.0 to modify and enhance the forms.
Note
For those who do not own a copy of Visual Basic 4.0, the Microsoft
Exchange Forms Designer includes a version of the Visual Basic 4.0 16-bit
compiler.
To get the most out of this chapter, you should have access to a copy of the Microsoft Exchange Forms Designer on your
machine. You do not have to be linked to a Microsoft Exchange Server to complete the project in this chapter. If you do
not have a copy of the Microsoft Exchange Forms Designer, you can still get a lot out of this chapter. The concepts and
techniques discussed here apply to any project that uses Microsoft Exchange as a message platform. The last section of
the chapter focuses on folder views. You do not need the Microsoft Exchange Forms Designer to complete the exercises
in that section of the chapter.
You can use the EFD to develop two different types of forms:
● Send forms-These are forms used to send information from one location to the next. This is, in effect, a
formatted e-mail message.
● Post forms-These are forms used to place information into a particular folder. This is an application designed to
control the content of bulletin board messages to be viewed by several people.
You can also use the EFD to design folder views. Folder views are rules that control just how a folder appears to the
users. By setting values such as Sort Order, Message Grouping, and Message Filtering, you can present
folder contents in ways that reflect users' needs and highlight the most important aspects of the message collection.
When you complete this chapter, you'll know how to design, code, test, and install customized forms and folders using
the Microsoft Exchange Forms Designer. You'll learn how to use the EFD to create a Send form and a Post form. You'll
also create several new folders with custom views. Finally, you'll learn how to link customer forms to folders.
The Microsoft Exchange Forms Designer is a development tool that is a part of Microsoft Exchange Server. The EFD is
a complete design tool for the creation and management of customized electronic message applications. You can design
forms that perform various tasks, including forms that
The Microsoft Exchange Forms Designer uses the Visual Basic development environment. If you are familiar with
Visual Basic or Microsoft Access, you'll have no trouble learning to use the Microsoft Exchange Forms Designer. Even
if you have not had a lot of experience with Visual Basic or Access, you'll find the EFD environment easy to work with.
Most of the form design work involves drag-and-drop operations to add fields to a form. When you use the EFD wizards,
toolbars, and menus, most of the basic message fields (To, Cc, Subject, and so on) are automatically added to your
forms. You can add custom controls such as labels, text boxes, list and combo boxes, check boxes and radio buttons, and
even tabs, frames, and picture boxes. One of the controls available with the Microsoft Exchange Forms Designer is a 16-
bit version of the rich-text control. This allows users to select fonts, type sizes, and colors within an editable text box.
Another very handy feature of the Microsoft Exchange Forms Designer is the ability to add field-level and form-level
help to the project without having to create a WinHelp file. The EFD's QuickHelp allows you to enter help information
for each control on the form and for the form itself. You can create a message that appears on the status bar at the bottom
of the form. You can also create a message window that acts as context-sensitive help whenever the user presses the f1
key. And if you are really serious, the EFD allows you to enter help context IDs that link to standard WinHelp files.
Although it is possible to use Visual Basic alone to design and implement Microsoft Exchange forms, the EFD provides
several advantages over "pure" Visual Basic. With the Microsoft Exchange Forms Designer, you get a tool that handles
most of the drudgery of linking message fields to form controls. The EFD helps you establish a consistent look and feel
for all your forms. The EFD also walks you through the installation process, which involves creating a custom message
type, registering that message type with Microsoft Exchange, and creating a configuration file to link the form to
Microsoft Exchange.
In this section, you'll use the Microsoft Exchange Forms Designer to create a job request form to initiate requests to have
maintenance jobs completed in a workplace. This will be a single-window Send form (addressed to a user). After you
build the form, you'll install it into your personal forms library for use at any time.
The easiest way to start developing forms with the Microsoft Exchange Forms Designer is to use the Forms Designer
wizard. The wizard will take you through the initial steps in creating an electronic form. Once you answer all the
wizard's questions, you'll see the EFD build a basic form for your use. You can then use the EFD to modify the project
before saving and installing the new application.
If you haven't already done so, start up the Microsoft Exchange Forms Designer. You can do this from the Microsoft
Exchange program group. To do this, press the Start button on the Windows 95 task bar. Then select Programs |
Microsoft Exchange | Microsoft Exchange Forms Designer. You can also start the EFD directly
from Microsoft Exchange. To do this, start Microsoft Exchange and log in to your e-mail system. Then select Tools
| Application Design | Forms Designer... (see Figure 5.1).
Figure 5.1 : Selecting the EFD from the Windows Messaging client.
Tip
Starting the EFD from the Microsoft Exchange menu takes more memory.
On some systems, it may seem a bit slower than starting EFD from the
program menu. However, when you're developing an EFD form, it's really
handy to have Microsoft Exchange up and running at the same time. That
way you can easily switch between design and test mode while you debug
your EFD application.
The first screen you'll see is the Forms Designer Wizard. It asks whether you want to begin a new project using the
wizard, load a template form, or open an existing form (see Figure 5.2).
For now, select the Form Template Wizard option and press Next to continue.
The wizard asks whether you are designing a Send form or a Post form (see Figure 5.3).
Send forms are used to send messages directly to one or more users. Send forms have a field on the form for the "To"
and "Cc" fields of a message. Post messages are sent to a folder, not a person, and therefore do not have a "To" or a "Cc"
field on them. For our example job request form, you want to use a Send form. This will make sure that the form is sent
directly to a person. Select Send and press Next.
The wizard next asks whether you are creating a form to send information to someone or a form to respond to an existing
EFD form (see Figure 5.4).
The first option allows you to create an "initiating" form. The second option allows you to create a response form. For
now, select the Send option and press the Next button.
Warning
Don't confuse the Send option on this screen with the previous screen
where you were asked if you wanted to create a Send or a Post form. This
screen is really asking you to describe the action of your form-send or
respond. The previous screen asked about the destination of your form-a
person or a group.
The wizard now asks whether you want your form to have one or two windows (see
Figure 5.5).
You use single-window forms when you want to allow the reader to be able to edit the same fields filled out by the
sender. A good example would be a form that you send to people with information for their editing and final approval.
You use the two-window form when you do not want to allow readers to alter the data on the form that they read. When
you select a two-window option, the EFD creates a compose form and a read form. The compose form appears when a
user first creates a form to send to someone. When the recipient opens the two-window form, only the read form appears.
This form has the same controls as the compose form, but the fields are all read-only.
For this example, select the one-window option and then press Next.
Finally, the Forms Designer Wizard asks you to supply the name and general description of your form (see Figure 5.6).
The name you enter appears in list boxes (and in some cases on menus) within the Windows Messaging client. The
description you enter appears in information dialog boxes that users can view when selecting Microsoft Exchange forms
from their client interface. For now, enter the information contained in Table 5.1.
After you supply the form name and description, press Next. The wizard displays a final screen telling you that you
have completed the wizard steps (see Figure 5.7).
At this point you could press the Back button to return to previous screens and make any changes needed. When you are
sure that all screens have been completed properly, select Finish to close the wizard.
You now have a basic electronic form ready for final modification and use. You can see that the top part of the form has
been filled in with the Date and From fields. These will be filled in automatically when you first execute the completed
form. You'll also see the To, Cc, and Subject fields. These fields will be filled in by the person executing the form.
The rest of the form has been left blank. It will contain application-specific controls and information. In the next few
sections, you'll add labels, input boxes, list controls, and a picture control to the form.
Now that you have the basic electronic form built, it's time to add the fields needed to collect and display specific data.
To do this, you add controls for new fields and set the field properties. After adding all the needed fields, you set a few
form-level properties, add some help, and you're ready to install and test your form.
It's very easy to add fields to the form. All you do is click once on the toolbox object you want to use, then move your
mouse to the desired location on the form, and click once again to drop the object onto the form.
Warning
If you're used to Visual Basic, you'll discover that the method for dragging
and dropping form objects is slightly different here. You do not paint the
objects onto the EFD form as you do in Visual Basic. Here you just click,
point, and click.
As a test, select the Entry Field object (called a text box in Visual Basic) and drop it onto the body of the form.
Note
You'll notice that you cannot use the EFD to place standard form objects in
the header area of the form. You can, however, place one of the MAPI
fields (From, Date, To, Cc, Bcc, and Subject) on the header.
Notice that the control is placed on the form along with an associated label control (see
Figure 5.9).
You can click on the label in design mode to edit the contents. You can also use the anchors on the object to move or
resize it as needed. It is also possible to "unlink" the caption and input control by selecting the large square on the upper
left of the input control and moving it independently of the caption.
Tip
Deleting the caption from the input form will also delete the input control
itself. You can use the General tab of the Field Properties dialog box
(double-click the control) to remove the caption. Locate the Position
drop-down list and set its value to None.
Now that you've added a field to the form, you need to adjust several of the field's properties. In the next section, you'll
learn how to do this using the Field Properties dialog box.
The Field Properties dialog box gives you access to several properties of the field object (see Figure 5.10).
● General-Use this tab to set the name, caption, and position of the control on the form. You can also use the tab
to establish the control's locked, hidden, and required status and to enter the field-level help.
● Format-Use this tab to set the font, size, color, alignment, and other formatting properties of the control. Note
that you must use this same tab to set properties for both input control and the caption.
● Initial Value-Use this tab to enter the default value for this control. The contents of this tab depend on the type
of control. List and combo boxes allow you to enter multiple items, text boxes allow you to enter straight text,
picture boxes allow you to load a graphic image from the disk, and so on.
Use Table 5.2 as a guide in setting the field properties of the text box field on your job request form.
After setting the properties on the three tabs, select Close to save the information.
You need to add several fields to the job request form before it is complete. Now that you have an idea of how to add
fields and set their properties, use the information in Table 5.3 and Figure 5.11 to add, size, and locate the remaining
fields on the form.
Tip
The area of the EFD form where you place your controls is scrollable. It is
very easy to lose one or more fields due to unexpected scrolling when you
place a control on the form. To make it easy to see where things are on the
form, you need to turn on the scroll bars. Select View | Show Scroll
Bars from the main menu. If you do not want users to see these at runtime,
turn them off before you install the form.
Note
Be sure to use a complete path/directory name for the Picture Field control
in Table 5.3. You can find the Chap05 directory under the main directory
created when you installed the source code from the CD-ROM that ships
with the book.
After adding all the fields and setting their properties, save the project (JOBREQ.EFP) before continuing with the next
step.
There are several form- and window-level properties that you can set for Microsoft Exchange forms. These settings
affect the way your form looks and behaves once it's up and running under Microsoft Exchange.
First, select View | Window Properties from the main menu. Then set the properties using the information in
Table 5.4.
Table 5.4. Setting the window properties of the job request form.
Dialog Tab Property Setting
General Window Name JobRequestWindow
Window Caption Job Request Form
Fields in Tab Order MAPI_To
MAPI_Subject
ContactPhone
JobType
Priority_1
Priority_2
Priority_3
Department
AffectsProduction
Description
Format Maximize Button (off)
Minimize Button (off)
ToolBar (off)
Formatting Toolbar (off)
Status Bar (on)
Window Sizing Options Fixed Size
Next you need to set the form-level properties. Select View | Form Properties from the main menu. Refer to
Table 5.5 for the proper settings.
Table 5.5. Setting the form properties of the job request form.
Tab Property Setting
General Form Display Name Job Request Form
Version 1
Number 1
Item Type IPM.JobRequest
You will note that the first time you bring up a new form, the Item Type property is set to a long string of letters and
numbers. This is a GUID (guaranteed unique ID). Microsoft Exchange uses this ID value internally to identify the form.
The value you enter here does not have to be this cryptic. It is a good idea to enter a value that will mean something to
you and others in your organization. It is, however, important that you keep this name unique.
Save this project again (JOBREQ.EFP) before you go on to your last development step-adding help.
It is very easy to add online help to your electronic forms. The Microsoft Exchange Forms Designer has a built-in
QuickHelp feature that lets you build tooltips and pop-up help boxes at the field, window, and form levels. You can even
add notes to the design-time version of the form for tracking development issues.
First, let's add a few notes to the design-time form. Select Help | Designer Notes... from the main menu to
bring up the Designer Notes screen (see Figure 5.12).
Enter a short comment about the form, the date, and the author. The information you enter here is stored with the project
and will be available each time you load the project into the Microsoft Exchange Forms Designer. Notice that this is a
rich-text box. You can set the font type, size, and color at any time.
Notice that you can select No Help, QuickHelp, or enter a context ID for a standard WinHelp file. For now, enter a
short comment into the QuickHelp pop-up box and press Close to save the form. You can also set the Windows
Caption by moving the cursor up into the title bar of the sample help window and typing a caption.
You can enter help at the window level, too. This is most useful when you have a project with multiple windows. For
now, select the Window Properties dialog box (View | Window Properties | General) and press the
Window Help... button. Your screen will look like the one in Figure 5.14.
Notice that you have an additional control on this dialog box. If you have multiple windows in your project, you can use
the drop-down list control to select each window and enter unique help information.
Finally, you can also enter help information at the field level. Double-click a field object or select View | Field
Properties | General Tab to bring up the Field Properties dialog box. Then press the Field Help... button
to view the help dialog box (see Figure 5.15).
Figure 5.15 : Viewing the Field Help for Users dialog box.
Notice that there are now two controls at the top of the help dialog box. The drop-down list can be used to select the field
for which you want to create a help topic. The Status Bar control lets you enter a short help line that will appear at the
bottom of the form as you select each field. Of course, the QuickHelp box contains the help information that will appear
in a pop-up box if you press f1 at run-time while a field is in focus.
Enter QuickHelp information for several fields and then save the project. Save your project as JOBREQ.EFP before
continuing with the last step-installing and testing your new form.
After you have completed the development phase of your Microsoft Exchange form, you need to run the Install
routine from the Microsoft Exchange Forms Designer. This routine
This entire process may take awhile, depending on the size of your project and your hardware configuration. If you do
not have the project loaded now, open the Microsoft Exchange Forms Designer and load the JOBREQ.EFP project.
Select File | Install... from the main menu. You'll see a small dialog box telling you that the Microsoft
Exchange Forms Designer is generating Visual Basic code. Then you'll see Visual Basic 4.0 load and compile the
project.
After Visual Basic finishes, you'll see a dialog box that asks you where you want to install the form (see Figure 5.16).
Select Personal Forms Library for now. This will install the form on your workstation. Once you have tested it
thoroughly, you can re-install the form on a network location to allow others to use the form.
After selecting a forms library, you'll be asked to fill in a few more questions about the form (see Figure 5.17). The
information in these fields is used by Microsoft Exchange to categorize your form. Forms are sorted and grouped to
make them easier to locate and use.
For now, enter your initials for the first category and Help for the second category. Enter your initials again as the
contact person. Notice that several of the fields you set in design mode appear here, too.
Your new Microsoft Exchange form is now installed. Exit the Microsoft Exchange Forms Designer and switch to your
Windows Messaging client so that you can start testing your new form.
Once you have installed the form, you can switch to Microsoft Exchange and run it. In the previous step, you installed
the form in your personal forms library. In order to start an instance of the form, you need to launch your Windows
Messaging client and select Compose | New Forms... from the main menu. You'll see a dialog box that lists all
the forms you have in your personal library (see Figure 5.18).
Select the job request form from the list to launch an instance of the form. You'll see the form appear with several fields
already filled in with suggested entries (see Figure 5.19).
Complete the form and send it to yourself. Then check your inbox for the arrival of the message.
Tip
If your server is slow in returning your form to you, select Tools |
Deliver Now Using... | Microsoft Exchange or Tools |
Deliver Now Using... | Microsoft Mail if you are running a
standalone version of Microsoft Exchange for Windows 95.
When you open the message, you'll see that it appears in the same electronic form that it was sent in. If you select
Compose | Reply from the main menu of the form, you'll see your form automatically convert the data on the
application into a text message (see Figure 5.20).
You can now fill out a response to the request and return it to the person who sent you the note (in this case, yourself!).
You can use the Microsoft Exchange Forms Designer to create a response form that reads information from the job
request form and includes that data automatically on the response form. You can also create Post forms that are not
addressed to users, but to folders. These Post forms help you control discussion groups and other public data sharing in
your organization.
The Microsoft Exchange Forms Designer ships with several example projects that illustrate using multiwindow forms
and using several forms together to create a set of send/respond forms. Check out the Templates folder and the Samples
folder for more examples of Microsoft Exchange forms development.
In the next section, you'll learn how to create folder views and then how to install an electronic form in a folder.
Another very easy and powerful way to create custom MAPI interfaces is to use the Windows Messaging client's
capabilities to create and control folder views. Folder views are an excellent way to set up customized views of the
message base. You can create folder views that show and group messages according to their subject. You can also create
views that show only selected items in the folder based on subject, sender, or several other criteria.
In effect, you can use folder views to narrow the scope of your incoming messages. This is especially handy in large
organizations where you get a lot of information and must focus on the most important messages first.
In this section, you'll learn how to create a new discussion folder and establish its view properties. You'll then write
several messages to test the folder view. Finally, you'll install a form in the folder. This way every time someone wants
to post a message to the folder, he or she can use the custom form.
Note
You need to have access to the Windows Messaging client that ships with
the Microsoft Exchange Server. That version has the capability to create
folder views. You do not, however, have to be connected to the Microsoft
Exchange Server to create folders and views. This example uses personal
folders and views.
Creating folder views is the easiest way to build custom discussion applications using Microsoft Exchange. You can
create a specialized view, test it on your personal system, and then publish it for others to use. You can even use the
Microsoft Exchange Forms Designer to create custom posting forms for use in the discussion forum. These forms can be
installed in the folder itself and will be available to anyone who enters the forum.
There are just a few steps to creating a custom folder and view:
● Select a message store and add a new folder.
● Create a folder view by setting the Sort, Group, and Filter options.
● Test the view by sending/posting messages to the folder.
● Install a new or existing form in the folder.
● Test the form by using it to send messages.
● Share the folder and place the form in the folder library.
The first step is to create a new folder. If you haven't done so yet, start the Windows Messaging client and select your
personal message store. Point to the top level of the message store and add a new folder called "MAPI Discussion
Group" (see Figure 5.21).
Once the folder is created, it is a good idea to set its Description property. This description will help everyone know
what kind of information is supposed to be in the folder. It is also a good idea to add the name of the person who created
the folder and the date it was first created. To set the Description property of a new folder, select the folder, and
then select File | Properties from the main menu. Enter a general description of the folder along with a creation
date and the author's initials (see Figure 5.22).
Once you fill in the description, press the Apply button or the OK button to update the folder properties.
The folder view controls just which messages are seen by the user, along with the order in which they are seen and what
message columns appear in the summary listing. There are four main steps to setting a folder view:
Once you have set all the view properties, you can test the folder view by posting messages to the folder.
First, highlight the MAPI Discussion Group folder again and select File | Properties to bring up the Folder
Properties page. This time select the View tab. Be sure the Folder Views radio button is selected and then press the
New button to create a new view.
The first step is to name the folder view. Enter "Group By Conversation Topic."
Tip
It is a good habit to name views based on grouping and sorting criteria. That
way, as you build up a library of folder views, it is easy to remember how
the view affects the message displays.
The next step is to select the columns to be displayed in the list window. Press the Columns button to bring up the
Columns dialog box (see Figure 5.23).
Locate and select the Conversation Topic column from the list box on the left. Add this column to the very top of the list
box on the right. Now delete the From column from the list box on the right. You can save this selection by pressing OK.
Tip
You may have noticed that there is a small input box at the lower right-hand
side of the dialog box. This input box allows you to set the display width of
each column in the list. The Conversation Topic column defaults to one
character. You do not need to change this. When messages are grouped
together, their topic will appear as a header within the listing. Adding the
conversation topic to the listing would only clutter the display.
Next you need to set the grouping value. Press the Group By button to bring up the Group By dialog box (see Figure
5.24).
In the topmost combo box, select Conversation Topic and select the Ascending radio button. Notice that you
can set the sort order by activating the combo box at the bottom of the Group By dialog box. It should be set to
Received, Ascending. If it is not, set it now, and then press OK to update the grouping and sorting properties.
Now select the Filter button from the Views dialog box. This calls up the first of two filter dialogs boxes (see Figure
5.25).
Through this dialog box, you can set criteria for limiting the display of messages:
● From-Use this to limit the view to only those messages that are from a specified user or distribution list
(defined in the MAPI Address Book). Notice that you can list more than one address on this line.
● Sent To-Use this to limit the view to only those messages that you sent to a specified user or distribution list.
You can include more than one address on this line.
● Sent directly to me-Check this box if you want to see only messages addressed directly to you.
● Copied (Cc) to me-Check this box if you want to see only messages that have you on the Cc: line.
● Subject-When you enter text here, the Windows Messaging client displays only messages that have that text in
the Subject line. You cannot use wildcards.
● Message body-When you enter text here, the Windows Messaging client displays only messages that have that
text somewhere in the message body.
You can also set additional filter criteria by pressing the Advanced button on the Filter dialog box (see Figure 5.26).
A second form appears through which you can set filters based on file size, date ranges, read/unread flags, and level of
importance. You can also set filters based on forms ("show me only Job Request Forms") or document statistics ("show
me only Word documents").
For now, select Cancel from the Advanced Filter dialog box and select Clear All at the main Filter dialog box to
turn off all filtering.
Warning
It is important to remember that setting message filters affects only the
display of message folders, not their content. If you have a folder that filters
all but a few messages, you should keep in mind that there may actually be
hundreds of messages in the folder, it's just that you can see only a few.
Message filtering will not remove messages from a folder; it just hides
them.
Under the Views tab of the Folder Properties dialog box, press Apply to update the properties and then select OK to
exit the dialog box. You have created a custom view for your folder. Now it's time to test the view.
To test the new folder view you just created, you need to add a few messages. For now, you can add these messages and
replies yourself. Once you are sure the view is working properly, you can place this view in a new or existing public
folder and share it with other users.
Since this view was built as a discussion forum, you'll use a Post form instead of the standard Send form. To create a
new post in the MAPI Discussion Group, highlight the folder and select Compose | New Post in this
Folder... from the main menu. This will bring up the default posting form (see Figure 5.27).
After filling out the form and posting it, check the folder to see how the view works. You'll see that a conversation topic
has been started and that your first message appears underneath the topic. You can click on the topic to expand the
message listing and then select the message to read it. When you create a reply to the message, it is added to the folder,
under the same topic. Figure 5.28 shows you how an extended set of messages appears in a discussion folder.
Note
Although the folder we created is a discussion folder, you are not restricted
to using Post messages while you are in the folder. If you wish, you can use
Send forms to reply directly to a user's inbox. This is a way to start private
conversations with people you first meet in a public discussion group.
Although there's a lot more to creating and managing folders and views, you should now have a pretty good idea of the
possibilities. If you are interested in learning more about Microsoft Exchange folders and views, check out the
documentation that ships with the Microsoft Exchange Server.
The final step in this chapter is to install a custom form in a folder. You can install forms in personal forms libraries or
folder forms libraries. The advantage of installing forms in the personal forms library is that it is available to the users no
matter what other folder they are looking in. All they need to do is select Compose | New Forms... to locate the
form installed on the local workstation.
The advantage of installing forms in a folder form library is that each time the user enters the folder, that custom form
appears on the Compose menu. This makes it easier to find and more likely that it will be used.
For this example, you'll install the job request form in the MAPI Discussion Group folder.
Note
It actually doesn't matter what folder you use for this exercise.
First, start up the Windows Messaging client and select the target folder (the MAPI Discussion Group folder). Then
select File | Properties and select the Forms tab. This brings up the Forms page. Press the Manage button to
display the Forms Manager dialog box, and press the Set button above the list box on the left to bring up the Set
Library To dialog box (see Figure 5.29).
You've seen this dialog box before. It's the same one you used when you used the Microsoft Exchange Forms Designer
to install the job request form. Select the Personal Forms Library radio button; then press OK to return to the
Forms Manager.
You'll now see one or more topics and forms in the list box on the left side of the form (see Figure 5.30).
Locate and select the job request form in the list box on the left. Then press Copy to copy the form to the list box on the
right. You have just associated the job request form with the MAPI Discussion Group folder. Now it's time to install the
form in the folder's library.
When you press Install..., Microsoft Exchange asks you for the location of the configuration file (.CFG) for the
form. This is stored in the subfolder in which you created the job request form. Locate the folder where you saved the
JOBREQ.EFP file. You'll see a subfolder called JOBREQ.VB. This is the folder that has the Visual Basic source code
and the JOBREQ.CFG file (see Figure 5.31).
After locating and selecting the JOBREQ.CFG file, click OK to load the configuration file. Microsoft Exchange will then
show you the Form Properties dialog box from the Microsoft Exchange Forms Designer. Select a category and a
subcategory, and enter your initials as the contact name for the form (see Figure 5.32).
Now you can press Close on the Forms Manager dialog box and press OK on the Form Properties tab page. You have
just installed your form into the MAPI Discussion Group folder.
Select Compose from the main menu, and you'll see an item at the bottom of the menu list called "New Job Request
Form" (see Figure 5.33).
Figure 5.33 : Selecting the new job request form the menu.
You can start from here and run the job request form just like any other form. If you move to another folder, however,
you will not see the form on the menu. It appears on a folder's menu only if it has been installed in that folder's form
library.
Summary
In this chapter, you learned how to use the Microsoft Exchange Forms Designer kit that ships with Microsoft Exchange
Server. You learned how to design, code, test, and install custom message forms for use at individual workstations or
over a large network.
You also learned how to set up Microsoft Exchange folders for use with custom forms,
including
In the next chapter, you'll learn how to use the Messaging API to create MAPI-aware windows applications that can read
and write MAPI messages from outside Windows Messaging clients.
Chapter 9
Creating a MAPI Mailing List Manager with the OLE Messaging Library
CONTENTS
● Introduction
❍ Laying Out the MLM Form
❍ Dropping Subscribers
❍ Listing Archives
● Summary
Introduction
After reviewing the OLE Messaging Library objects in Chapter 8, "The OLE Messaging Library," you're now ready to
build a MAPI application for Win95 and Visual Basic 4.0 that uses these objects.
The Mailing List Manager application lets users define and manage automated mailing lists from the client desktop.
Messages can be distributed within a single server or across the Internet (depending on the available transports at the
desktop). All access to MAPI services will be performed through the OLE Message objects.
The MLM application allows individuals to create a set of text files to be distributed to a
controlled list of users at specified times. This project has only one simple form and several support routines. All
application rules are stored in a set of ASCII control files similar to INI/registry settings. These control files can be
changed by the list manager to determine how the mailing list operates and what features are available to subscribers.
Once you complete this application, you'll be able to establish and manage one or more one-way mailing lists from your
own desktop. These mailing lists can be limited to your current attached server or cross over any transport out onto the
Internet (depending on the transports installed on your desktop).
The MLM application has only one form. Since the primary purpose of the application is to manage automated lists,
there is very little needed in the way of a GUI interface. MLM has a set of command buttons to initiate specific tasks and
a single scrollable text box to show progress as the application processes incoming and outgoing mail.
Start a new Visual Basic project and lay out the MLM form. Refer to Table 9.1 and Figure 9.1 for details on the size and
position of the controls on the form.
Note that the layout table calls for a control array of command buttons. Add a single button to the form, set its properties
(including the Index property), and then use the Edit | Copy, Edit | Paste menu options to make the additional
copies of the button. You can then edit the Caption properties as needed.
After you lay out the form, you need to add a handful of variables to the general declaration area, a few routines to
handle the standard form events, and one routine to respond to the command-button actions. Listing 9.1 shows the code
that declares the form-level variables for this project. Add this code to the general declaration area of the form.
Option Explicit
Next, add the code in Listing 9.2 to the Form_Load event. This code centers the form and then stores its current width
and height. This information will be used to prevent users from resizing the form at run-time.
You'll also notice that the Form_Load event checks for a parameter passed on the command line at startup. This will be
used to determine what set of control files will be used for each run of the MLM application (you'll see more about this
later).
Next, add the code in Listing 9.3 to the Form_Resize event. This code uses the values established in the Form_Load
event to keep forcing the form back to its original size whenever a user tries to adjust the form size. Note, however, that
this routine will allow users to minimize the form.
You also need to add code behind the command-button control array. Listing 9.4 contains the code that should be placed
in the Command1_Click event. This routine just calls a set of custom subroutines that you'll add a bit later in the
chapter.
One more line of code is needed to complete this section. The text box control should be a read-only form object. By
adding the following line of code to the Text1_KeyPress event, you can trick Visual Basic into ignoring any
keyboard input performed within the text box control.
That's the code needed to support form events and controls. Save this form as MLM.FRM and save the project as MLM.
VBP. In the next section you'll add a series of simple support routines to the project.
Now you'll add a few support routines that are called frequently from other, high-level routines in the project. You'll add
all these routines to the general declaration section of the form.
First, add a new subroutine called Status, and add the code shown in Listing 9.5.
The code in the Status routine places a new line in the text box. This will be used to pass progress information to the
text box control as the MLM is processing subscriber lists and the Microsoft Exchange inbox.
The MLM project gets its primary instructions from a set of ASCII text control files. The next routine you'll build in this
section is the one that reads the master control file. Add a new subroutine called ControlsLoad to the project, and
enter the code shown in Listing 9.6.
Notice that the ControlsLoad routine reads each line of the ASCII text file, and if it is not a comment line (that is, it
starts with a ";"), it parses the line into a control name array and a control value array. You'll use these values throughout
your project.
Now that the control values are stored in a local array, you need a routine to retrieve a particular control value. Add a
new function (not a subroutine) to the project called ControlSetting, and add the code shown in Listing 9.7.
The ControlSetting function accepts a single parameter (the name of the control value you are requesting) and
returns a single value (the value of the control setting you named). This routine accomplishes its task by simply reading
through the array of control names until the name is found.
That's all for the general support routines. Save this form and project again before continuing.
This next set of routines allows users to edit the various control files required to manage the project. You'll use a call to
the NOTEPAD.EXE applet to edit the control files. This is much easier than spending the time to write your own text file
editor. Also, the first time you call these routines you'll be prompted to create the new files.
Add a new subroutine called ControlsEdit to the form, and enter the code shown in Listing 9.8.
This routine first attempts to load the master control values, then launches the default editor to allow users to modify
those values. You can also see the use of the Status routine to update the form's text box. Go back to the
Command1_Click routine (see Listing 9.4) and remove the comment from in front of the ControlsLoad command.
Then save this project.
Before you can run this routine, you need to create the default control file. Start NOTEPAD.EXE and enter the
information shown in Listing 9.9. Once you complete the entry, save the file in the same folder as the MLM project and
call it MLM.TXT.
Tip
If you get errors attempting to launch the editor from these routines, you can
include the drive and path qualifiers in the Editor control value.
; ===================================================
; Mailing List Control values for MLM
; ===================================================
;
; read by MLM.EXE
;
; ===================================================
;
MAPIUserName=MCA
MAPIPassword=
SearchKey=MLM
ListName=MLM Mailing List
NewSub=SUB
NewSubMsg=MLMHello.txt
UnSubMsg=MLMBye.txt
UnSub=UNSUB
GetArchive=GET
ListArchive=LIST
ArchiveFile=MLMArch.txt
ListSchedule=MLMSked.txt
ListSubs=MLMSubs.txt
Editor=notepad.exe
Tip
If you don't want to spend time entering this control file information, you
can find it in the MLM folder that was created when you installed the
source code from the CD-ROM.
There are several entries in this control file. For now, make sure that the control names and values are entered correctly.
You'll learn more about how each one works as you go along. Once you get the hang of the control file, you can modify
it to suit your own mailing-list needs.
Now add a new subroutine, called SubEdit, to allow the editing of the subscriber list. Enter the code in Listing 9.10
into the routine.
Normally you will not need to pre-build the subscriber file. It will be created as you add new subscribers to your mailing
list via e-mail requests. However, for testing purposes, open up Notepad and enter the values shown in Listing 9.11.
When you are done, save the file as MLMSUBS.TXT in the same folder as the Visual Basic project.
Listing 9.11. Creating the test MLMSUBS.TXT file.
; ====================================================
; Mailing List Subscriber File
; ====================================================
;
; Read by MLM.EXE
;
; format:name^address^transport
;
; where:name = display name
; address = e-mail address
; transport = MAPI transport
;
; example:Mike Amundsen^[email protected]^SMTP
;
; ====================================================
;
Michael C. Amundsen^[email protected]^SMTP
Mike Amundsen^102461,1267^COMPUSERVE
The addresses in the file may not be valid e-mail addresses on your system, but they illustrate the format of the file. Each
address entry has three parts:
As users request to be on your mailing list, their mailing information is added to this file. Later in the chapter, you'll add
yourself to this list by sending yourself an e-mail request.
The next control file needed for the MLM application is the schedule file. This control file contains information on the
display name, complete filename, and scheduled delivery date of messages to be sent by MLM. Create a new routine
called SkedEdit, and add the code in Listing 9.12.
You'll need to create a default schedule file for this project. Listing 9.13 shows the schedule file format. Use NOTEPAD.
EXE to build this file and save it in the project directory as MLMSKED.TXT.
; ==================================================
; Mailing List Schedule file
; ==================================================
;
; read by MLM.EXE
;
; format: YYMMDD,uafn,title
;
; where: YYMMDD = Year, Month, Day
; uafn = unambiguous file name
; title = descriptive title
;
; example: 960225,MLMFAQ.txt,MLM FAQ Document
;
; ==================================================
You can see from the sample file that there are three control values for each entry:
● YYMMDD-The year, month, and day that the message should be sent.
● UAFN-An unambiguous filename. The contents of this text file will be placed in the body of the message to be
sent.
● Title-This is the title of the message. This value will be placed on the subject line of the message that is sent.
As you build your mailing list message base, you can add lines to this control file.
The last edit routine to add to the project is the one used to edit the archive list. Add a new subroutine called ArchEdit
to the project, and enter the code shown in Listing 9.14.
Again, you'll need to create an initial archive listing file before you first run your project. Use NOTEPAD.EXE to build a
file called MLMARch.TXT and enter the data shown in Listing 9.15. Save this file in the project directory.
; ==================================================
; Mailing List Archive File
; ==================================================
;
; read by MLM.EXE
;
; format: YYMMDD,uafn,title
;
; where: YYMMDD = Year, Month, Day
; uafn = unambiguous file name
; title = descriptive name
;
; example: 960225,MLMFAQ.txt,MLM FAQ Document
;
; ==================================================
This file format is identical to the one used in the MLMSKED.TXT file. The contents of this file can be requested by
subscribers when they want to retrieve an old message in the database. By passing a GET YYMMDD line in the message
subject, subscribers can get a copy of the archive file sent to them automatically.
This is the last of the edit routines for the project. Be sure to save this project before you continue.
Coding the MAPIStart and MAPIEnd routines
Before you can start processing messages, you need to build the routines that will start and end your MAPI sessions. Add
a new subroutine called MAPIStart to the project, and enter the code that appears in Listing 9.16.
Note the use of the OLE Messaging Library as the means of access into the MAPI system. Now add the MAPIEnd
subroutine to your project and enter the code from Listing 9.17.
These two routines are the start and end of the ReadMail and SendMail routines you'll add in the next two sections.
Create a new routine called SendMail and add the code shown in Listing 9.18.
The SendMail routine first clears the status box and loads the master control file. Then the MAPIStart routine is
called. Once the MAPI session is established, the routine calls ProcessSubList to handle all processing of the
subscriber list. After the list is processed, the MAPIEnd routine is called and the status box is updated along with
message to the user announcing the completion of the processing.
Next add the ProcessSubList subroutine, and enter the code shown in Listing 9.19.
The main job of the ProcessSubList routine is to open the schedule file, and see if there is a message to send for
today's date. If one is found, the routine opens the subscriber control file and calls the ProcessSubListMsg routine
to compose and send the message.
Finally, add the ProcessSubListMsg routine and enter the code that appears in Listing 9.20.
The most important part of the ProcessSubListMsg routine is the last section of code that composes and addresses
the message. There are two main processes in this part of the routine. The first process is the creation of a new
Message object:
The second process is the creation of a new Recipient object and the addressing of the message:
Notice that addressing is handled a bit differently for MS-type messages. Messages with the address type of MS are
addresses within the Microsoft addressing scheme-they're local addresses. To handle these items, you only need to load
the Name property, set the recipient type (To:), and then call the MAPI Resolve method to force MAPI to look up the
name in the address book(s). When the name is found, MAPI loads the Address property with the complete transport
and e-mail address for routing. This is how most MAPI messages are usually sent.
However, for messages of type other than MS, it is likely that they are not in the locally available address books. These
messages can still be sent if you load the Address property of the message with both the transport type and the user's e-
mail address. This is the way to handle processing for messages that were sent to you from someone who is not in your
address book. This is known as one-off addressing. One-off addressing ignores the Name property and uses the
Address property to route the message.
That is all the code you need to send out daily messages to your subscriber list. The next set of routines will allow your
application to scan incoming messages for mailing list-related items and process them as requested.
Tip
It is a good idea to save your project as you go along. The next set of
routines are a bit longer and you may want to take a break before continuing.
The next set of routines handles the process of scanning the subject line of incoming messages for mailing-list
commands. These commands are then processed and subscribers are added or dropped from the list and archive items are
sent to subscribers as requested.
The Inbox processing can recognize four different commands on the subject line. These commands are:
● SUB-When this command appears in the subject line of a message, the sender's name and address are added to
the subscriber control file.
● UNSUB-When this command appears in the subject line of a message, the sender's name and address are
removed from the subscriber control file.
● LIST-When this command appears in the subject line of a message, MLM will compose and send a message
that contains a list of all the archived messages that the subscriber can request.
● GET YYMMDD-When this command appears in the subject line of a message, MLM will retrieve the archived
message (indicated by the YYMMDD portion of the command) and send it to the subscriber.
Tip
The exact word used for each of these four commands is determined by
settings in the master control file. See Listing 9.9 for an example of the
master control file. If you want to change the values for these commands,
you can do so in the control file. This is especially useful if you plan to
manage more than one list from the same e-mail address. Adding prefixes to
the commands will help MLM distinguish which command should be
respected and which commands are for some other mailing list.
The first three routines for handling the inbox are rather simple. The first routine clears the progress box, loads the
controls, calls the ProcessInbox routine, and performs cleanup functions upon return. Add the ReadInbox
subroutine and add the code shown in Listing 9.21.
Next, add a new subroutine called ProcessInbox, and add the code that appears in Listing 9.22.
This routine performs three main tasks. The first is to open the messages stored in the Inbox folder. Every message
store has an Inbox folder. All new messages are sent to the Inbox folder upon receipt.
The second step is to create a collection of all the messages in the Inbox folder. You access messages as a collection of
objects in the folder.
The third process in this routine is to inspect each message in the collection to see if its subject line contains the search
key word from the master control file. If found, the message is passed to the ProcessInboxMsg routine for further
handling.
Now add the ProcessInboxMsg subroutine. This routine checks the content of the message for the occurrence of
MLM command words (SUB, UNSUB, LIST, GET). If one is found, the appropriate routine is called to handle the
request. Enter the code shown in Listing 9.23.
Listing 9.23. Adding the ProcessInboxMsg routine.
In the next few sections you'll add supporting code to handle all the MLM subject-line commands. It's a good idea to
save the project at this point before you continue.
When a person sends you an e-mail message with the words MLM SUB in the subject line, the MLM application adds
that person's e-mail address to the subscriber list. The next set of routines handles all the processing needed to complete
that task. This version of the program will also automatically send the new subscriber a greeting message (one that you
designate in the control file).
First, add a new subroutine called ProcessInboxMsgNewSub to the project, and enter the code shown in Listing
9.24.
This routine first checks to see if the name already exists in the subscriber control file. If not, it is added and the new
subscriber is sent a friendly greeting message.
Create a new function called SubFind, and enter the code from Listing 9.25.
The SubFind routine accepts one parameter (the name to look up), and returns True if the name is found and False
if the name is not in the subscriber list.
Next, add the SubWrite subroutine to the project. The code for this routine is in Listing 9.26.
Notice that the SubWrite routine copies the Name, Address, and Type properties from the AddressEntry object
into the subscriber control file. Each value is separated by a caret (^). This separator character was chosen somewhat
arbitrarily. You can change it if you wish.
Warning
If you change the separator value, be sure you don't use a character that could be part of a
valid e-mail address. E-mail addresses today can have a comma (,), colon (:), semicolon (;),
slashes (/ or \), and other characters. You'll need to be careful when you choose your separator
character!
Next add the SubGreet routine. This composes and sends a friendly greeting message to all new subscribers. Add the
code from Listing 9.27 to your project.
The SubGreet routine looks similar to the routine used to send daily messages to subscribers. The message sent as the
greeting pointed to the NewSubMsg parameter in the master control file.
Save your work before adding the code to drop subscribers from the list.
Dropping Subscribers
The routines needed to drop subscribers from the mailing list are very similar to the code needed to add them. You'll
create a routine to respond to the request and two supporting routines-one to delete the name from the list, and one to
send a goodbye message to the requester.
First add the ProcessInboxMsgUnSub subroutine to the project and enter the code from Listing 9.28.
Listing 9.28. Adding the ProcessInboxMsgUnSub routine.
This routine checks to make sure the name is in the subscriber list. If it is, then the name is dropped and a goodbye
message is sent. Add the SubDelete routine to the project by copying the code from Listing 9.29.
This routine accomplishes the delete process by copying all the valid names to a temporary file, and then erasing the old
file and renaming the temporary file as the new master subscriber list. While this may seem a bit convoluted, it is the
quickest and simplest way to handle deletes in a sequential ASCII text file.
Note
In a more sophisticated project, you could build the subscriber list in a
database and use database INSERT and DELETE operations to manage the
list.
Next add the SubBye routine. This sends a goodbye message to the subscriber that was just dropped from the list. The
greeting message is kept in the text file pointed to by the value of the UnSubMsg control parameter in the master control
file.
The next code routines will handle subscriber requests for the list of retrievable archive
messages.
Listing Archives
One of the added features of MLM is to allow subscribers to send requests for copies of old, archived messages. Users
can also request a list of messages that are in the archive. You need two routines to handle the LIST command-the main
caller, and the one to actually assemble and send the list.
Add the new subroutine ProcessInboxMsgArcList to the project and enter the code shown in Listing 9.31.
Now create the WriteArcList subroutine and add the code shown in Listing 9.32.
The WriteArcList routine reads the MLMARch.TXT control file and creates a message body that has a brief set of
instructions and lists all available archived messages. Once this is done, the message is addressed and sent.
Once subscribers have received a list of available archives, they can send a MLM GET YYMMDD command on the
subject line of a message to ask for a specific message to be sent to them. You need three routines to handle this
processing:
First add the ProcessInboxMsgArcGet subroutine to your project and enter the code in Listing 9.33.
Finally, add the WriteArcGet routine to the project and enter the code shown in Listing 9.35.
The WriteArcGet routine picks the archive name out of the subject line and, if it is found, reads the archived
message, composes a new message, and sends it to the requestor.
That is all the code for this project. The next step is to test the various MLM functions. Be sure to save the project before
you begin testing. Once testing is complete, you can make an executable version of the project for installation on any
workstation that has the MAPI OLE Messaging Library installed.
In a production setting, you can set up an e-mail account that is dedicated to processing MLM requests. All e-mail
messages regarding that list can be addressed to this dedicated account. You (or someone else) can run the MLM once a
day and it can automatically log onto the dedicated account and perform the list processing. Also, since MLM accepts a
command-line parameter, you can build control files for several different mailing lists and run them all from the same
workstation. You just need to keep in mind that in order to process the messages, you need to start the MLM application
and run it at least once a day.
Tip
If you have the Microsoft Plus! pack installed, you can use the System
Agent to schedule MLM to run at off-peak times. If you decide to use the
System Agent, you need to add additional code to the project to allow you
to select the Read & Send button automatically. Just add an additional
parameter to the command line that will execute the Command1_Click
event for Read & Send.
For testing purposes, set the MLM control file to log onto your own e-mail account. You can then send messages to
yourself and test the features of MLM to make sure they are working properly.
Before you start testing you need to make sure you have valid ASCII files for the new subscribe greeting (MLMHELLO.
TXT) and the unsubscribe departing message (MLMBYE.TXT). Refer to Listings 9.36 and 9.37 for examples of each of
these files.
Tip
You can also find examples in the source code directory Chap08\MLM
created when you installed the CD-ROM.
Welcome!
MCA
BYE - MCA
Use NOTEPAD.EXE to create these two files and save them in the project directory.
You may also need to modify the MLMSKED.TXT file to match today's date. Change the first entry from 960225 to make
sure that any registered subscriber gets a message when you run the SendMail routine.
Once the request is sent, load MLM and select the ReadMail button. This will scan all the messages in your inbox, and
(if all goes right!) find and process your request to be added to the list. Figure 9.3 shows how the MLM screen looks as it
is processing.
After MLM is done, start up your MAPI client again. You should see a greeting message in your inbox confirming that
you have been added to the MLM mailing list (see Figure 9.4).
Next, try sending a message that requests a list of available archives. Use your MAPI client to compose a message with
MLM LIST in the subject line. After sending the message, run the MLM ReadMail option again, and then check your
inbox with the MAPI client. You should see a message similar to the one in Figure 9.5.
Once you get the list, you can send MLM a command to retrieve a specific message in the archive. Use your MAPI
client to send a message that asks for one of the messages. After sending the message, run MLM ReadMail, and then
recheck your MAPI client for the results. You should get a message like the one in Figure 9.6.
Tip
You have probably noticed that messages that have already been read and
processed are being processed again each time you run MLM. You can
prevent this from happening by deleting the messages from the inbox by
hand, or by adding code to the project to delete each message after you are
finished processing it.
You can test the SendMail option by simply starting MLM and pressing the SendMail button. This will search for a
message file tagged with today's date and send it to all subscribers in the list. To test this, modify one of the entries in the
MLMSKED.TXT file so that it has the current date as its key number. Figure 9.7 shows what the MLM progress screen
looks like as it is working.
Finally, you can test the unsubscribe feature of MLM by sending a message with MLM UNSUB in the subject. When
MLM receives this message, it will drop your name from the subscriber list and send you a departing message.
Summary
In this chapter you built a mailing list manager using Microsoft's OLE Messaging Library. This application lets you
define a mailing list, allow others to become list subscribers, publish messages automatically (based on date), and allow
others to query and retrieve old messages from the list archives. This program can accept members from within a single
network, or from around the world through Internet (or other) transports.
In the next chapter you'll use OLE to build a MAPI application that allows distant users to query databases and other
collections of information by way of e-mail.
Chapter 10
CONTENTS
In this chapter you'll learn how to use MAPI services to create a threaded discussion client. Threaded discussions clients
are used quite frequently in groupware settings and on the Internet. The biggest difference between a discussion tool and
an e-mail client is that the e-mail client is designed primarily for conducting one-to-one conversations. The discussion
tool, however, is designed to support multiple parties, all participating in the same discussion. Even though MAPI
services were originally deployed as only an e-mail solution, Microsoft has added several features to MAPI that now
make it an excellent platform for building discussion applications.
Before getting into the details of building the tool, you'll learn a bit more about the differences between e-mail and
discussion communications. You'll also learn how to take advantage of little-known MAPI properties and new features
of the OLE Messaging library that make it easy to put together a standalone discussion tool that can be deployed from
within a Local Area Network, over a Wide Area Network, or even across the Internet. You'll learn
As an added bonus, after you've completed the programming example in this chapter, you'll have a set of library
functions that allow you to easily add threaded discussion capabilities to new or existing Visual Basic applications.
There are a number of other advantages to using discussion groups instead of e-mail. Often, it is easier to find answers to
technical problems if you can go to a place where all the "techies" hang out. Discussion forums can work the same way.
Instead of trying to e-mail several people in attempts to solve your problem, you can often find a discussion forum where
you can send a single request that will reach hundreds (possibly thousands) of people who may be able to help you. So
discussion forums can increase your ability to get your problems solved sooner.
Another good way to highlight the differences between e-mail and discussion groups is by comparing several face-to-
face meetings (e-mail messages) with a single staff meeting where everyone shows up at the same place at the same time
(the discussion forum). Using forum communications can reduce the amount of time you need to spend communicating.
You can say it once and reach lots of people instead of having to repeat your message in lots of single e-mail messages.
Companies use forums as a way to communicate information of general interest as well as a way to take advantage of
specialized expertise within an organization. Where corporate e-mail can lead to isolated individuals communicating in a
vacuum, discussion groups can foster increased interaction with others and a sense of belonging to a special group-even
if one or more of the team members is half-way around the world.
Now that you have a general idea of what discussion groups are and how you can use them in your organization, you're
ready to review the three key concepts that make discussion systems different from e-mail systems.
Folders as Destinations
First, and most important, users participating in an online discussion forum do not send messages to individuals. Instead
they send their messaging to a single location where all messages are stored. In the MAPI model, the storage location is
called a folder. When you create MAPI-based forum tools, you'll select a folder (or folders) to hold all the
correspondence from others participating in the forum.
Note
There are times when forum participants will initiate private e-mail
correspondence in order to cover a topic in more depth or to delve deeper
into an aspect of the discussion that would not be interesting to most of the
other members.
Then, after each message has been composed, you just post the message to the discussion folder for others to see. They,
if appropriate, respond to your message with their own comments. The key point to remember is that messages are
addressed to locations, not people.
Another key aspect of discussion groups is the ability to track topics in a thread that leads from the beginning of the
discussion to the end. As each participant replies to an existing message, a relationship is established between the source
message and the reply. Of course, it is perfectly correct (and quite common) to generate a "reply to a reply." This can
continue on indefinitely. And in the process an intricate web of ideas and comments all collect in the storage folder that
houses the discussion group.
Some discussion tools simply list the messages in the chronological order in which they were received. These are
referred to as non-threaded or flat-table discussion tools (see Figure 10.1).
Non-threaded tools (often called readers) can be handy, but most people prefer the discussion tools that provide threaded
discussion tracking. With threaded tools, each conversation that is initiated is a branch. Each branch can have its own
subsequent conversation thread. And those threads can be combined with others, too. Viewing discussion messages as
related threads is really handy (see Figure 10.2).
MAPI uses two special properties of the Message object to keep track of each branch and sub-branch of a threaded
discussion. These two properties are the ConversationTopic and the ConversationIndex properties. The
ConversationTopic is usually a readable string. This is much like the subject line of a mail message. Conversation
topics for a discussion forum for a typical computer firm might be
● General questions
● Sales
● Technical support
● Press releases
Note
Some forums have fixed topics and only allow users to select from a
predetermined list when posting messages. Other forums allow users to
enter free-form text into the topic field.
MAPI uses the ConversationIndex property to keep track of conversation threads within the topic group. This is
usually done using some type of numbering scheme. Microsoft recommends that programmers use the same method that
is employed by Microsoft Exchange when populating the ConversationIndex field. Microsoft Exchange uses the
CoCreateGuid API call to generate a unique number to place in the ConversationIndex field. New messages
that respond to an existing message should inherit the ConversationIndex of the previous message and append
their own index value to the right. This way, each new branch of the conversation has a longer ConversationIndex.
You'll get a better look at this technique when you build the sample Visual Basic project later in this chapter.
Note
The CoCreateGuid API generates a unique value based on the system
date (among other things). You can use any method you wish to keep track
of conversation threads, but it is highly recommended that you use the
method described here. It is quick, effective, and requires very few
computing resources.
The last major concept to deal with when building discussion tools is the use of the MAPI Update method instead of
the Send method. In all the examples covered in the book so far, when you complete a new message and want to place it
into the MAPI message pool, you use the Send method (or some type of Send API call) to release the message to
MAPI for delivery. This works when you have a person to whom you are addressing the message. However, because
discussion messages are not addressed to persons but to folders instead, you cannot "send" new messages. Instead you
use the Update method to update the contents of a MAPI folder. In fact, attempting to use the Send method to deliver
forum messages will result in a MAPI error.
Tip
The key idea here is to think of updating the contents of a MAPI folder as
opposed to sending a message to a person.
The actual process of placing a message in a MAPI folder includes adding a blank message to the target folder, setting
that message's subject and text body (just like any mail message) and then setting several other message properties, too.
Each of the properties shown in Table 10.1 must be set properly before you invoke the Update method to place a
message in a MAPI folder.
Note
You'll get to see the details of creating a forum message when you build the
forum tool later in this chapter. The main thing to keep in mind now is that
you do not use the Send method to place messages in folders.
So there are the three key points to remember about the differences between e-mail and discussion messages:
Now it's time to use Visual Basic to build the example forum tool.
For the rest of the chapter, you'll build a complete discussion tool that can be used to track ongoing messages in a target
folder. You'll be able to use the program to read messages, generate replies to existing messages, and start new
discussion threads. You'll also be able to select the target folder for the discussion. This way, you can use the same tool
to monitor more than one discussion.
Note
The forum tool described in this chapter is a very basic project. Not much
time will be spent on the user interface. This is done to keep focus on the
general issues of creating a discussion tool for MAPI systems. If you plan to
put a version of this project into production, you'll want to add some bells
and whistles to make this a more friendly product.
You'll use the OLE Messaging library (OML) to access MAPI services for this project. The OML gives you all the
features you need to be able to manipulate message and folder properties within the MAPI file system. Although you can
use the MAPI.OCX to read most of the discussion-related properties, you cannot use the OCX to place messages in a
target MAPI folder. Also, you cannot use the simple MAPI API declarations to gain access to target folders or to
manipulate message properties.
Tip
If you are planning to build any software that manipulates folders, you'll
need to use the OLE Messaging library. No other Microsoft programming
interface (besides the C MAPI interface) allows you to gain access to the
folders collection.
There is one main code module and several forms in the Discuss project you'll build here.
● MAPIPost-This code module holds all the routines for posting new threads, replying to threads, and collecting
information on the available information stores, folders, and messages available to the workstation. You can use
the code here in other Visual Basic discussion projects.
● modDiscuss-This code module contains a few constants and global variables used for the Discuss project.
● mdiDiscuss-This is the main form. This acts as a wrapper for the note form and the message list form.
● frmNote-This form is used to read, compose, and reply to existing forum messages.
● frmMsgs-This form is used to display a list of discussion messages within the target folder. The messages are
shown in the threaded discussion form.
● frmOptions-This form allows users to change the target folder for the discussion, set the default MAPI logon
profile, and control whether the message listing is shown in threaded or flat-table format.
● frmAbout-This is the standard About box for the project.
Note
Before you start coding the Discuss project, make sure you have added the
OLE Messaging type library. Do this by selecting Tools | References
from the main menu of Visual Basic. You will need to install the OLE
Messaging library from the MSDN CD-ROM before you can locate it using
the "Tools | References" menu option.
The MAPIPost Code Library contains several very important routines. These routines will be used throughout the
project to gain access to folder collections and message collections within the folders. This also holds routines for
posting new messages and generating replies to existing messages. There are also several routines for performing folder
and message searches. You'll be able to use the routines in this module in other MAPI-related projects.
First, start a new Visual Basic project and add a BAS module (Insert | Module). Set its Name property to
MAPIPost and save the file as MAPIPOST.BAS. Now add the code shown in Listing 10.1 to the declaration section of
the form.
Option Explicit
'
' OLE message objects
Public objSession As Object
Public objMsgColl As Object
Public objMsg As Object
Public objRecipColl As Object
Public objRecip As Object
Public objAttachColl As Object
Public objAttach As Object
Public objAddrEntry As Object
Public objUserEntry As Object
Public objFolderColl As Object
Public objFolder As Object
Public objInfoStoreColl As Object
Public objInfoStore As Object
Public gnIndentlevel as Integer
Public cStoreID As String
'
' UDT for store/folder pairs
Type FolderType
Name As String
FolderID As String
StoreID As String
End Type
'
Public FolderRec() As FolderType ' members
Public iFldrCnt As Integer ' pointer
'
' UDT for message/conversation pairs
Type MsgType
Subject As String
Topic As String
ConvIndex As String
MsgID As String
Date As Date
End Type
'
Public MsgRec() As MsgType ' members
Public iMsgCnt As Integer ' pointer
'
' type for creating Exchange-compliant timestamp
Type GUID
guid1 As Long
guid2 As Long
Listing 10.1. continued
guid3 As Long
guid4 As Long
End Type
'
Declare Function CoCreateGuid Lib "OLE32.DLL" (pGuid As GUID) As Long
Public Const S_OK = 0
You'll notice the usual OLE Messaging library object declarations along with two user-defined types that will be used to
keep track of message and folder collections. This will come in quite handy as you'll see later on. There is also the
CoCreateGuid API call. You'll use this to generate unique ConversationIndex values for your message threads.
Next you need to add code that starts and ends MAPI services. Listing 10.2 shows the OLEMAPIStart and
OLEMAPIEnd routines. Add them to your project.
The next routines are used to build a collection of all the folders in all the message stores available to the workstation.
You'll remember that MAPI 1.0 allows more than one message store for each workstation. Typically, users will have a
personal message store, a server-based collection of messages, and possibly a message store related to an outside
messaging service (such as Sprint, CompuServe, and so on). Each one of these stores has its own set of folders, too. The
routine in Listing 10.3 shows you how you can enumerate all the folders in all the message stores and build a local user-
defined type that you can use to locate and manipulate MAPI folders. Add the code shown in Listing 10.3 to your
project.
You'll see that the routine in Listing 10.3 walks through all the attached message stores and calls the LoadFolders
routine to actually collect all the folders in a message store. This routine also allows you to pass an option list control
(list box, combo box, or outline control). The routine will use this control to build an onscreen pick list of the available
folders.
Now add the LoadFolders routine from Listing 10.4 to your project.
Notice that this routine is called recursively in order to collect all the folders that might be found within a folder. Since
MAPI places no restrictions on how many levels of folders may be defined, you need to use a recursive routine to locate
all the available folders.
Once you have built the folder collection, you'll need a method for pulling information out of the collection. Listing 10.5
shows a function that will take the friendly name of a folder and return the unique folder ID and store ID. Add this to
your project.
Warning
This routine will return the folder record of the first folder with the name
you request. Because MAPI allows users to define two folders with the
same name, this routine may not always return the results expected. This
works fine for most projects, but you should keep it in mind when
developing MAPI search tools.
You also need some tools for collecting and accessing all the discussion messages in a folder. Listing 10.6 shows the
routine that you can use to collect all messages into a local user-defined type. Add the routine to your project.
You'll need three different routines to access messages from the user-defined array. First, you need a routine that allows
you to pass in a pointer to the sorted list and that returns the ConversationIndex of a message. Listing 10.7 shows
how this is done.
Next you need a routine that takes the conversation index and returns the complete internal message structure. Listing
10.8 shows you how to do this step.
'
' start w blank records
GetMsgRec.MsgID = ""
GetMsgRec.ConvIndex = ""
GetMsgRec.Subject = ""
GetMsgRec.Topic = ""
'
' now try to find it
If iPointer < 0 Or iPointer > UBound(MsgRec) Then
MsgBox "Invalid Message pointer!", vbExclamation, "GetMsgRec"
Exit Function
Else
GetMsgRec = MsgRec(iPointer + 1)
End If
'
End Function
While you're coding the message routines, add the FillOutline subroutine shown in Listing 10.10. This routine
loads an outline control from the sorted list. The outline can then be displayed to the user.
The FillOutline routine also makes sure threaded messages are indented properly and expands the entire message
tree for users to see the various branches.
One more handy routine is the MakeTimeStamp function. This will be used to generate the ConversationIndex
values. Add the code from Listing 10.11 to your project.
LocalErr:
MsgBox "Error " & Str(Err) & ": " & Error$(Err)
MakeTimeStamp = "00000000"
Exit Function
'
End Function
Only two routines remain: OLEMAPIPostMsg and OLEMAPIReplyMsg. The OLEMAPIPostMsg routine builds and
posts a new message thread to the target folder. Add the code from Listing 10.12 to your project.
There are quite a few things going on in this routine. First, it locates the folder and message store where the message will
be posted. Then a new message object is created, populated with the appropriate values, and posted (using the Update
method) to the target folder.
The OLEMAPIReplyMsg is quite similar, but this method carries information forward from the source message to
make sure that the conversation thread is maintained. Add the code from Listing 10.13 to your project.
That's all there is to this module. Save the module (MAPIPOST.BAS) and the project (DISCUSS.VBP) before moving
on to the next section.
The two main forms for the Discuss project are the MDI Discuss form and the Msgs form. The MDI form presents a
button array and hosts all the other forms. The Msgs form is used to display the threaded discussion list.
You'll also need to add a few values to a short BAS module. These are project-level values that are used throughout the
project. Add a BAS module, set its Name property to ModDiscuss and save it as MODDISCUSS.BAS. Now add the
code shown in Listing 10.14 to the general declaration section of the form.
Option Explicit
'
' constants
Public Const dscRead = 0
Public Const dscNewPost = 1
Public Const dscReply = 2
'
' variables
Public cGroup As String
Public cProfile As String
Public bThreaded As Boolean
That's all you need to add to this form. Save it (MODDISCUSS.BAS) and close it now.
After you complete the form layout, save the form as MDIDISCUSS.FRM before you begin coding.
Listing 10.15 shows the MDIForm_Load event. Add this to your project.
'
lblStatus = "Logging into Discussion Group [" & cGroup & "]..."
'
OLEMAPIStart cProfile
CollectFolders
OLEMAPIGetMsgs cGroup, frmMsgs.list1
FillOutline frmMsgs.list1, frmMsgs.Outline1
frmMsgs.Show
lblStatus = ""
'
End Sub
Listing 10.16 shows the code for the Activate and Resize events of the form. Add these two routines to your
project.
Finally, add the code from Listing 10.17 to the MDIForm_Unload event.
'
' write to registry
SaveSetting App.EXEName, "Options", "Profile", cProfile
SaveSetting App.EXEName, "Options", "Group", cGroup
SaveSetting App.EXEName, "Options", "Threaded", bThreaded
'
'drop all loaded forms
'
Dim x As Integer
Dim y As Integer
'
x = Forms.Count - 1
For y = x To 0 Step -1
Unload Forms(y)
Next
End
'
End Sub
Next, you need to add code to the cmdMain_Click event to handle user selections from the button array. Listing
10.18 shows the code to handle this.
You can see that the cmdMain routine calls two other routines: LoadMsgRec and NewMsgRec. You need to add these
routines to your project. First, add the NewMsgRec subroutine to the form. Add the code from Listing 10.19.
The code in Listing 10.19 initializes values on the note form and then calls the form for the user.
The code for the LoadMsgRec routine is a bit more complicated. This routine must first locate the selected message,
load it into the form, and then call the note form. Add the code in Listing 10.20 to your form.
Listing 10.20. Adding the LoadMsgRec routine.
The Msgs form is used to show the threaded discussion list. Refer to Figure 10.4 and Table 10.3 for details on laying out
the form.
Note
You'll notice that the form contains both an outline control and a list box
control. The list box control is not visible at run time. It is used to
automatically sort the messages by conversation index.
There is very little code to the form. Listing 10.21 shows all the code you need to add to the Msgs form.
Save this form as DSCMSGS.FRM and update the project before going to the next step.
Building the Other Forms
There are three other forms you need to add to the project. The Note form will be used to read and reply to messages; the
Options form allows the user to set and store some program options; and the About dialog box contains typical program
information.
Add a new form to the project and set its Name property to frmNote. Refer to Table 10.4 and Figure 10.5 in laying out
the note form.
After laying out the form, save it (DSCNOTE.FRM) before you add the code.
Along with the typical form-related events, you need to add code to handle user button selections and a custom routine to
establish the mode of the form (read, reply, or new message).
First, Listing 10.22 shows all the code for the Form_Load, Form_Activate, and Form_Resize events. Add this
to your project.
Listing 10.22. Adding the Form_Load, Form_Activate, and Form_Resize code.
Worth mentioning here is the Form_Resize code. This code will adjust controls on the form to fill out as much (or as
little) screen area as is allowed.
Another routine that deals with form controls is the StatusUpdate routine (Listing 10.23). This routine toggles the
various controls based on the mode of the form (read, reply, or new message). Add the code from Listing 10.23 to your
form.
The last routine you need to add to the form is the code for the cmdBtn_Click event. This also uses the mode of the
form to determine just what the program will do when the user presses the OK button. Add the code from Listing 10.24
to your form.
After you complete the code, save the form (DSCNOTE.FRM) and project (DISCUSS.VBP) before you go to the next
section.
The Options form allows the user to select the folder for the discussion group, enter a MAPI profile, and turn the
message display from flat to threaded. Refer to Figure 10.6 and Table 10.5 for laying out the Options form.
It's a good idea to save this form (DSCOPTIONS.FRM) before you start coding.
There is not much code for the Options form. Listing 10.25 shows the code for the Form_Load event.
CollectFolders lstGroup
'
Me.Left = (Screen.Width - Me.Width) / 2
Me.Top = (Screen.Height - Me.Height) / 2
'
End Sub
The next code to add is for the cmdBtn_Click event. This routine will save the user's choices in the system registry
for later recall. Add the code from Listing 10.26 to your form.
'
' save to registry
SaveSetting App.EXEName, "Options", "Profile", Trim
(cProfile)
SaveSetting App.EXEName, "Options", "Group", Trim
(cGroup)
SaveSetting App.EXEName, "Options", "Threaded", IIf
(chkThreaded.Value = ➂1, 1, 0)
'
' update list & main form
OLEMAPIGetMsgs cGroup, frmMsgs.list1
FillOutline frmMsgs.list1, frmMsgs.Outline1
mdiDiscuss.Caption = "Discuss [" & cGroup & "]"
'
MousePointer = vbNormal
'
End Select
'
Unload Me
'
End Sub
'
lblSelected = Trim(lstGroup.List(lstGroup.ListIndex))
'
End Sub
Now save the form (DSCOPTIONS.FRM) and update the project. Only one more form to go!
The About dialog box contains basic information about the project. Refer to Figure 10.7 and Table 10.6 for laying out
the form.
You only need to add code to the Form_Load event and the cmdOK_click event. Listing 10.27 shows all the code
for the About form.
That's the last of the code for the Discuss project. Save this form (DSCABOUT.FRM) and update the project before you
begin testing.
Note
The discussion tool will not work in a Remote Mail setup. You need to have
direct access to at least one message store.
When you first start Discuss, you'll be asked to log into MAPI. One of the first things you should do is open the Options
page and select a target folder and set up your default user profile (see Figure 10.8).
You can select any folder as the discussion target. However, since the idea is to carry on discussions with other people,
you'll typically select a public folder as the discussion target.
Note
If you are working on a standalone machine, you can select any personal
folder for this demonstration. Just remember that no one but you can see the
results!
The program will list only messages that have their Type property set to IPM.Discuss. This means the first time you
select a target folder, you won't see any messages. So the next thing you need to do is add a message!
Press New Post to add a new thread to the folder (see Figure 10.9).
You can also highlight any message in the discussion and double-click it to read it. When you press the Reply button at
the bottom of a read form, it automatically turns into a reply form. Even the subject and message body are updated to
show that this is a reply (see Figure 10.10).
Summary
In this chapter you learned how to use the OLE Messaging library to create online, threaded discussion tools using MAPI
services. You learned that there are three ways in which discussion messages differ from mail messages:
You also learned how to build routines that collect all the message stores available to a workstation, all the folders in
each of those stores, and all the messages within a folder. You now know how to compose a message for Update
(rather than Send) and how to use the CoCreateGuid API to generate unique conversation index values used in
threaded discussion tools.
Best of all, most of the heart of this example program can be used to add discussion capabilities to other Visual Basic
projects.
Chapter 11
CONTENTS
● Summary
In this chapter you'll learn how to use the OLE Messaging library to create a stand-alone e-mail agent. This agent can
scan your incoming mail and, based on rules you establish, automatically handle messages for you. All actions are based
on rules you establish in a control file.
The first part of the chapter will discuss the concept of e-mail agents and cover the overall design of the program. The
next sections will detail the coding of the forms and support routines needed to complete the project. In the final section,
you'll install and test the MAPI Email Agent program.
Note
The Microsoft Exchange Server clients allow users to establish and code
their own mail agent (called the Inbox Assistant). If you have the Microsoft
Exchange Server client, now is a good time to review the Inbox
Assistant to get an idea of its features. The programming project
covered in this chapter works independently of the Inbox Assistant
and does not require that users have Microsoft Exchange Server installed on
their system.
When you complete the programming project in this chapter, you'll have a fully functional MAPI Email Agent that can
be installed on any workstation that has access to a MAPI-compliant e-mail system. Also, the techniques used to build
this project can be incorporated into other Windows programming projects to add message processing capabilities.
Before starting to code the project, it's a good idea to discuss the general features and functions of an e-mail agent. Once
you have a good idea of what e-mail agents can do, then you can lay out the basic design features of the MAPI Email
Agent programming project covered in this chapter.
Basically, an e-mail agent is a program that "acts for you." It is a program that reviews your messages and, based on
information you have supplied, processes the messages for you. Typically, e-mail agents process messages in the user's
inbox. Users can set up rules that tell the agent how to handle each new message. These rules can tell the e-mail agent to
check various parts of the incoming message and then take a specific action.
For example, the agent can be instructed to look for all messages that are received from your boss and then place those
messages in a special folder called "Urgent." Or the agent could be told that any message with the word "SALES" in the
subject line should be immediately forwarded to another user's inbox and then erased from your inbox without any
comment. You might also tell the agent to automatically reply to all senders that you are out on vacation and will return
next week.
For this chapter, you'll use Visual Basic 4.0 and the OLE Messaging library to build a stand-alone MAPI Email Agent
that has the following features:
● Timed scanning of your inbox-Users can start the program and allow it to run unattended. It scans the inbox for
new messages every N minutes. Users can also set configuration values that start the program as an icon on the
task bar or as a dialog box.
● Message notification-Users can establish a rule that causes a dialog box to pop up each time a specific message
is received. This notification can be based on sender ID, subject content, or level of importance.
● Automatic forwarding-Users can create rules that automatically forward messages to other addresses. Users can
also determine whether the original should be kept or discarded.
● Automatic replies-Users can create rules that generate automated replies to senders based on sender ID, subject
content, or level of importance.
● Automatic message copying or moving-Users can create rules that copy or move incoming messages to other
folders in the user's message store. This feature can be used to sort incoming message by sender ID, subject
content, or level of importance.
Note
The features described here are just the start of what can be accomplished
with an e-mail agent. The number of options has been limited to keep this
chapter focused on design and coding issues instead of content. As you
build your own agent, you can add many other capabilities.
To accomplish this, the MAPI Email Agent will keep track of rules created by the user. These rules will have three parts:
tests, comparisons, and actions. The test portion of the rule performs a simple scan of the designated portion of the
message, searching for requested content. The MAPI Email Agent described in this chapter is capable of inspecting three
message parts:
For example, the test SUBJECT MAPI tells the agent to check the message subject for the word "MAPI." The phrase
SENDER Boss tells the agent to check for messages sent to the user from the e-mail ID "boss."
All tests must use a logical condition as part of the processing. The MAPI Email Agent uses comparisons to do this. The
program can check for the following four logical conditions:
You'll notice that the last value is able to check the selected message part for the occurrence of a word or phrase. Note
that all the comparisons are case-insensitive. It is important to note that the LT and GT can be used with character data,
too.
The last of the three portions of a rule is the action. This is the part of the rule that tells the agent what action to take if
the test criteria have been met. The MAPI Email Agent can perform the following actions on a message:
The agent allows users to determine whether the forwarded and reply messages are retained or removed once the
forward/reply is generated.
The MAPI Email Agent allows users to build tests and actions, and then use them to create rules. All this information is
stored in a text file similar to an INI file. This file also contains general control information, such as the scan interval,
whether the agent should create a log file, the default log on profiles, and so on. Listing 11.1 shows a sample rule file.
Listing 11.1. Sample rule file for the MAPI Email Agent.
; ********************************************************
; MAPI Email Agent Control File
; ********************************************************
;
[General]
Editor=notepad.exe
ScanInterval=2
LogFile=mea.log
LogFlag=1
RuleCount=3
ActionCount=4
TestCount=4
Profile=MCA
DeleteForwardFlag=0
NotifyDialog=1
DeleteReplyFlag=0
MinimzeOnStart=0
AutoStart=0
LastUpdated=04/29/96 9:27:30 PM
[Actions]